Отдельный рабочий процесс для частей вашего кода

Асинхронное программирование - это принцип, который позволяет части ваших программ запускаться в ожидании других действий, которые произойдут в потоке вашего приложения. Это позволяет частям вашего кода выполняться независимо от основного рабочего процесса.

Вот несколько примеров асинхронных процессов: выборка данных из сети или перебор некоторого очень большого фрагмента данных.

Во флаттере есть несколько способов написать асинхронный код. Некоторые популярные методы:

  • Будущее.
  • Асинхронный / Ожидание.
  • Потоки.

Цель этой статьи - помочь вам начать использовать потоки в ваших приложениях для флаттера, и я ожидаю, что у вас уже есть предварительные знания о написании приложений для флаттера. Давайте приступим к делу!

Что такое реактивное программирование?

По данным Википедии:

Реактивное программирование - это парадигма программирования, ориентированная на потоки данных и распространение изменений. Это означает, что должна быть возможность легко выражать статические или динамические потоки данных на используемых языках программирования, и что базовая модель выполнения будет автоматически распространять изменения через поток данных.

В реактивном программировании данные передаются в структуре, заданной языком, фреймворком или библиотекой, которые вы используете, таким образом, что когда данные передаются в структуру на одном конце, вывод всегда будет обновляться, если значение этих данных изменится.

Именно это и делают потоки. Поток - это поток асинхронных событий. Рассматривайте его как трубу, содержащую жидкость. Вы наливаете жидкость из одного конца трубы, а она выходит из другого конца.

Потоки могут нести и обрабатывать различные типы данных, такие как объект, функция, карта, список и даже потоки потоков. Довольно круто, а?

Теперь примеры кода

В первом примере создается простой поток, который принимает строку и по завершении выводит ее:

@override
void initState() {
super.initState();
Stream<String> stream = new Stream.fromFuture(inputData());
stream.listen((data) {
print("Our data: " + data);
}, onDone: () {
print("Done");
}, onError: (error) {
print("Error returned");
});
}
Future<String> inputData() async {
print("Fetching Data...");
return "Let's Use Streams!";
}

Выход

Получение данных…
Наши данные: давайте воспользуемся потоками!
Готово

Здесь Stream получает данные от функции inputData(), которая возвращает текст “Let’s use streams!” . Затем мы используем stream.listen() для работы с данными, поступающими в поток. Здесь у нас есть onDone() , и onError() метод. onDone() использует данные, когда процесс завершен, и onError() может использоваться для выдачи ошибки, если она есть.

Второй пример

final StreamController controller= StreamController();
controller.stream.listen((data) {
print("received data: $data");
}, onDone: () {
print("Stream done");
}, onError: () {
print("Error occured");
});
// data flowing into the stream
controller.sink.add('stream controllers are awesome');
controller.sink.add("Because You can do more");
controller.sink.add('random string');
// Close the StreamController when done to avoid memory leaks
controller.close();

Выход

полученные данные: потрясающие контроллеры потоков
полученные данные: потому что вы можете делать больше
полученные данные: случайная строка
поток завершен

Класс StreamController создает контроллер для любого создаваемого потока. чтобы вам было проще использовать несколько слушателей (мы скоро к этому вернемся). Здесь мы добавляем наши данные с помощью sink.add() ,, который представляет собой объект, принимающий данные, вводимые в поток. Кроме того, вы должны закрыть ваш контроллер после его использования, чтобы предотвратить утечку памяти.

Трансляция потоков

Этот тип потока позволяет использовать несколько слушателей. Созданные нами ранее потоки могли иметь только одного слушателя; они известны как потоки с одной подпиской.

Пример кода

@override
void initState() {
super.initState();
stream();
}
final StreamController controller = StreamController.broadcast(); //add a .broadcast() 
stream() {
controller.stream.where((data) => (data is String)).listen((data) {
print("DataReceived: " + data);
}, onDone: () {
print("Task 1 Done");
}, onError: (error) {
print("Some Error");
});
controller.stream.where((data) => (data is int)).listen((data) {
print("DataReceived: " + data.toString());
}, onDone: () {
print("Task 2 Done");
});
controller.stream.where((data) => (data is Map)).listen((data) {
print(data);
}, onDone: () {
print("Task 3 Done");
});

controller.sink.add('random string');
controller.sink.add(1234);
controller.sink.add({'key 1': 'value A', 'key 2': 'value B'});
controller.close();
}

Выход

DataReceived: случайная строка

Получено данных: 1234

{ключ 1: значение A, ключ 2: значение B}

Задание 1 выполнено

Задание 2 выполнено

Задание 3 выполнено

Здесь мы инициализируем StreamController с помощью .broadcast() , а затем прослушиваем поток три раза. Обратите внимание, что перед прослушиванием мы использовали метод .where() , это помогает мне прослушивать только те данные в потоке, которые соответствуют заданному условию. Сначала мы печатаем только строки, затем целые числа, а затем карты.

Теперь вы знаете, как создавать и использовать поток. Я напишу отдельную статью, где мы сможем использовать потоки для рисования виджетов на нашем экране в реальном рабочем приложении!

Вы можете найти меня в Твиттере.