标签: kotlin-flow

如何将 kotlin 中的挂起函数和流程的结果结合起来?

伙计们想象我有这两个数据源:

val flowA: Flow<String>
suspend fun funB(): Int
Run Code Online (Sandbox Code Playgroud)

如何将两者的结果合并到一个流程中(比方说Flow<Pair<String, Int>>)?

下面的方法怎么样?有没有更好的办法?

combine(
  flowA,
  flow {emit(funB())}
) { a, b ->
  ...
}
Run Code Online (Sandbox Code Playgroud)

suspend reactive-programming kotlin kotlin-flow

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

如何结合 livedata 和 kotlin flow

把最新的collect放在observe里面好不好?

viewModel.fetchUserProfileLocal(PreferencesManager(requireContext()).userName!!)
            .observe(viewLifecycleOwner) {
                if (it != null) {
                    viewLifecycleOwner.lifecycleScope.launch {
                        viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
                            launch {
                                viewModel.referralDetailsResponse.collect { referralResponseState ->
                                    when (referralResponseState) {
                                        State.Empty -> {
                                        }
                                        is State.Failed -> {
                                            Timber.e("${referralResponseState.message}")
                                        }
                                        State.Loading -> {
                                            Timber.i("LOADING")
                                        }
                                        is State.Success<*> -> {
                                            // ACCESS LIVEDATA RESULT HERE??
}}}}
Run Code Online (Sandbox Code Playgroud)

我确信不是,当本地数据库发生变化时,我的 API 也会被调用三次,正确的方法是什么?

我的 ViewModel 看起来像这样,我从本地 Room DB 获取用户信息,推荐详细信息响应是 API 响应

private val _referralDetailsResponse = Channel<State>(Channel.BUFFERED)
val referralDetailsResponse = _referralDetailsResponse.receiveAsFlow()

init {
        val inviteSlug: String? = savedStateHandle["inviteSlug"]
        // Fire invite link
        if (inviteSlug …
Run Code Online (Sandbox Code Playgroud)

android kotlin android-livedata kotlin-coroutines kotlin-flow

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

如何使用挂起函数作为参数来初始化视图模型中的流

我正在使用房间数据库和数据存储。这是我的代码

视图模型

@HiltViewModel
class SubscriptionViewModel @Inject constructor(
    private val userDataStore: UserDataStore,
    private val walletDao: WalletDao
) : ViewModel() {

val flow: Flow<List<Transaction>> = walletDao.getAllTransactions(userDataStore.getId()) 
 // This shows an error as userDataStore.getId() is a suspend function in DataStore


 init {
        viewModelScope.launch(IO) {
            getWalletAmount()
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

数据存储

 suspend fun getId(): String {
        val preferences = dataStore.data.first()
        return preferences[USER_ID] ?: ""
    }
Run Code Online (Sandbox Code Playgroud)

钱包道

 @Query("SELECT * FROM recent_transactions where user_id=:user_id")
    fun getAllTransactions(user_id: String): Flow<List<Transaction>>
Run Code Online (Sandbox Code Playgroud)

问题是我无法初始化流程。我尝试使用 Lateinit 在 init{ } 块中初始化它,但是在片段中访问时它崩溃,表示流程尚未初始化。

任何解决方案都会有帮助。

android kotlin android-room kotlin-coroutines kotlin-flow

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

如何设计一个Flow,它是另一个Flow的每最新5个数据的平均值?

有一个Flow每100ms就会发出一次数据,我希望得到该Flow的每最新5个数据的平均值,并将平均值转换为Double值到另一个Flow中。

如何设计流程?

代码A

   fun soundDbFlow(period: Long = 100) = flow {
        while (true) {
            var data = getAmplitude()
            emit(data)
            delay(period)
        }
    }
    .get_Average_Per5_LatestData {...} //How can I do? or is there other way?
    .map { soundDb(it) }

    private fun getAmplitude(): Int {
        var result = 0
        mRecorder?.let {
            result = it.maxAmplitude
        }
        return result
    }    
        
    private fun soundDb(input:Int, referenceAmp: Double = 1.0): Double {
        return 20 * Math.log10(input / referenceAmp)
    }
Run Code Online (Sandbox Code Playgroud)

新增内容:

致plplmax:谢谢!

我假设代码 B 会发出 1,2,3,4,5,6,7,8,9,10.....

你保证代码C会(1+2+3+4+5)/5先计算,然后 …

kotlin kotlin-flow

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

Kotlin Map 项目列表流程

我有一个事务存储库,我可以从中获取Flow<List<Transaction>>.
基于这些数据,我需要创建一个Flow<List<Source?>>.

可以传递给 which 的hastransaction返回一个源(如果存在),否则返回。sourceIdsourceRepository.getSource()null

视图模型代码

var transactions: Flow<List<Transaction>> = transactionRepository.transactions
var sourceList: Flow<List<Source?>> = flow {
    transactions.map {
        it.map { transaction ->
            if (transaction.sourceId != null) {
                sourceRepository.getSource(transaction.sourceId)
            } else {
                null
            }
        }
    }.collect {
        emit(it)
    }
}
Run Code Online (Sandbox Code Playgroud)

有什么办法可以改变mapmap减少这段代码吗?

android kotlin kotlin-flow

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

Kotlin Flow“在此范围内有多个具有此类名称的标签”

我有一个流集合,我想要执行一个条件,如果列表为空则返回,因为没有进一步的工作要做。

我的问题是 Android studio 向我抛出一条烦人的消息

此范围内有多个具有此类名称的标签

我假设它很沮丧,因为我正在收集中进行收集(请参阅下面的代码,希望它能理解我为什么这样做)。

有没有一种方法可以重新标记集合,以便它知道我在谈论哪一个,我在上面没有看到任何内容。

另外,我是流程新手,所以如果我做错了,请告诉我正确的方法,因为这似乎是有效的,因为我需要一个流程用于另一个流程。

viewModelScope.launch {
    companyDataStore.getFromDataStore()
        .catch { e ->
            _snackBar.value = e.message
        }.collect { company ->
            companyFeatures = company.features

            userClient.getGroupsByFeatures(companyFeatures)
                .catch { e ->
                    _snackBar.value = e.message
                }
            .collect { groupList ->
                if (groupList.data?.size == 0)
                {
                    return@collect
                }

                groups = groupList.data!!
                feedFilter.group = groups.firstOrNull()?.guid
            }
        }
}
Run Code Online (Sandbox Code Playgroud)

android kotlin android-studio kotlin-coroutines kotlin-flow

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

使用 flow 作为 API 调用的返回类型

我从过去 8 个月开始就开始关注 kotlin 和协同例程,根据我的理解,如果我们将它用作 api 调用的返回类型,那么它并不是流的最佳使用。

例如:

fun getCoutries(): Flow<List<Country>> = flow {
   emit(apiInterface.getAllCountries())
}
Run Code Online (Sandbox Code Playgroud)

我在一次性 api 调用中看到类似这样的流的使用,我想知道是否应该阻止这种情况。因为流是一股流,而不是一次射击。

android coroutine kotlin kotlin-coroutines kotlin-flow

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

Android 首选项数据存储流不会发出相同的值

只是测试Preferences DataStore并发现提供的Flow输出不会发出相同的值,我的设置如下:

数据存储实用程序类:

object DataStore {
    private val Context.settings by preferencesDataStore("settings") 

    suspend fun saveBoolean(context: Context, keyResId: Int, value: Boolean) {
        val key = booleanPreferencesKey(context.getString(keyResId))

        context.settings.edit {
            it[key] = value
        }
    }

    fun getBooleanFlow(context: Context, keyResId: Int, defaultValueResId: Int): Flow<Boolean> {
        val key = booleanPreferencesKey(context.getString(keyResId))
        val defaultValue = context.resources.getBoolean(defaultValueResId)

        return context.settings.data.map {
            it[key] ?: defaultValue
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

视图模型类:

class FirstViewModel(application: Application) : AndroidViewModel(application) {
    private val uiScope = viewModelScope

    val isUpdateAvailable = DataStore.getBooleanFlow(
        getApplication(), R.string.is_update_available_key, R.bool.is_update_available_default …
Run Code Online (Sandbox Code Playgroud)

android android-preferences sharedpreferences kotlin-flow android-jetpack-datastore

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

Android 中 Flow 的一次性操作

我正在尝试在 中显示用户信息DetailActivity。因此,我请求数据并从服务器获取用户的数据。但在本例中,返回类型是Flow<User>. 让我向您展示以下代码。

ServiceApi.kt

@GET("endpoint")
suspend fun getUser(@Query("id") id: Int): Response<User>
Run Code Online (Sandbox Code Playgroud)

存储库.kt

fun getUser(id: Int): Flow<User> = flow<User> {
    val userResponse = api.getUser(id = id)
    if (userResponse.isSuccessful) {
        val user = userResponse.body()
        emit(user)
    }
}
.flowOn(Dispatchers.IO)
.catch { // send error }
Run Code Online (Sandbox Code Playgroud)

详细视图模型.kt

class DetailViewModel(
    private val repository : Repository
) {
    val uiState: StateFlow<User> = repository.getUser(id = 369).stateIn(
        scope = viewModelScope,
        started = SharingStarted.WhileSubscribed(5000),
        initialValue = User() // empty user
    )
}
Run Code Online (Sandbox Code Playgroud)

详细活动.kt

class DetailActivity: …
Run Code Online (Sandbox Code Playgroud)

android android-lifecycle kotlin-flow

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

当生产者发出多个值时 single() 和 first() 终端运算符

我只需要收集流发出的两个值中的第一个值。

我有一个返回流量的函数:

fun myFlow = flow {
    try {
        emit(localDataSource.fetchData())
    } catch(e: Exception) { 
        // just skip this error
    }
    emit(remoteDataSource.fetchData(1000, 0))
}
Run Code Online (Sandbox Code Playgroud)

在一种特殊情况下,我只需要第一个发出的值,无论它是来自本地缓存还是远程源。我尝试过这个:

fun getRandomFavoriteItem() = myFlow.first().filter { it.score > 7 }.randomOrNull()

但first()调用总是抛出

java.lang.IllegalStateException:违反了流异常透明度:先前的“emit”调用引发了异常 kotlinx.coroutines.flow.internal.AbortFlowException:流已中止,不再需要元素,但随后尝试发射值。

我尝试过的:

  1. 单身的() -

java.lang.IllegalArgumentException:流有多个元素

  1. take(1).first() -

java.lang.IllegalStateException:违反了流异常透明度:先前的“emit”调用引发了异常 kotlinx.coroutines.flow.internal.AbortFlowException:流已中止,不再需要元素,但随后尝试发射值

  1. 捕获错误,但它并不止于此:
myFlow.catch { e ->
    if (e !is IllegalArgumentException) {
        throw e
    }
}.first().filter { it.score > 7 }.randomOrNull()
Run Code Online (Sandbox Code Playgroud)

我的问题是:

  1. 如果在发出的值超过 1 个的情况下它不起作用,那么使用 first() 的意义何在?如果我知道我的流程仅产生一个值,我可以使用任何其他终端运算符。
  2. 如何避免这些错误以及如何仅收集第一个值而不添加重复代码?

kotlin kotlin-flow

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