标签: kotlin-flow

Kotlin 流排序

有没有办法按自定义顺序对流发出的集合进行排序,例如:

fun getList():Flow<Something>

fun main(){
   launch{
       getList().filter{}.map{}.sortBy{
                //
       }.toList()
   }
}
Run Code Online (Sandbox Code Playgroud)

kotlin kotlin-coroutines kotlin-flow kotlin-coroutines-flow

1
推荐指数
1
解决办法
967
查看次数

Kotlin 协程。Kotlin Flow 和共享首选项。waitClose 从未被调用

我很乐意观察共同偏好的变化。以下是我使用 Kotlin Flow 执行此操作的方法:

数据源。

interface DataSource {

    fun bestTime(): Flow<Long>

    fun setBestTime(time: Long)
}

class LocalDataSource @Inject constructor(
    @ActivityContext context: Context
) : DataSource {

    private val preferences = context.getSharedPreferences(PREFS_FILE_NAME, Context.MODE_PRIVATE)

    @ExperimentalCoroutinesApi
    override fun bestTime() = callbackFlow {
        trySendBlocking(preferences, PREF_KEY_BEST_TIME)
        val listener = SharedPreferences.OnSharedPreferenceChangeListener { sharedPreferences, key ->
            if (key == PREF_KEY_BEST_TIME) {
                trySendBlocking(sharedPreferences, key)
            }
        }
        preferences.registerOnSharedPreferenceChangeListener(listener)
        awaitClose { // NEVER CALLED
            preferences.unregisterOnSharedPreferenceChangeListener(listener)
        }
    }

    @ExperimentalCoroutinesApi
    private fun ProducerScope<Long>.trySendBlocking(
        sharedPreferences: SharedPreferences,
        key: String?
    ) {
        trySendBlocking(sharedPreferences.getLong(key, 0L))
            .onSuccess …
Run Code Online (Sandbox Code Playgroud)

android callback kotlin kotlin-coroutines kotlin-flow

1
推荐指数
1
解决办法
8007
查看次数

stateIn 运算符不会更新 StateFlow 的缓存值

我有一些共享流,它们被合并为不同类中的多个流,然后这些流被合并为一个流。原始共享流配置如下:

protected val statusMutable = MutableSharedFlow<Int>()
val status: Flow<Int> = statusMutable.asSharedFlow()
Run Code Online (Sandbox Code Playgroud)

所以,默认配置。最后我有这样的代码:

val status
    get() = merge(
        object1.status, // merged shared flows
        object2.status, // merged shared flows
        object3.status, // merged shared flows
        statusMutable
    ).stateIn(GlobalScope, SharingStarted.Lazily, initialValue = someInt)
Run Code Online (Sandbox Code Playgroud)

这个流应该是无限热流,所以我正在使用GlobalScope(如果有更好的方法,你也可以告诉我如何更好地处理这个问题,但这不是实际的问题)。

实际的问题是,值被很好地发出和收集,但由于某种原因,结果StateFlow并没有更新其值属性(因此重播缓存)。这会导致新订阅者无法获得订阅的最新发出值的情况。造成这种情况的原因是什么以及如何解决?

android kotlin kotlin-coroutines kotlin-flow

1
推荐指数
1
解决办法
636
查看次数

当过滤器需要更改时重新运行 StateFlow?

我有一个StateFlow包含简单的字符串列表。我希望能够过滤该字符串列表。每当过滤器更新时,我想向 StateFlow 推送新的更新。

class ResultsViewModel(
    private val api: API
) : ViewModel() {

  var filter: String = ""
  val results: StateFlow<List<String>> = api.resultFlow()
        .stateIn(viewModelScope, SharingStarted.Eagerly, emptyList())
}
Run Code Online (Sandbox Code Playgroud)

map将 a 粘贴到 上很容易api.resultFlow()

  val results: StateFlow<List<String>> = api.resultFlow()
        .map { result ->
            val filtered = mutableListOf<String>()
            for (r in result) {
                if (r.contains(filter)) {
                   filtered.add(r)
                }
            }
            filtered
        }
        .stateIn(viewModelScope, SharingStarted.Eagerly, emptyList())
Run Code Online (Sandbox Code Playgroud)

但是,如何让流程在filter发生变化时真正发出更新呢?目前,这仅适用于filter设置的初始值。

kotlin kotlin-flow kotlin-stateflow

1
推荐指数
1
解决办法
1624
查看次数

难道 Flow.collect() 会阻塞 UI?

我正在 kotlinlang.org 上阅读有关流程的文章:https ://kotlinlang.org/docs/flow.html

他们展示了下一个例子:

fun simple(): Flow<Int> = flow { 
   println("Flow started")
   for (i in 1..3) {
       delay(100)
       emit(I)
   }
}

fun main() = runBlocking<Unit> {
   println("Calling simple function...")
   val flow = simple()
   println("Calling collect...")
   flow.collect { value -> println(value) } 
   println("Calling collect again...")
   flow.collect { value -> println(value) } 
}
Run Code Online (Sandbox Code Playgroud)

他们说输出是:

Calling simple function...

Calling collect...
Flow started

1

2

3

Calling collect again...

Flow started

1

2

3
Run Code Online (Sandbox Code Playgroud)

因此,UI 线程似乎正在等待第一个flow.collect函数完成,然后再继续打印“再次调用收集...”

我希望当第一个流程构建器运行时,系统将打印“再次调用收集...”,因此输出将是:

Calling simple function... …
Run Code Online (Sandbox Code Playgroud)

android kotlin kotlin-coroutines kotlin-flow

1
推荐指数
1
解决办法
886
查看次数

如何在 Jetpack Compose 中正确使用 Flow 和 ProgressBar?

我有这段代码可以增加数据库中的值:

override fun incrementQuantity() = flow {
    try {
        emit(Result.Loading)
        heroIdRef.update("quantity", FieldValue.increment(1)).await()
        emit(Result.Success(true))
    } catch (e: Exception) {
        emit(Result.Failure(e))
    }
}
Run Code Online (Sandbox Code Playgroud)

该函数是从 ViewModel 类中调用的,然后从可组合函数中读取如下响应:

when(val response = viewModel.incrementResponse) {
    is Result.Loading -> showProgressBar()
    is Result.Success -> Log.d("TAG", "Quantity incremented.")
    is Result.Failure -> Log.d("TAG", response.e.message)
}
Run Code Online (Sandbox Code Playgroud)

这意味着在流程中我收到两个事件,第一个是Loading,第二个是数据或失败。我的问题是:

建议这样做吗?或者最好不使用流程并使用如下内容:

override fun incrementQuantity(): Result<Boolean> {
    try {
        heroIdRef.update("quantity", FieldValue.increment(1)).await()
        Result.Success(true)
    } catch (e: Exception) {
        Result.Failure(e)
    }
}
Run Code Online (Sandbox Code Playgroud)

在可组合项内部:

showProgressBar()
when(val response = viewModel.incrementResponse) {
    is Result.Success -> {
        hideProgressBar()
        Log.d("TAG", "Quantity incremented.") …
Run Code Online (Sandbox Code Playgroud)

android kotlin kotlin-coroutines android-jetpack-compose kotlin-flow

1
推荐指数
1
解决办法
3300
查看次数

Android Flow/StateFlow 和数据绑定/Room

我正在尝试弄清楚流/状态流和数据绑定。

\n

在我的项目中,我有 Room 中的“打印机”列表,以及 SharedPreferences 中的“默认打印机”的 ID。

\n

这是我的架构:\n在此输入图像描述

\n

1\xc2\xb0/ 问题:我在这个架构中表现良好?

\n

我是否使用了良好的流程并做得很好,还是出了什么问题?

\n

2\xc2\xb0/ 第一个问题:在我的列表中获取我的默认打印机

\n

房间给我一个Flow<List<Printer>>。借助我的适配器,我将其显示在回收器视图中viewModel.allPrinters.collect

\n

但是,当我想从房间绑定资源时,绑定“需要”LiveData 或 StateFlow,这是我的困难,因为 stateIn 需要协程。

\n

我怎样才能从我的默认打印机Flow<List<Printer>>(通过他的属性“id”在列表中找到它)并确保列表/项目是否更新,我的参考也将获得更新?\n如果我更改打印机的名称defaultPrinter并将其更新到 room(感谢我的存储库/room DAO),我希望在我的对象defaultPrinter和列表中更改名称。

\n

您还可以确认我的变量类型defaultPrinter应该是StateFlow<Printer?>

\n

注意:当我更新项目时,printerRoomDAO.update(item:Printer)我必须传递数据对象的副本Printer(新引用),否则我的 UI 将不会更新。

\n

3\xc2\xb0/ 第二个问题:使用状态流看起来很复杂

\n

isPrinterListEmpty这是我的 ViewModel 中的示例

\n
val hasNoPrinter = allPrinters.mapLatest {\n    it.isEmpty()\n}.asLiveData()\n
Run Code Online (Sandbox Code Playgroud)\n

它运行良好,但我不应该使用 StateFlow 吗?怎么做 ?因为stateIn()需要一个协程,而我下面的尝试不起作用。

\n
val hasNoPrinter = …
Run Code Online (Sandbox Code Playgroud)

data-binding kotlin android-livedata kotlin-flow kotlin-stateflow

1
推荐指数
1
解决办法
2643
查看次数

如何使用参数收集 ViewModel 中的流

我在存储库中有一个函数,它根据参数从网络或远程数据源返回响应。

图书库:

suspend fun getBooks(isNetwork: Boolean) : Flow<Books>
Run Code Online (Sandbox Code Playgroud)

我想在视图模型中收集它,但每次调用 ViewModel 方法时都会创建一个新的协程。我知道我应该在暴露给 UI 层之前映射流程,但是如何将参数传递给函数呢?

图书视图模型:

fun getBooks(isNetwork: Boolean) {
        viewModelScope.launch {
            bookRepository.getBooks(isNetwork).collectLatest { books ->
             ...
            }
        }
}
Run Code Online (Sandbox Code Playgroud)

这里getBooks函数也用于进行网络调用,需要多次调用。每次调用 ViewModel 中的 getBooks 时,都会创建一个新的协程,从而创建多个观察者。

android mvvm coroutine kotlin-flow

1
推荐指数
1
解决办法
2578
查看次数

通过 Kotlin 中的另一个挂起函数发出 Flow

如何让下面的流量收集器收到“hello”?收集器正在调用,myFunction1()而收集器又调用myFunction2(). 两者都是挂起函数。

目前,当我点击运行并且没有收到流量时,什么也没有发生。我在这里错过了什么吗?

CoroutineScope(IO).launch {
    val flowCollector = repo.myFunction1()
        .onEach { string ->
            Log.d("flow received: ", string)
        }
        .launchIn(GlobalScope)
}

Run Code Online (Sandbox Code Playgroud)
class Repo {

    suspend fun myFunction1(): Flow<String> = flow {
        /*some code*/
        myFunction2()
    }

    suspend fun myFunction2(): Flow<String> = flow {
        /*some code*/
        emit("hello")
    }
}
Run Code Online (Sandbox Code Playgroud)

suspend coroutine kotlin kotlin-coroutines kotlin-flow

0
推荐指数
1
解决办法
3627
查看次数

如何从构建的流对象中发出值

我的问题是我们如何从构建的流对象中发出一个值,如下所示:

class Sample {
    var flow: Flow<Object> = null

    fun sendRequest(){
       flow = flow{}
       requestWrapper.flowResponse = flow

    }

    fun getResponse(){
       // I want to emit data here with built flow object on 
       // requestWrapper like this

        requestWrapper.flowResponse.emit()

    }
}
Run Code Online (Sandbox Code Playgroud)

这个问题有什么可能的解决方案吗?

android kotlin kotlin-coroutines kotlin-flow kotlin-sharedflow

0
推荐指数
1
解决办法
627
查看次数