有没有办法按自定义顺序对流发出的集合进行排序,例如:
fun getList():Flow<Something>
fun main(){
launch{
getList().filter{}.map{}.sortBy{
//
}.toList()
}
}
Run Code Online (Sandbox Code Playgroud) 我很乐意观察共同偏好的变化。以下是我使用 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) 我有一些共享流,它们被合并为不同类中的多个流,然后这些流被合并为一个流。原始共享流配置如下:
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并没有更新其值属性(因此重播缓存)。这会导致新订阅者无法获得订阅的最新发出值的情况。造成这种情况的原因是什么以及如何解决?
我有一个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设置的初始值。
我正在 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) 我有这段代码可以增加数据库中的值:
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
我正在尝试弄清楚流/状态流和数据绑定。
\n在我的项目中,我有 Room 中的“打印机”列表,以及 SharedPreferences 中的“默认打印机”的 ID。
\n\n我是否使用了良好的流程并做得很好,还是出了什么问题?
\n房间给我一个Flow<List<Printer>>。借助我的适配器,我将其显示在回收器视图中viewModel.allPrinters.collect。
但是,当我想从房间绑定资源时,绑定“需要”LiveData 或 StateFlow,这是我的困难,因为 stateIn 需要协程。
\n我怎样才能从我的默认打印机Flow<List<Printer>>(通过他的属性“id”在列表中找到它)并确保列表/项目是否更新,我的参考也将获得更新?\n如果我更改打印机的名称defaultPrinter并将其更新到 room(感谢我的存储库/room DAO),我希望在我的对象defaultPrinter和列表中更改名称。
您还可以确认我的变量类型defaultPrinter应该是StateFlow<Printer?>
注意:当我更新项目时,printerRoomDAO.update(item:Printer)我必须传递数据对象的副本Printer(新引用),否则我的 UI 将不会更新。
isPrinterListEmpty这是我的 ViewModel 中的示例
val hasNoPrinter = allPrinters.mapLatest {\n it.isEmpty()\n}.asLiveData()\nRun Code Online (Sandbox Code Playgroud)\n它运行良好,但我不应该使用 StateFlow 吗?怎么做 ?因为stateIn()需要一个协程,而我下面的尝试不起作用。
val hasNoPrinter = …Run Code Online (Sandbox Code Playgroud) data-binding kotlin android-livedata kotlin-flow kotlin-stateflow
我在存储库中有一个函数,它根据参数从网络或远程数据源返回响应。
图书库:
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 时,都会创建一个新的协程,从而创建多个观察者。
如何让下面的流量收集器收到“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) 我的问题是我们如何从构建的流对象中发出一个值,如下所示:
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
kotlin-flow ×10
kotlin ×9
android ×6
coroutine ×2
callback ×1
data-binding ×1
mvvm ×1
suspend ×1