未在 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();
    });
}

注意情况:

片段内:

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;
}

有趣的部分:

我做错了什么?

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
});

这是我做错的地方,现在已经修复了。