Reputation: 1943
After a failure, if a user writes correct username and password then it should both download files and open the Main Activity. However, in this case, my app crashes. If the user correctly writes username and password at first try, the app runs smoothly.
I have 3 different LiveData objects so that I can observe all of them with the help of MediatorLiveData
and call the next one according to condition. The error output:
E/AndroidRuntime: FATAL EXCEPTION: main Process: com.cesar.sertificar, PID: 7482 java.lang.IllegalArgumentException: This source was already added with the different observer at android.arch.lifecycle.MediatorLiveData.addSource(MediatorLiveData.java:89) at com.cesar.sertificar.ui.activity.login.LoginViewModel.handleFirstRunProcess(LoginViewModel.java:101) at com.cesar.sertificar.ui.activity.login.LoginActivity.doLogin(LoginActivity.java:68) at com.cesar.sertificar.ui.activity.login.LoginActivity.onClick(LoginActivity.java:88) at android.view.View.performClick(View.java:5214) at android.view.View$PerformClick.run(View.java:20978) at android.os.Handler.handleCallback(Handler.java:739) at android.os.Handler.dispatchMessage(Handler.java:95) at android.os.Looper.loop(Looper.java:145) at android.app.ActivityThread.main(ActivityThread.java:6134) at java.lang.reflect.Method.invoke(Native Method) at java.lang.reflect.Method.invoke(Method.java:372) at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1399) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1194)
LoginViewModel.class
void handleFirstRunProcess() {
mIsNetworkAvailable.setValue(isAnActiveConnection());
mProcessResult.addSource(mIsNetworkAvailable, isNetworkAvailable -> {
mProcessResult.removeSource(mIsNetworkAvailable);
if (isNetworkAvailable == null) return;
if (!isNetworkAvailable) {
mProcessResult.setValue(new NetworkState(NetworkState.Status.FAILED,
getApplication().getString(R.string.first_run_network_warning)));
return;
}
doLogin(); //First doLogin
});
mProcessResult.addSource(mIsLoginSuccessful, isLoginSuccessful -> {
mProcessResult.removeSource(mIsLoginSuccessful);
if (isLoginSuccessful == null) return;
if (isLoginSuccessful.getStatus() == NetworkState.Status.FAILED) {
mProcessResult.setValue(new NetworkState(NetworkState.Status.FAILED,
getApplication().getString(R.string.login_error)));
return;
}
if (preferenceUtil.getBooleanData(Constants.FIRST_RUN_KEY, true)) {
downloadEmptyRecipientForm(); //Second download form if first run
} else {
mProcessResult.setValue(NetworkState.LOADED); //Open an activity
}
});
mProcessResult.addSource(mIsFormDownloadingSuccessful, isFormDownloaded -> {
mProcessResult.removeSource(mIsFormDownloadingSuccessful);
if (isFormDownloaded == null) {
return;
}
if (isFormDownloaded.getStatus() == NetworkState.Status.FAILED) {
mProcessResult.setValue(new NetworkState(NetworkState.Status.FAILED,
getApplication().getString(R.string.first_run_empty_form_error)));
return;
}
mProcessResult.setValue(NetworkState.LOADED); //Third open an activity
preferenceUtil.putBooleanData(Constants.FIRST_RUN_KEY, false);
});
}
Upvotes: 1
Views: 1860
Reputation: 5324
I faced the same issue in my ViewModel. Seems like it is an inner limitation of MediatorLiveData. If it sees that the same type of LiveData is added, it wants to have the same listener to work with it. I will just add my case as it was with the same type of error and after (no error, works fine). Code with error:
networkSum = new MediatorLiveData<>();
networkSum.addSource(firstData, integer -> {
if (integer == null) {
firstIsFinished = false;
errorInFirst = false;
} else if (integer == SupportNetworkFunctions.STATUS_IN_PROGRESS) {
networkSum.postValue(integer);
firstIsFinished = false;
} else if (integer == SupportNetworkFunctions.STATUS_FINISHED_WITH_ERROR) {
firstIsFinished = true;
errorInFirst = true;
calculateFinished();
} else {
firstIsFinished = false;
errorInFirst = false;
calculateFinished();
}
});
networkSum.addSource(secondData, integer -> {
if (integer == null) {
secondIsFinished = false;
errorInSecond = false;
} else if (integer == SupportNetworkFunctions.STATUS_IN_PROGRESS) {
networkSum.postValue(integer);
secondIsFinished = false;
} else if (integer == SupportNetworkFunctions.STATUS_FINISHED_WITH_ERROR) {
secondIsFinished = true;
errorInSecond = true;
calculateFinished();
} else {
secondIsFinished = false;
errorInSecond = false;
calculateFinished();
}
});
After the refactoring:
networkSum = new MediatorLiveData<>();
Observer<Integer> statusObserver = new Observer<Integer>() {
@Override
public void onChanged(@Nullable Integer integer) {
if (integer != null) {
if (integer == SupportNetworkFunctions.STATUS_IN_PROGRESS) {
networkSum.postValue(integer);
} else if (integer == SupportNetworkFunctions.STATUS_FINISHED_WITH_ERROR) {
finishedItems++;
errorAppeared = true;
calculateFinished();
} else {
finishedItems++;
calculateFinished();
}
}
}
};
networkSum.addSource(firstData, statusObserver);
networkSum.addSource(secondData, statusObserver);
Upvotes: 1