1
  • I work on a project that downloads some files if the login is successful and then opens Main Activity. If not so, it neither logins nor downloads files and prompts the user to login successfully to download the required files.
  • 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);
        });
    }
nuhkoca
  • 1,777
  • 4
  • 20
  • 44

1 Answers1

1

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);
Valentina Konyukhova
  • 4,464
  • 2
  • 24
  • 33