How to cache PagingData in a way that it does not cause its data to reflow(如何以不导致数据回流的方式缓存PagingData)
问题描述
我有两个片段的简单设置:ConversationFragment
和DetailsFragment
我正在使用Room
和Paging 3 library
,为了填充ConversationFragment
,我正在使用PagingLiveData
实现和属于ConversationFragment
的AndroidViewModel
。
我在这里使用的不是Navigation Components
,根据Android文档,这只是一个通用的片段导航。
DetailsFragment
,然后再次返回到该片段。一切正常,直到我打开所述片段并返回,那么绑定在ConversationFragment
中的观察者就会丢失,因为该片段在打开DetailsFragment
时会被销毁。
到目前为止,这不是一个大问题,我可以再次重新启动观察器,当我这样做时,它确实可以工作。
但是,当我再次附加观察器时,整个列表回流,这会导致RecyclerView
中的项目变得狂野,列表所在的位置丢失,并且滚动条更改大小以确认页面正在加载/重新加载。
我可以在一定程度上忍受这种怪异的行为,但在此基础上失去职位是不可接受的。
我研究了在视图模型中缓存结果,但我可以在可用的文档中找到的示例都是基本的,没有说明如何使用LiveData<PagingData<...>
对象实现相同的结果。
目前我拥有的是以下内容:
ConversationFragment
@Override
public void onViewCreated(
@NonNull View view,
@Nullable Bundle savedInstanceState
) {
if (viewModel == null) {
viewModel = new ViewModelProvider(this).get(ConversationViewModel.class);
}
if (savedInstanceState == null) {
// adapter is initialized in onCreateView
viewModel
.getList(getViewLifecycleOwner())
.observe(getViewLifecycleOwner(), pagingData -> adapter.submitData(lifecycleOwner.getLifecycle(), pagingData));
}
super.onViewCreated(view, savedInstanceState);
}
ConversationViewModel
public class ConversationViewModel extends AndroidViewModel {
final PagingConfig pagingConfig = new PagingConfig(10, 10, false, 20);
private final Repository repository;
private final MutableLiveData<PagingData<ItemView>> messageList;
public ConversationFragmentVM(@NonNull Application application) {
super(application);
messageList = new MutableLiveData<>();
repository = new Repository(application);
}
public LiveData<PagingData<ItemView>> getList(@NonNull LifecycleOwner lifecycleOwner) {
// at first I tried only setting the value if it was null
// but since the observer is lost on destroy and the value
// is not it would never be able to "restart" the observer
// again
// if (messageList.getValue() == null) {
PagingLiveData.cachedIn(
PagingLiveData.getLiveData(new Pager<>(pagingConfig, () -> repository.getMessageList())),
lifecycleOwner.getLifecycle()
).observe(lifecycleOwner, messageList::setValue);
// }
return messageList;
}
}
实际上,即使我返回PagingLiveData.cachedIn
的结果,当我返回到片段时,行为也是一样的;项目在回收视图列表中显示不稳定的行为,并且它所在的位置完全丢失。
这就是我试图实现的目标,看看它是否解决了我的问题:
这是此处提供的代码实验室:https://developer.android.com/codelabs/android-training-livedata-viewmodel#8
如您所见,mAllWords
被缓存,它们仅在第一次构造视图模型时初始化,任何后续更改都只是更新,并且只需要在片段被销毁并在后台堆栈中重新创建时附加新的观察器。
这就是我想要做的,但它并不像我想象的那样工作,至少不像我想象的那么简单。
如何实现此目标?
推荐答案
这里有很多需要解包的内容,但我最好的猜测是ConversationViewModel
中的getList
方法。使用ViewModels和LiveData跨导航持久化数据是正确的,但是在这里,您是在每次调用此方法时重新创建LiveData,这意味着当您恢复ConversationFragment
和onViewCreated
被调用时,它会创建一个新的分页程序来获取新数据。
ConversationViewModel
时创建分页向导,然后访问LiveData对象本身,而不是方法。您可以在Codelab示例中看到这一点,他们在构造函数中分配LiveData,并在getAllWords()
方法中简单地返回已经创建的LiveData。
我使用this作为示例,将ConversationViewModel
更改为类似以下内容,并将其更改为使用您的配置和存储库。
private final LiveData<PagingData<ItemView>> messageList;
public ConversationFragmentVM(@NonNull Application application) {
super(application);
repository = new Repository(application);
// CoroutineScope helper provided by the lifecycle-viewmodel-ktx artifact.
CoroutineScope viewModelScope = ViewModelKt.getViewModelScope(viewModel);
Pager<Integer, User> pager = Pager<>(
new PagingConfig(/* pageSize = */ 20),
() -> ExamplePagingSource(backend, query));
messageList = PagingLiveData.cachedIn(PagingLiveData.getLiveData(pager), viewModelScope);
}
public LiveData<PagingData<ItemView>> getList(){
return messageList;
}
然后在您的片段中,您只需像往常一样观察getList(),只是这次它返回的是预先存在的版本。
viewModel.getList().observe(getViewLifecycleOwner(), pagingData ->
adapter.submitData(lifecycleOwner.getLifecycle(), pagingData));
}
我无法测试这是否可以编译或工作,如果不能,请让我知道,我将更新此答案。
这篇关于如何以不导致数据回流的方式缓存PagingData的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持编程学习网!
本文标题为:如何以不导致数据回流的方式缓存PagingData
基础教程推荐
- 如何在 iPhone 上显示来自 API 的 HTML 文本? 2022-01-01
- Kivy Buildozer 无法构建 apk,命令失败:./distribute.sh -m “kivy"d 2022-01-01
- 当从同一个组件调用时,两个 IBAction 触发的顺序是什么? 2022-01-01
- 在 gmail 中为 ios 应用程序检索朋友的朋友 2022-01-01
- 如何在 UIImageView 中异步加载图像? 2022-01-01
- android 应用程序已发布,但在 google play 中找不到 2022-01-01
- UIWebView 委托方法 shouldStartLoadWithRequest:在 WKWebView 中等效? 2022-01-01
- 如何让对象对 Cocos2D 中的触摸做出反应? 2022-01-01
- Android:对话框关闭而不调用关闭 2022-01-01
- 如何在没有IB的情况下将2个按钮添加到右侧的UINavigationbar? 2022-01-01