微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Android Kotlin 协程在使用变量打开的片段上创建 RecyclerView

如何解决Android Kotlin 协程在使用变量打开的片段上创建 RecyclerView

标题所述,我尝试在使用变量打开的片段上创建一个回收视图。

这是一个没有变量的工作版本:
片段:

viewmodel.lists.observe(viewLifecycleOwner) {
   listadapter.submitList(it)
}

ViewHolder:

val lists = shishaDao.getList(HARDCODED_INT).asLiveData()

如您所见,有一个硬编码的整数。这个整数可以保存不同的值,这会改变列表的值。

这是我对变量的尝试:
片段:

viewmodel.lists(title).observe(viewLifecycleOwner) {
   listadapter.submitList(it)
}

我现在想访问一个需要必要变量的函数,而不是访问视图持有者的变量。

ViewHolder:

fun lists(title: String): LiveData<List<Tabak>> {
   val nr = dao.getNr(title)
   return dao.getList(nr).asLiveData()
}

应用程序崩溃并出现以下错误

Cannot access database on the main thread since it may potentially lock the UI for a long period of time.

这里也有尝试过的方法

fun lists(title: String): LiveData<List<Tabak>> {
   val nr: Int = 0
   viewmodelScope.launch {
      nr = dao.getNr(title)
      Log.e("NR",nr.toString())
   }
   return dao.getList(nr).asLiveData()
}
fun lists(title: String): LiveData<List<Tabak>> {
   val nr: mutablelivedata<Int> = mutablelivedata(0)
   viewmodelScope.launch {
      nr.value = dao.getNr(title)
      Log.e("NR",nr.value.toString())
   }
   return dao.getList(nr.value!!).asLiveData()
}

两种方法都不会崩溃。 Log.e 显示正确的数字,但最后一行仍然使用 0。

我的实际问题:如何从 dao.getNr(title) 获取 nr 值以在最后一行 getList(nr) 中使用它?

解决方法

我找到了一种使用 LiveData 的方法。这是一个很大的方法,但也很有用。

PreferenceManager.kt

class PreferencesManager @Inject constructor(context: Context) {

    private val dataStore = context.createDataStore("user_preferences")

    val preferencesFlow = dataStore.data
        .catch { exception ->
            if (exception is IOException) {
                Log.e(TAG,"Error reading preferences",exception)
                emit(emptyPreferences())
            } else {
                throw exception
            }
        }
        .map { preferences ->
            val choseMarke = preferences[PreferencesKeys.CHOSE_TITLE] ?: 2
            FilterPreference(choseTitle)
        }

    suspend fun updateChoseTitle (choseTitle: Int) {
        dataStore.edit { preferences ->
            preferences[PreferencesKeys.CHOSE_TITLE] = choseTitle
        }
    }

    private object PreferencesKeys {
        val CHOSE_TITLE = preferencesKey<Int>("chosen_title")
    }
}

Fragment.kt 看起来像这样

viewModel.lists.observe(viewLifecycleOwner) {
   listAdapter.submitList(it)
}

和 ViewModel.kt

class ListsViewModel @ViewModelInject constructor(private val dao: Dao,private val preferencesManager: PreferencesManager,@Assisted private val state: SavedStateHandle) : ViewModel() {
    val searchQuery = state.getLiveData("searchTitle","")
    val preferencesFlow = preferencesManager.preferencesFlow

    ...

    private val listsFlow = combine(searchQuery.asFlow(),preferencesFlow) { query,filterPreference ->
        Pair(query,filterPreference)
    }.flatMapLatest { (_,filterPreference) ->
        dao.getList(filterPreference.choseMarke)
    }

我不再尝试使用片段内的标题。在打开片段之前,我需要按下这个标题的按钮,然后我已经将标题(作为来自 dao getNr 的 int)保存在 mainActivity 中。

MainActivity.kt

onNavigationItemSelected(item: MenuItem): Boolean {
   viewModel.onNavigationClicked(item)
}

MainViewModel.kt

fun onNavigationClicked(item: MenuItem) = viewModelScope.launch {
   val choseMarkeNr = shishaDao.getMarkeNr(item.title.toString())
   preferencesManager.updateChoseMarke(choseMarkeNr)
}

这种方式奏效了。 :)

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。