Компоненты архитектуры: Наблюдатель продолжает наблюдать даже после удаления его на onDestroy - PullRequest
0 голосов
/ 05 сентября 2018

Я разрабатываю приложение, в котором мне нужно каждые 30 секунд выполнять сетевой вызов, удалять предыдущие данные и вставлять новые. И каждый раз, когда новые данные вставляются, я показываю их в RecyclerView. Я использую Handler для сетевого вызова и LiveData для наблюдения за изменениями данных. Все просто отлично работает, просто Live Data обозреватель запускает несколько раз, поэтому данные удаляются и вставляются несколько раз, в результате обновляя 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);
}

Удаление наблюдателя на Дестрой:

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

Вот мой метод в ViewModel:

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

Repository:

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

DataSource:

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

Теперь проблема в том, что когда мой фрагмент уничтожен и воссоздан, Обозреватель запускается несколько раз, вот журналы:

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, почему это должно происходить? Любая помощь будет принята с благодарностью.

EDIT:

Я изменил свой код, чтобы проверить, являются ли LiveData и Observer нулевыми, а затем только инициализировал его. Но это не помогает, он все еще вызывается несколько раз.

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

Ответы [ 3 ]

0 голосов
/ 05 сентября 2018

Во-первых, если я правильно понимаю, вы используете RecyclerView и каждый фрагмент в этом RecyclerView называется setUpUserRecyclerView(); в его onCreate() методе. Итак, если у вас есть 3 фрагмента, у вас будет 3 наблюдателя. Если вы хотите, чтобы все они использовали ViewModel из Activity, вы должны указать родительское действие здесь -> ViewModelProviders.of(getActivity(), factory)

Во-вторых, почему вы используете observeForever в своем хранилище? Вы можете использовать только observe?

И последнее, если вы хотите запускать этот запрос каждые 30 секунд, почему бы вам не использовать PeriodicWorkRequest из WorkManager -> https://developer.android.com/topic/libraries/architecture/workmanager/basics#java

Надеюсь, я чем-нибудь помогу:)

0 голосов
/ 05 сентября 2018

Итак, что мы узнали из экспериментов в комментариях, вам нужно было проверить, наблюдается ли mTablesData уже перед его наблюдением, и наблюдать только, если оно не наблюдается, как

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

0 голосов
/ 05 сентября 2018

Я думаю, вам нужно обернуть mObserver в CompositeDisposable.

CompositeDisposable disposable = new CompositeDisposable();

disposable.add(mObserver);

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

Надеюсь, это поможет вам.

...