Сбор нескольких потоков в один

#android #kotlin #kotlin-coroutines #kotlin-flow

Вопрос:

Я собираю данные из хранилища данных в потоках во вложенном запуске{}.

 viewLifecycleOwner.lifecycleScope.launchWhenStarted {   launch {   DataStore.userName.collect {  // it emits string value  Log.e(TAG, it )  }  }  launch {  DataStore.userPhone.collect {  // it emits string value  Log.e(TAG, it )  }  }  launch {  DataStore.userAddress.collect {  // it emits string value  Log.e(TAG, it )  }  }  }  

Есть ли лучший способ собирать потоки фрагментами ? Например, сбор всех данных в одном блоке запуска {}.

Комментарии:

1. Использование может использовать комбинацию : fun lt;T1, T2, T3, Rgt; combine(flow: Flowlt;T1gt;, flow2: Flowlt;T2gt;, flow3: Flowlt;T3gt;, transform: suspend (T1, T2, T3) -gt; R): Flowlt;Rgt; . Поэтому используйте здесь combine(DataStore.userName, DataStore.userPhone, DataStore.userAddress, ::Triple).onEach{ (name, phone, address) -gt; .... }.launchIn(scope) — подумайте о добавлении этого в качестве удобного метода в DataStore .

Ответ №1:

Один из вариантов-объединить все потоки следующим образом:

 combine(DataStore.userName, DataStore.userPhone, DataStore.userAddress) { userName, userPhone, userAddress -gt;  // Operate on these values }  

Другим вариантом может быть использование launchIn , которое запускает сбор потока в предоставленной области сопрограммы.

 viewLifecycleOwner.lifecycleScope.launchWhenStarted {   DataStore.userName.onEach { userName -gt;  // ...  }.launchIn(this)   DataStore.userPhone.onEach { userPhone -gt;  // ...  }.launchIn(this)   DataStore.userAddress.onEach { userAddress -gt;  // ...  }.launchIn(this) }  

launchIn это просто сокращение для scope.launch { flow.collect() } .

Комментарии:

1. Чтобы уточнить, функция combine() выдает новую комбинацию текущих значений из всех потоков источника всякий раз, когда один поток источника выдает новое значение. Это может быть желательным поведением, но может привести к нескольким избыточным операциям. Для уникальных комбинаций, таких как пользовательские данные, zip() может быть лучшим вариантом.

2. @nulldroid Можем ли мы использовать zip с несколькими потоками? Из того, что я помню, мы можем застегивать только два потока одновременно, flow1.zip(flow2) { a,b -gt; }

3. Ой, как-то я об этом забыла. Вы правы, zip работает только с двумя потоками из коробки. В этом случае вам нужно будет сделать вложенный почтовый индекс. flow1.zip(поток 2) { a,b -gt; }.zip(поток 3) {ab, c -gt;gt; }

4. Zip будет выдавать только тогда, когда все потоки изменятся .. поэтому, например, если пользователь изменит свой адрес, последнее изменение адреса не будет замечено с помощью оператора zip. Также цепные молнии означают, что они неявно зависят от предыдущей операции с молнией, что может привести к другим проблемам. Combine-это правильный оператор, который объединяет последние из всех потоков, независимо от того, обновляются ли они независимо.

5. Все варианты приветствуются , я думаю, что я пойду с объединением трех потоков. Кажется, это решает мою проблему