架构组件:即使在onDestroy上删除它之后,Observer也会继续观察

问题描述 投票:1回答:3

我正在开发一个应用程序,我需要每隔30秒进行一次网络调用,并删除以前的数据并插入新的数据。每次插入新数据时,我都会在RecyclerView中显示它。我正在使用Handler提供网络调用和LiveData来观察数据更改。一切正常,只有实时数据观察器触发多次,因此数据被删除并多次插入结果以频繁刷新RecyclerView,导致它每30秒闪烁一次。

以下是我尝试过的代码:

在我的片段中,我这样做:

private LiveData<List<RestaurantTablesModel>> mData;
private Observer<List<RestaurantTablesModel>> mObserver;
private TablesViewModel mViewModel;

 @Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // Inflate the layout for this fragment
    View mView = inflater.inflate(R.layout.fragment_tables, container, false);
    ButterKnife.bind(this, mView);

    TablesViewModelFactory factory = InjectorUtils.provideTablesFactory(getActivity());
    mViewModel = ViewModelProviders.of(this, factory).get(TablesViewModel.class);

    setUpUserRecyclerView();

    return mView;

}

private void setUpRecyclerView() {

  mData = mViewModel.getTablesData(mLocationID);

    mObserver = tablesModels -> {
        if (tablesModels != null) {
            mTablesRecyclerAdapter.addTables(tablesModels);
            Log.e(LOG_TAG, "setUpUserRecyclerView: tablesModels");
        }
    };

  mData.observe(this, mObserver);
}

删除观察者onDestroy:

@Override
public void onDestroy() {
   mData.removeObserver(mObserver);
   super.onDestroy();
}

以下是我在ViewModel中的方法:

public LiveData<List<TablesModel>> getTablesData(int mLocationID){
    return mRepository.getTablesData(mLocationID);
}

库:

public LiveData<List<TablesModel>> getTablesData(int mLocationID){

    LiveData<TablesModel[]> mTablesData = mDataSource.getTablesData();

    mTablesData.observeForever(tablesModels -> {
        mExecutors.diskIO().execute(() -> {

            //Completed: delete old table data if there are conflicts.

            if (tablesModels != null) {
                mDatabaseDao.deleteTables();

                mDatabaseDao.insertTablesData(tablesModels);
            }else {
                Log.e(LOG_TAG, "Nothing: ");
            }
        });
        Log.e("Handlers", "repository getTablesData");
    });

    return mDatabaseDao.getTablesData(mLocationID);
}

数据源:

private MutableLiveData<RestaurantTablesModel[]> mDownloadedTablesModel;

public LiveData<RestaurantTablesModel[]> getTablesData() {
    Log.e("Handlers", "getTablesData");
    fetchTablesData();
    return mDownloadedTablesModel;
}

public void fetchTablesData() {

    if (Utils.isNetworkAvailable(mContext)) {
        NetworkUtils.NetworkInterface mInterface = this;

        handler = new Handler();

        runnableCode = new Runnable() {

            @Override
            public void run() {
                // Do something here on the main thread
                Log.e("Handlers", "Called on network thread");

                URL getTablesURL = NetworkUtils.getAllTableUrl(mContext);

                NetworkUtils.getResponseFromAPI(mContext, getTablesURL, mInterface);

                // Repeat this the same runnable code block again another 30 seconds
                // 'this' is referencing the Runnable object
                handler.postDelayed(this, 30000);
            }
        };

        handler.post(runnableCode);

    } else {
        Log.d(LOG_TAG, "fetchTablesData: No network!");
    }
}

现在的问题是当我的片段被销毁并重新创建Observer被多次触发时,这里是日志:

09-05 10:28:29.853 3666-3666/? E/TablesFragment: setUpRecyclerView: tablesModels
09-05 10:28:30.039 3666-3666/? E/TablesFragment: setUpRecyclerView: tablesModels
09-05 10:28:30.607 3666-3666/? E/TablesFragment: setUpRecyclerView: tablesModels
09-05 10:28:30.657 3666-3666/? E/TablesFragment: setUpRecyclerView: tablesModels
09-05 10:28:30.669 3666-3666/? E/TablesFragment: setUpRecyclerView: tablesModels
09-05 10:28:30.704 3666-3666/? E/TablesFragment: setUpRecyclerView: tablesModels

并且它会比以前触发更多次,每次重新创建片段时,我认为观察者正在重新调用片段,并且观察者的前一个实例仍在播放中。

但是,如果我要删除OnDestroy中的观察者,为什么要这样呢?任何帮助将受到高度赞赏。

编辑:

我更改了代码以检查LiveData和Observer是否为null,然后仅初始化它。但它没有帮助,它仍然被多次调用。

if (mTablesData == null){
        mData = mViewModel.getTablesData(mLocationID);

        if (mObserver == null){
            mObserver = tablesModels -> {
                if (tablesModels != null) {
                    mTablesRecyclerAdapter.addTables(tablesModels);
                    Log.e(LOG_TAG, "setUpUserRecyclerView: tablesModels");
                }
            };

            mData.observe(this, mObserver);
        }

    }

编辑2:

试过这个,但也没有奏效:

   mTablesData = mViewModel.getTablesData(mLocationID);

    mObserver = tablesModels -> {
        if (tablesModels != null) {
            mTablesRecyclerAdapter.addTables(tablesModels);
            Log.e(LOG_TAG, "setUpRecyclerView: tablesModels");
        }
    };

    if (!mTablesData.hasObservers()) {
        mTablesData.observe(this, mObserver);
    }
android android-room android-handler android-architecture-components android-livedata
3个回答
1
投票

所以我们从评论中的实验中学到了什么,你需要在观察之前检查mTablesData是否已被观察到,并观察它是否仅被观察到,如

if (!mTablesData.hasObservers()) { mTablesData.observeForever(tablesModels -> { ...


1
投票

首先,如果我理解正确你使用RecyclerViewRecyclerView中的每个片段在setUpUserRecyclerView();方法中称为onCreate()。所以,如果你有3个碎片,你将有3个观察者。如果你想让他们所有人都使用ViewModelActivity你必须在这里指出父活动 - > ViewModelProviders.of(getActivity(), factory)

第二,为什么在存储库中使用observeForever?你能用observe吗?

最后如果你想每30秒运行一次这个请求,为什么不使用PeriodicWorkRequestWorkManager - > https://developer.android.com/topic/libraries/architecture/workmanager/basics#java

希望我能以某种方式帮助:)


0
投票

我认为你需要将mObserver包装在CompositeDisposable中。

CompositeDisposable disposable = new CompositeDisposable();

disposable.add(mObserver);

@Override
public void onDestroy() {
   mData.removeObserver(mObserver);
   disposable.clear();
   super.onDestroy();
}

我希望它对你有所帮助。

© www.soinside.com 2019 - 2024. All rights reserved.