Может ли кто-нибудь правильно объяснить мне это выражение ... Кажется, это проблема, с которой я столкнулся в настоящее время.
Starts to listen the given source LiveData, onChanged observer will be called when source value was changed.
onChangedcallback will be called only when this MediatorLiveData is active.If the given LiveData is already added as a source but with a different Observer,
IllegalArgumentExceptionwill be thrown.
В настоящее время у меня в качестве модели 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)
Я буду очень признателен за объяснение, почему я продолжаю получать эту ошибку.
Спасибо




Вы настраиваете наблюдателей 2 на том же источнике MediatorLiveData.
Вы можно установить только 1 наблюдателя на источник, иначе выдается IllegalStateException, как и в вашем случае.
Переместите свой метод observe с onResume() на onCreate().
ViewModel не разрушается, когда вы переводите свою деятельность в фоновый режим. Он все еще находится в памяти, ожидая возврата активности на передний план. Он уничтожается только тогда, когда деятельность полностью закрывается.
Если вы хотите, чтобы останавливаться наблюдал за конкретным источником, просто используйте removeSource().
Если вы хотите, чтобы Начало снова наблюдал за источником, используйте addSource().
@ cr05s19xx использует void removeSource (LiveData<S> toRemote), чтобы прекратить наблюдение за источником MediatorLiveData. Проверьте, отключена ли локация, если есть, удалите ресурс.
Не могли бы вы уточнить? Используя мой пример? Могу ли я вызвать addSource и removeSource в ViewModel или в действии? Спасибо
@ cr05s19xx Вам необходимо хранить ваши объекты LiveData в ViewModel. Затем вам необходимо определить методы, которые позволят вам наблюдать и прекратить наблюдение, также внутри ViewModel. В вашей Activity, когда что-то происходит, и вы хотите прекратить наблюдение, вызовите метод, чтобы прекратить наблюдение из ViewModel. Когда вы будете готовы снова наблюдать, из Activity вызовите метод из ViewModel, который снова начнет наблюдение.
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() {
//
// }
}
Спасибо, @Daniel B. Моя причина размещения метода наблюдателя в onResume заключается в том, что я выполняю проверки, чтобы включить определение местоположения. Теперь, если пользователь оставляет действие на странице настроек, чтобы включить определение местоположения, он возвращается к методу
onResume. А еще хотелось бы понаблюдать за Только при включении локации. Я последую вашему совету, но можете ли вы предложить способ наблюдения только при включенной локации ...? Спасибо