java.lang.IllegalArgumentException:这个源已经添加了不同的观察者

cr0*_*9xx 8 java android mvvm android-livedata android-architecture-components

任何人都可以为我正确解释这个表达......这似乎是我目前面临的问题。

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);
        });
    }
}
Run Code Online (Sandbox Code Playgroud)

在活动中,我有这个:

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 + "");
            });
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

一切都运行得很顺利,但是,当我离开此活动并返回时,应用程序因错误而崩溃:

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)
Run Code Online (Sandbox Code Playgroud)

我将非常感谢解释以及为什么我不断收到此错误。

谢谢

Dan*_* B. 8

您正在同一源上设置2 个MediatorLiveData观察者。

只能为每个 source 设置 1 个观察者,否则IllegalStateException会抛出一个异常,就像您的情况一样。

将您的observe方法从onResume()移至onCreate()

当您将 Activity 置于后台时,ViewModel 不会被破坏。它仍在内存中,等待 Activity 返回前台。只有当活动完全关闭时它才会被销毁。

如果您想停止观察特定来源,只需使用removeSource().

如果您想再次开始观察源,请使用addSource()