未在 Fragments (ItemKeyedDataSource) 中获取 LiveData 可观察值
Not getting LiveData observable values within Fragments (ItemKeyedDataSource)
我正在使用 Firestore 并使用 ItemKeyedDataSource
成功地将它与 Paging Library 集成。这是一个要点:
public class MessageDataSource extends ItemKeyedDataSource<Query, Message> {
//... private members
MessageDataSource(Query query) {
mQuery = query;
}
@Override
public void loadInitial(@NonNull LoadInitialParams<Query> params, @NonNull LoadInitialCallback<Message> callback) {
mLoadStateObserver.postValue(LoadingState.LOADING);
mQuery.limit(params.requestedLoadSize).get()
.addOnCompleteListener(new OnLoadCompleteListener() {
@Override
protected void onSuccess(QuerySnapshot snapshots) {
getLastDocument(snapshots);
// I'm able to get the values here
List<Message> m = snapshots.toObjects(Message.class);
for (Message message : m) {
Log.d(TAG, "onSuccess() returned: " + message.getTitle());
}
callback.onResult(snapshots.toObjects(Message.class));
}
@Override
protected void onError(Exception e) {
Log.w(TAG, "loadInitial onError: " + e);
}
});
}
@Override
public void loadAfter(@NonNull LoadParams<Query> params, @NonNull LoadCallback<Message> callback) {
Log.d(TAG, "LoadingState: loading");
mLoadStateObserver.postValue(LoadingState.LOADING);
params.key.limit(params.requestedLoadSize).get()
.addOnCompleteListener(new OnLoadCompleteListener() {
@Override
protected void onSuccess(QuerySnapshot snapshots) {
getLastDocument(snapshots);
callback.onResult(snapshots.toObjects(Message.class));
}
@Override
protected void onError(Exception e) {
Log.w(TAG, "loadAfter onError: " + e);
}
});
}
private void getLastDocument(QuerySnapshot queryDocumentSnapshots) {
int lastDocumentPosition = queryDocumentSnapshots.size() - 1;
if (lastDocumentPosition >= 0) {
mLastDocument = queryDocumentSnapshots.getDocuments().get(lastDocumentPosition);
}
}
@Override
public void loadBefore(@NonNull LoadParams<Query> params, @NonNull LoadCallback<Message> callback) {}
@NonNull
@Override
public Query getKey(@NonNull Message item) {
return mQuery.startAfter(mLastDocument);
}
/*
* Public Getters
*/
public LiveData<LoadingState> getLoadState() {
return mLoadStateObserver;
}
/* Factory Class */
public static class Factory extends DataSource.Factory<Query, Message> {
private final Query mQuery;
private MutableLiveData<MessageDataSource> mSourceLiveData = new MutableLiveData<>();
public Factory(Query query) {
mQuery = query;
}
@Override
public DataSource<Query, Message> create() {
MessageDataSource itemKeyedDataSource = new MessageDataSource(mQuery);
mSourceLiveData.postValue(itemKeyedDataSource);
return itemKeyedDataSource;
}
public LiveData<MessageDataSource> getSourceLiveData() {
return mSourceLiveData;
}
}
}
然后在 MessageViewModel
class 的构造函数中:
MessageViewModel() {
//... Init collections and query
// Init Paging
MessageDataSource.Factory mFactory = new MessageDataSource.Factory(query);
PagedList.Config config = new PagedList.Config.Builder()
.setPrefetchDistance(10)
.setPageSize(10)
.setEnablePlaceholders(false)
.build();
// Build Observables
mMessageObservable = new LivePagedListBuilder<>(mFactory, config)
.build();
mLoadStateObservable = Transformations.switchMap(mMessageObservable, pagedListInput -> {
// No result here
Log.d(TAG, "MessageViewModel: " + mMessageObservable.getValue());
MessageDataSource dataSource = (MessageDataSource) pagedListInput.getDataSource();
return dataSource.getLoadState();
});
}
注意情况:
当我在 MainActivity#oncreate
方法中初始化视图模型并观察它时,它按预期工作并且能够在 recyclerview 中查看它。
后来我决定创建一个 Fragment 并通过将所有逻辑移动到 Fragment 来重构它,当我尝试观察相同的实时数据时,没有返回任何值。这是我的做法。
片段内:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...
mViewModel = ViewModelProviders.of(getActivity()).get(MessageViewModel.class);
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//...
mViewModel.getMessageObserver().observe(this, messages -> {
Log.d(TAG, "onCreateView() returned: " + messages.size());
});
mViewModel.getLoadingStateObserver().observe(this, loadingState -> {
Log.d(TAG, "onCreateView() returned: " + loadingState.name());
});
return view;
}
有趣的部分:
- 在片段中,
loadstate
返回值 LOADING
和 SUCCESS
- 在
MessageDataSource
内,成功返回了查询值,但在 Fragment 中观察到相同值时,我没有得到任何值。
我做错了什么?
P.S:我在学习Android。
片段可能会出现一些问题。在 onActivityCreated() 中设置观察者以确保创建视图并将观察语句中的 'this' 更改为 'getViewLifecycleOwner()'。例如,这可以防止观察者在片段从后台弹出后多次触发。你可以阅读它 here。
因此,将您的观察者更改为:
mViewModel.getLoadingStateObserver().observe(getViewLifecycleOwner(), loadingState -> {
Log.d(TAG, "onCreateView() returned: " + loadingState.name());
});
Share data between fragments 上显示的示例代码是最小的,只是看着它我得到了错误的概述,直到我非常仔细地阅读了这部分:
These fragments can share a ViewModel using their activity scope to
handle this communication, as illustrated by the following sample
code:
所以基本上你必须在 Activity
中初始化视图模型:ViewModelProviders.of(this).get(SomeViewModel.class);
然后在 Activity 的片段上,您可以将其初始化为:
mViewModel = ViewModelProviders.of(getActivity()).get(SomeViewModel.class);
mViewModel.someMethod().observe(this, ref -> {
// do things
});
这是我做错的地方,现在已经修复了。
我正在使用 Firestore 并使用 ItemKeyedDataSource
成功地将它与 Paging Library 集成。这是一个要点:
public class MessageDataSource extends ItemKeyedDataSource<Query, Message> {
//... private members
MessageDataSource(Query query) {
mQuery = query;
}
@Override
public void loadInitial(@NonNull LoadInitialParams<Query> params, @NonNull LoadInitialCallback<Message> callback) {
mLoadStateObserver.postValue(LoadingState.LOADING);
mQuery.limit(params.requestedLoadSize).get()
.addOnCompleteListener(new OnLoadCompleteListener() {
@Override
protected void onSuccess(QuerySnapshot snapshots) {
getLastDocument(snapshots);
// I'm able to get the values here
List<Message> m = snapshots.toObjects(Message.class);
for (Message message : m) {
Log.d(TAG, "onSuccess() returned: " + message.getTitle());
}
callback.onResult(snapshots.toObjects(Message.class));
}
@Override
protected void onError(Exception e) {
Log.w(TAG, "loadInitial onError: " + e);
}
});
}
@Override
public void loadAfter(@NonNull LoadParams<Query> params, @NonNull LoadCallback<Message> callback) {
Log.d(TAG, "LoadingState: loading");
mLoadStateObserver.postValue(LoadingState.LOADING);
params.key.limit(params.requestedLoadSize).get()
.addOnCompleteListener(new OnLoadCompleteListener() {
@Override
protected void onSuccess(QuerySnapshot snapshots) {
getLastDocument(snapshots);
callback.onResult(snapshots.toObjects(Message.class));
}
@Override
protected void onError(Exception e) {
Log.w(TAG, "loadAfter onError: " + e);
}
});
}
private void getLastDocument(QuerySnapshot queryDocumentSnapshots) {
int lastDocumentPosition = queryDocumentSnapshots.size() - 1;
if (lastDocumentPosition >= 0) {
mLastDocument = queryDocumentSnapshots.getDocuments().get(lastDocumentPosition);
}
}
@Override
public void loadBefore(@NonNull LoadParams<Query> params, @NonNull LoadCallback<Message> callback) {}
@NonNull
@Override
public Query getKey(@NonNull Message item) {
return mQuery.startAfter(mLastDocument);
}
/*
* Public Getters
*/
public LiveData<LoadingState> getLoadState() {
return mLoadStateObserver;
}
/* Factory Class */
public static class Factory extends DataSource.Factory<Query, Message> {
private final Query mQuery;
private MutableLiveData<MessageDataSource> mSourceLiveData = new MutableLiveData<>();
public Factory(Query query) {
mQuery = query;
}
@Override
public DataSource<Query, Message> create() {
MessageDataSource itemKeyedDataSource = new MessageDataSource(mQuery);
mSourceLiveData.postValue(itemKeyedDataSource);
return itemKeyedDataSource;
}
public LiveData<MessageDataSource> getSourceLiveData() {
return mSourceLiveData;
}
}
}
然后在 MessageViewModel
class 的构造函数中:
MessageViewModel() {
//... Init collections and query
// Init Paging
MessageDataSource.Factory mFactory = new MessageDataSource.Factory(query);
PagedList.Config config = new PagedList.Config.Builder()
.setPrefetchDistance(10)
.setPageSize(10)
.setEnablePlaceholders(false)
.build();
// Build Observables
mMessageObservable = new LivePagedListBuilder<>(mFactory, config)
.build();
mLoadStateObservable = Transformations.switchMap(mMessageObservable, pagedListInput -> {
// No result here
Log.d(TAG, "MessageViewModel: " + mMessageObservable.getValue());
MessageDataSource dataSource = (MessageDataSource) pagedListInput.getDataSource();
return dataSource.getLoadState();
});
}
注意情况:
当我在
MainActivity#oncreate
方法中初始化视图模型并观察它时,它按预期工作并且能够在 recyclerview 中查看它。后来我决定创建一个 Fragment 并通过将所有逻辑移动到 Fragment 来重构它,当我尝试观察相同的实时数据时,没有返回任何值。这是我的做法。
片段内:
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// ...
mViewModel = ViewModelProviders.of(getActivity()).get(MessageViewModel.class);
}
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
//...
mViewModel.getMessageObserver().observe(this, messages -> {
Log.d(TAG, "onCreateView() returned: " + messages.size());
});
mViewModel.getLoadingStateObserver().observe(this, loadingState -> {
Log.d(TAG, "onCreateView() returned: " + loadingState.name());
});
return view;
}
有趣的部分:
- 在片段中,
loadstate
返回值LOADING
和SUCCESS
- 在
MessageDataSource
内,成功返回了查询值,但在 Fragment 中观察到相同值时,我没有得到任何值。
我做错了什么?
P.S:我在学习Android。
片段可能会出现一些问题。在 onActivityCreated() 中设置观察者以确保创建视图并将观察语句中的 'this' 更改为 'getViewLifecycleOwner()'。例如,这可以防止观察者在片段从后台弹出后多次触发。你可以阅读它 here。 因此,将您的观察者更改为:
mViewModel.getLoadingStateObserver().observe(getViewLifecycleOwner(), loadingState -> {
Log.d(TAG, "onCreateView() returned: " + loadingState.name());
});
Share data between fragments 上显示的示例代码是最小的,只是看着它我得到了错误的概述,直到我非常仔细地阅读了这部分:
These fragments can share a ViewModel using their activity scope to handle this communication, as illustrated by the following sample code:
所以基本上你必须在 Activity
中初始化视图模型:ViewModelProviders.of(this).get(SomeViewModel.class);
然后在 Activity 的片段上,您可以将其初始化为:
mViewModel = ViewModelProviders.of(getActivity()).get(SomeViewModel.class);
mViewModel.someMethod().observe(this, ref -> {
// do things
});
这是我做错的地方,现在已经修复了。