【问题标题】:Not getting LiveData observable values within Fragments (ItemKeyedDataSource)没有在 Fragments (ItemKeyedDataSource) 中获取 LiveData 可观察值
【发布时间】:2019-01-24 01:56:02
【问题描述】:

我正在使用 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 来重构它,当我尝试观察相同的实时数据时,没有返回任何值。这是我的做法。

片段内:

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

有趣的部分:

  • 在 Fragment 中,loadstate 返回值 LOADINGSUCCESS
  • MessageDataSource 内,查询的值已成功返回,但在片段中观察到相同的值时,我没有得到任何值。

我在这里做错了什么?

P.S:我正在学习 Android。

【问题讨论】:

  • 使用 this 代替 getActivity()。所以你的代码看起来像 ==> mViewModel = ViewModelProviders.of(this).get(MessageViewModel.class);
  • 试过了,没用,另外,我需要这个,因为我将实现一个Listener 来与另一个片段通信。
  • @Rajarshi 如果你需要实时分页,this 是一种推荐的方式,你可以通过结合查询游标和limit()方法对查询进行分页.我还建议您看看这个 video 以便更好地理解。
  • @AlexMamo 但它不是实时的,我得到了预期的结果,请参阅loadInitial 方法。唯一的问题是,虽然我可以在 Activity 中获得结果,但我不能在片段中做同样的事情。在 Fragment 中,不返回 PagedList of Messages 而返回网络状态,很奇怪。而且我不太擅长调试这个,:(。

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


【解决方案1】:

Share data between fragments 上显示的示例代码非常简单,只是看着它我得到了错误的概述,直到我仔细阅读了这部分:

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

所以基本上你必须在Activity:ViewModelProviders.of(this).get(SomeViewModel.class);中初始化viewmodel

然后在 Activity 的片段上你可以将其初始化为:

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

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

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

【讨论】:

    【解决方案2】:

    片段可能会出现一些问题。在 onActivityCreated() 中设置观察者以确保创建视图并将观察语句中的“this”更改为“getViewLifecycleOwner()”。例如,这可以防止观察者在片段被弹出回栈后多次触发。你可以阅读它here。 因此,将您的观察者更改为:

    mViewModel.getLoadingStateObserver().observe(getViewLifecycleOwner(), loadingState -> {
        Log.d(TAG, "onCreateView() returned: " + loadingState.name());
    });
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-23
      相关资源
      最近更新 更多