在应用程序启动时从房间数据库访问数据,以允许无延迟导航

问题描述 投票:0回答:1

我使用 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 秒才能开始导航:-)

android android-room android-livedata
1个回答
0
投票

我不知道您的查询有多重,以及您正在处理多少数据,但我认为您可以包含一些内容,以免遇到长时间延迟。 首先,如果您有太多数据,请为回收器视图添加分页。其次,我认为在您的情况下将数据保存在 viewModel 中不是一个好主意。我认为您正在主线程上执行所有操作,相反,您可以使用协程并在后台线程上进行提取,以最大程度地减少等待时间。另一方面,您可以使用缓存并按需获取数据,如果数据发生了变化,也不是每次都如此!另外,您使用的查询在您的情况下似乎效率不高。您的最后一个列表取决于表中的两行,这会产生延迟。您可以将此查询分成两个不同线程上同时进行的两个并行查询。为什么使用livedata?有必要吗?您可以使用 sharedflow 代替。

    RecyclerViews 的分页:
// 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>>

    使用 SharedFlow 代替 LiveData:
// 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 并在那里发出流。

© www.soinside.com 2019 - 2024. All rights reserved.