java.lang.IllegalArgumentException: этот источник уже был добавлен с другим наблюдателем - PullRequest
0 голосов
/ 06 января 2019

Может ли кто-нибудь объяснить, пожалуйста, правильно это выражение для меня ... Кажется, это проблема, с которой я сталкиваюсь в настоящее время.

MediatorLiveData#addSource

Начинает прослушивать данный источник LiveData, при изменении значения источника будет вызван onChanged наблюдатель.

onChanged обратный вызов будет вызываться только тогда, когда эта MediatorLiveData активна.

Если данные LiveData уже добавлены в качестве источника, но с другим наблюдателем, будет выдано IllegalArgumentException.

В настоящее время в качестве моей ViewModel используется следующее (Called SplashViewModel)

package com.testapp.testapp.ui.splash;

import com.testapp.testapp.repository.HealthTipRepository;

import javax.inject.Inject;

import androidx.lifecycle.LiveData;
import androidx.lifecycle.MediatorLiveData;
import androidx.lifecycle.ViewModel;


public class SplashViewModel extends ViewModel {

    private final HealthTipRepository healthTipRepository;

    // Load Status will be used to fill up the progress bar inside the Activity
    private final MediatorLiveData<Integer> loadStatus = new MediatorLiveData<>();

    @Inject
    SplashViewModel(HealthTipRepository healthTipRepository) {
        this.healthTipRepository = healthTipRepository;
    }

    LiveData<Integer> observeLoadStatus() {
        loadStatus.addSource(healthTipRepository.createHealthTips(), healthTips -> {
            int currentValue = loadStatus.getValue();
            int newValue = currentValue != null ? currentValue + 25 : 25;
            loadStatus.setValue(newValue);
        });
    }
}

В активности у меня это:

package com.testapp.testapp.ui.splash;

import android.Manifest;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.location.LocationManager;
import android.os.Bundle;
import android.provider.Settings;
import android.view.View;
import android.widget.ProgressBar;

import com.testapp.testapp.R;
import com.testapp.testapp.storage.PrefManager;
import com.testapp.testapp.ui.BaseActivity;
import com.testapp.testapp.ui.FactoryViewModel;

import javax.inject.Inject;

import androidx.annotation.Nullable;
import androidx.lifecycle.ViewModelProviders;
import butterknife.BindView;

// Base Activity has already injected the Dagger component
public class SplashActivity extends BaseActivity {

    @BindView(R.id.splash_progress)
    ProgressBar progressBar;

    @Inject
    FactoryViewModel factoryViewModel;
    private SplashViewModel viewModel;

    // PrefManager is responsible for managing shared preferences. It exposes a .get Method
    @Inject
    PrefManager prefManager;

    @Override
    protected void onCreate(@Nullable Bundle savedInstance) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.splash_activity);

        ButterKnife.bind(this);

        viewModel = ViewModelProviders.of(this, factoryViewModel).get(SplashViewModel.class);
    }

    @Override
    protected void onResume() {
        super.onResume();

        // Performs checks to turn on location. The viewmodel is placed in the
        // onREsume to ensure that even when we leave the activity to turn on the
        // location and return, we can always start the viewmodel
        boolean turnedOnLocation = false;
        if (!turnedOnLocation) {
            startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS));
        }

        boolean appSetup = prefManager.get("app_setup", false);
        if (!appSetup) {
            viewModel.observeLoadStatus().observe(this, status -> {
                progressBar.setProgress(status + "");
            });
        }
    }
}

Все работает так же гладко, однако, когда я покидаю это действие и возвращаюсь, приложение вылетает с ошибкой:

Process: com.testapp.testapp, PID: 29865
java.lang.RuntimeException: Unable to resume activity {com.testapp.testapp/com.testapp.testapp.ui.splash.SplashActivity}: java.lang.IllegalArgumentException: This source was already added with the different observer
    at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3609)
    at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3649)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1663)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:164)
    at android.app.ActivityThread.main(ActivityThread.java:6524)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:438)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:888)
 Caused by: java.lang.IllegalArgumentException: This source was already added with the different observer
    at androidx.lifecycle.MediatorLiveData.addSource(MediatorLiveData.java:89)
    at com.testapp.testapp.ui.splash.SplashViewModel.fetchSensorLocations(SplashViewModel.java:25)
    at com.testapp.testapp.ui.splash.SplashViewModel.observeLoadStatus(SplashViewModel.java:17)
    at com.testapp.testapp.ui.splash.SplashActivity.observeViewModels(SplashActivity.java:121)
    at com.testapp.testapp.ui.splash.SplashActivity.onResume(SplashActivity.java:77)
    at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1355)
    at android.app.Activity.performResume(Activity.java:7138)

Я буду очень признателен за объяснение и почему я продолжаю получать эту ошибку.

Спасибо

Ответы [ 2 ]

0 голосов
/ 17 января 2019

1.) Вы вообще НЕ ДОЛЖНЫ использовать onResume, если только вы не работаете с камерой.

Но если вы это сделаете, то вам следует использовать observeForever и removeObserver вместо .observe(LifecycleOwner.

2.) Это

   // Load Status will be used to fill up the progress bar inside the Activity
    private final MediatorLiveData<Integer> loadStatus = new MediatorLiveData<>();

    @Inject
    SplashViewModel(HealthTipRepository healthTipRepository) {
        this.healthTipRepository = healthTipRepository;
    }

    LiveData<Integer> observeLoadStatus() {
        loadStatus.addSource(healthTipRepository.createHealthTips(), healthTips -> {
            int currentValue = loadStatus.getValue();
            int newValue = currentValue != null ? currentValue + 25 : 25;
            loadStatus.setValue(newValue);
        });
    }
}

должно быть

   // Load Status will be used to fill up the progress bar inside the Activity
    private final MediatorLiveData<Integer> loadStatus = new MediatorLiveData<>();

    {
        loadStatus.addSource(healthTipRepository.createHealthTips(), healthTips -> {
            int currentValue = loadStatus.getValue();
            int newValue = currentValue != null ? currentValue + 25 : 25;
            loadStatus.setValue(newValue);
        });
    }

    @Inject
    SplashViewModel(HealthTipRepository healthTipRepository) {
        this.healthTipRepository = healthTipRepository;
    }

    // LiveData<Integer> observeLoadStatus() {
    // 
    // }
}
0 голосов
/ 06 января 2019

Вы настраиваете 2 наблюдателей на одном и том же источнике MediatorLiveData.

Вы можете установить только 1 наблюдателя на источник , в противном случае выдается IllegalStateException, как в вашем случае.

Переместите ваш метод observe с onResume() на onCreate().

ViewModel не разрушается, когда вы помещаете свою деятельность в фоновый режим. Он все еще в памяти, ожидая, когда активность вернется на передний план. Уничтожается только тогда, когда действие полностью закрыто.

Если вы хотите остановить наблюдение определенного источника, просто используйте removeSource().

Если вы хотите начать , снова наблюдая источник, используйте addSource().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...