I'm using Android Architecture Components
in my App. In My Login Activty, I'm showing a Dialog when the login is failed!
Due to Live Data, the dialog has been showing over 3 times. I added some logs & discovered that the livedata
is called multiple times.
How can I Fix this Issue ?
ACTIVITY
mViewModel.authenticate(token, binding.inputPassword.getText().toString()).observe(LoginActivity.this, apiResponse -> {
progress.dismiss();
if (apiResponse != null) {
if (apiResponse.getError() != null) {
Log.e("Login", "Network Failure");
} else {
if (apiResponse.getAuthuser().getStatus().equals("VALID")) {
PrefUtils.saveUserToPrefs(LoginActivity.this, apiResponse.getAuthuser());
finish();
} else if (apiResponse.getAuthuser().getStatus().equals("INVALID")) {
Log.e("LOGIN Issue ", "Showing Dialog" + apiResponse.getAuthuser().getStatus());
loginFailure();
}
}
}
});
ViewModel
class LoginActivityViewModel extends ViewModel {
private final FarmerRepository farmerRepository;
private MediatorLiveData<ApiResponse> mApiResponse;
LoginActivityViewModel(FarmerRepository repository) {
mApiResponse = new MediatorLiveData<>();
farmerRepository = repository;
}
MediatorLiveData<ApiResponse> authenticate(String encryptedMobile, String pwd) {
mApiResponse.addSource(
farmerRepository.authenticate(encryptedMobile, pwd),
apiResponse -> mApiResponse.setValue(apiResponse)
);
return mApiResponse;
}
}
LOGCAT
11-01 00:13:31.265 24386-24386 E/LOGIN Issue: Showing DialogINVALID
11-01 00:13:31.312 24386-24386 E/LOGIN Issue: Showing DialogINVALID
11-01 00:13:37.034 24386-24386 E/LOGIN Issue: Showing DialogINVALID
11-01 00:13:38.196 24386-24386 E/LOGIN Issue: Showing DialogINVALID
11-01 00:13:38.234 24386-24386 E/LOGIN Issue: Showing DialogINVALID
11-01 00:13:38.273 24386-24386 E/LOGIN Issue: Showing DialogINVALID
UPDATE
After using SingleLiveEvent. It is not being observed. Can you tell me what is wrong with the code ?
Updated ViewModel
class LoginActivityViewModel extends ViewModel {
private final FarmerRepository farmerRepository;
private MediatorLiveData<ApiResponse> mApiResponse;
private SingleLiveEvent<ApiResponse> mMsgUpdate;
LoginActivityViewModel(FarmerRepository repository) {
mApiResponse = new MediatorLiveData<>();
farmerRepository = repository;
mMsgUpdate = new SingleLiveEvent<>();
}
SingleLiveEvent<ApiResponse> authenticate(String encryptedMobile, String pwd) {
mApiResponse.addSource(
farmerRepository.authenticate(encryptedMobile, pwd),
apiResponse -> mMsgUpdate.setValue(apiResponse)
);
return mMsgUpdate;
}
}
You should manually call removeObserver(Observer) to stop observing this LiveData. While LiveData has one of such observers, it will be considered as active. If the observer was already added with an owner to this LiveData, LiveData throws an IllegalArgumentException .
Since we are using switchmap in viewmodel and the livedata was set again the observer in fragment A was getting triggered twice. To fix this all i had to do was check if livedata had the same value that is being set now to avoid making network calls and triggering livedata in fragment A twice.
LiveData overview Part of Android Jetpack. LiveData is an observable data holder class. Unlike a regular observable, LiveData is lifecycle-aware, meaning it respects the lifecycle of other app components, such as activities, fragments, or services.
The role of the ViewModel is to represent the current state of the view. LiveData adds the ability to observe state changes. You are treating your LiveData object as a way to carry the response back upon a call to authenticate. Instead, your authenticate method should simply take the credentials as parameters, decide whether or not to log the person in, and if you do, update the LiveData ViewModel to reflect that the person is logged in, then observers will get this and most likely dismiss this view and show whatever other parts of the authenticated state you want to show (e.g. LoggedInUsername).
So in summary:
That's one way. Because a login screen is transient, observers of state updates may be seen as superfluous. But that's how the ViewModel/LiveData mechanism works.
My answer is not a solution to this question description but rather to question title. Just title.
Originally answered here
If your observer for a LiveData<*> is getting called multiple times then it means you are calling livedata.observe(...) multiple times. This happened to me as I was doing livedata.observe(...) in a method and was calling this method whenever user does some action thus observing liveData again. To solve this I moved livedata.observe(...) to onCreate() lifecycle method.
What was the scenario?
The App has a color swatch. When user selects a color I had to make API call to fetch Product Images for that color. So was making API call and was observing livedata in onColorChanged()
. When user selects a new color, onColorChanged()
would be called again thus observing for livedata changes again.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With