伙计们想象我有这两个数据源:
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) 把最新的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
我正在使用房间数据库和数据存储。这是我的代码
视图模型
@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{ } 块中初始化它,但是在片段中访问时它崩溃,表示流程尚未初始化。
任何解决方案都会有帮助。
有一个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先计算,然后 …
我有一个事务存储库,我可以从中获取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)
有什么办法可以改变map并map减少这段代码吗?
我有一个流集合,我想要执行一个条件,如果列表为空则返回,因为没有进一步的工作要做。
我的问题是 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) 我从过去 8 个月开始就开始关注 kotlin 和协同例程,根据我的理解,如果我们将它用作 api 调用的返回类型,那么它并不是流的最佳使用。
例如:
fun getCoutries(): Flow<List<Country>> = flow {
emit(apiInterface.getAllCountries())
}
Run Code Online (Sandbox Code Playgroud)
我在一次性 api 调用中看到类似这样的流的使用,我想知道是否应该阻止这种情况。因为流是一股流,而不是一次射击。
只是测试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
我正在尝试在 中显示用户信息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) 我有一个返回流量的函数:
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:流已中止,不再需要元素,但随后尝试发射值。
java.lang.IllegalArgumentException:流有多个元素
java.lang.IllegalStateException:违反了流异常透明度:先前的“emit”调用引发了异常 kotlinx.coroutines.flow.internal.AbortFlowException:流已中止,不再需要元素,但随后尝试发射值
myFlow.catch { e ->
if (e !is IllegalArgumentException) {
throw e
}
}.first().filter { it.score > 7 }.randomOrNull()
Run Code Online (Sandbox Code Playgroud)