在片段(ItemKeyedDataSource)中未获取LiveData可观察的值

时间:2018-08-17 04:22:22

标签: android firebase android-fragments google-cloud-firestore android-livedata

我正在与Firestore合作,并使用ItemKeyedDataSource成功地将其与分页库集成在一起。这是要点:

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类的构造函数中:

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来对其进行重构,当我尝试观察相同的livedata时,不返回任何值。这是我的方法。

在片段内:

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返回值LOADINGSUCCESS
  • MessageDataSource中,查询的值已成功返回,但是在Fragment中观察到该值时,我没有任何值。

我在这里做什么错了?

P.S:我正在学习Android。

2 个答案:

答案 0 :(得分:0)

使用碎片可能会发生一些问题。在onActivityCreated()中设置了观察者,以确保创建视图并将观察语句中的“ this”更改为“ getViewLifecycleOwner()”。例如,这可以防止观察者在将片段从后堆栈弹出后多次触发。您可以阅读有关here的信息。 因此,将您的观察者更改为:

Activity

答案 1 :(得分:0)

Share data between fragments上显示的示例代码几乎是最少的,只是看了一下,我才得到了错误的概述,直到我非常仔细地阅读了这一部分:

  

这些片段可以使用其活动范围共享ViewModel   处理此通信,如以下示例所示   代码:

因此,基本上,您必须在Activity中初始化视图模型:ViewModelProviders.of(this).get(SomeViewModel.class);

然后在活动的片段上,可以将其初始化为:

mViewModel = ViewModelProviders.of(getActivity()).get(SomeViewModel.class);

mViewModel.someMethod().observe(this, ref -> {
   // do things
});

这是我做错的,现在已解决。