我使用 Room 作为我的 Android TV 应用程序的数据库。 我有四个不同的实体:帐户、类别、渠道、数据。 在我的 MainFragment 中,我并排显示 3 个回收器视图。
第一个显示已激活的帐户(其中 account.isActive = 1),第二个显示当帐户获得焦点时相关帐户的类别(category.favorite = 1)。然后是channelwithdata-recyclerview,当类别获得焦点时,它显示类别的相关频道(其中channel.isSelected = 1)及其相关信息(数据)。 因此可以有多个帐户,每个帐户可以有多个类别,每个类别都有多个包含其数据的通道。 目前,在 MainActivity 的 onCreate 中启动应用程序时,我正在调用 3 个视图模型函数,它们从数据库中获取相关数据作为 LiveData,并将每个数据保存在视图模型中的变量中。例如我打电话:
viewmodel.getActivatedAccounts()
在 MainActivity 中
-> 在我的视图模型中:
accountsLiveData: LiveData<List<Account>>? = null
和
private fun getActivatedAccounts() =
viewModelScope.launch {
accountsLiveData = dao.getActivatedAccounts()
}
dao 函数是:
fun getActivatedAccounts(): LiveData<List<Account>>
它对于帐户和类别工作正常,但是当我到达channelsWithData时(因此通道和数据之间的关系->
data class ChannelsWithData(
@Embedded var channel: Channel,
@Relation(
entity = Data::class,
parentColumn = "dataChannelId",
entityColumn = "dataChannelId"
)
var dataList: List<Data>
))
使用 dao 函数:
@Transaction
@Query("SELECT * FROM channel WHERE isSelected = 1")
fun getAllSelectedChannelsWithData(): LiveData<List<ChannelsWithData>>
我注意到,当我在第一次启动更新时安装应用程序更新时,它加载速度很快(大约 1-2 秒),但当我再次启动应用程序时,大约需要 15-20 秒。
所以我想问的是:在应用程序启动时获取我需要的所有数据是一个好主意吗?如果是的话,像我一样将其保存在视图模型实时数据变量中是一个好方法吗?此刻。 或者最好调用一个新的查询,例如:
@Query("SELECT * FROM Channel WHERE accountId = :accountId AND category_id = :categoryId")
fun getChannelsWithDataPerCategoryAndAccount(accountId: Long, categoryId: String): LiveData<List<ChannelsWithData>>
每次一个类别成为焦点?
我的目标是尽可能减少用户在浏览帐户、类别和频道时的等待时间。最好不应该有任何。 另一方面,我不希望用户必须等待近 20 秒才能开始导航:-)
我不知道您的查询有多重,以及您正在处理多少数据,但我认为您可以包含一些内容,以免遇到长时间延迟。 首先,如果您有太多数据,请为回收器视图添加分页。其次,我认为在您的情况下将数据保存在 viewModel 中不是一个好主意。我认为您正在主线程上执行所有操作,相反,您可以使用协程并在后台线程上进行提取,以最大程度地减少等待时间。另一方面,您可以使用缓存并按需获取数据,如果数据发生了变化,也不是每次都如此!另外,您使用的查询在您的情况下似乎效率不高。您的最后一个列表取决于表中的两行,这会产生延迟。您可以将此查询分成两个不同线程上同时进行的两个并行查询。为什么使用livedata?有必要吗?您可以使用 sharedflow 代替。
// In your ViewModel
val pageSize = 20 // Number of items to load per page
var currentPage = 0
var isLoading = false
fun loadNextPage() {
if (isLoading) return
isLoading = true
viewModelScope.launch {
val nextPageData = dao.getActivatedAccounts(pageSize, currentPage * pageSize)
// Process and update your RecyclerView adapter with the nextPageData
currentPage++
isLoading = false
}
}
// In your ViewModel
private fun getActivatedAccounts() = viewModelScope.launch {
withContext(Dispatchers.IO) {
accountsLiveData = dao.getActivatedAccounts()
}
}
// In your ViewModel
var cachedCategories: List<Category>? = null
var cachedChannels: List<ChannelsWithData>? = null
fun getCategories(accountId: Long) = viewModelScope.launch {
if (cachedCategories == null) {
cachedCategories = dao.getFavoriteCategories(accountId)
}
// Use cachedCategories to populate your RecyclerView adapter
}
fun getChannels(categoryId: String) = viewModelScope.launch {
if (cachedChannels == null) {
cachedChannels = dao.getAllSelectedChannelsWithData()
}
// Filter cachedChannels by categoryId and use it to populate your RecyclerView adapter
}
// In your DAO
@Query("SELECT * FROM channel WHERE isSelected = 1")
fun getAllSelectedChannels(): LiveData<List<Channel>>
@Query("SELECT * FROM data WHERE dataChannelId IN (SELECT channelId FROM channel WHERE isSelected = 1)")
fun getSelectedChannelsData(): LiveData<List<Data>>
// In your ViewModel
val activatedAccountsFlow = dao.getActivatedAccountsFlow().asSharedFlow()
// Collect the activatedAccountsFlow in your Fragment or Activity
lifecycleScope.launch {
viewModel.activatedAccountsFlow.collect { activatedAccounts ->
// Update your RecyclerView adapter with the activatedAccounts
}
}
或者甚至不在你的 dao 中使用 LiveData 并在那里发出流。