簡體   English   中英

java.lang.IllegalArgumentException:這個源已經添加了不同的觀察者

[英]java.lang.IllegalArgumentException: This source was already added with the different observer

任何人都可以為我正確解釋這個表達......這似乎是我目前面臨的問題。

MediatorLiveData#addSource

開始偵聽給定的源 LiveData,當源值更改時將調用 onChanged 觀察者。

僅當此 MediatorLiveData 處於活動狀態時才會調用onChanged回調。

如果給定的 LiveData 已作為源添加但具有不同的觀察者,則將拋出IllegalArgumentException

我目前有以下作為我的 ViewModel(稱為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)

我將非常感謝解釋以及為什么我不斷收到此錯誤。

謝謝

您正在MediatorLiveData的同一源上設置2 個觀察者。

只能為每個 source 設置 1 個觀察者,否則會拋出IllegalStateException ,就像您的情況一樣。

將您的observe方法從onResume()onCreate()

當您將活動置於后台時,ViewModel 不會被破壞。 它仍在內存中,等待活動返回前台。 只有當活動完全關閉時它才會被銷毀。

如果您想停止觀察特定來源,只需使用removeSource()

如果您想再次開始觀察源,請使用addSource()

1.) 通常不應該使用onResume除非您正在使用相機。

但是如果你這樣做了,那么你應該使用observeForeverremoveObserver而不是.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() {
    // 
    // }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM