Android Architecture Singleliveevent And Eventobserver Practicle Example In Java
Solution 1:
Check out below example about how you can create single LiveEvent to observe only one time as LiveData
:
Create a class called Event
as below that will provide our data once and acts as child of LiveData
wrapper :
publicclassEvent<T> {
private boolean hasBeenHandled = false;
private T content;
publicEvent(T content) {
this.content = content;
}
public T getContentIfNotHandled() {
if (hasBeenHandled) {
returnnull;
} else {
hasBeenHandled = true;
return content;
}
}
public boolean isHandled() {
return hasBeenHandled;
}
}
Then declare this EventObserver
class like below so that we don't end up placing condition for checking about Event
handled every time, everywhere :
publicclassEventObserver<T> implementsObserver<Event<T>> {
private OnEventChanged onEventChanged;
publicEventObserver(OnEventChanged onEventChanged) {
this.onEventChanged = onEventChanged;
}
@OverridepublicvoidonChanged(@Nullable Event<T> tEvent) {
if (tEvent != null && tEvent.getContentIfNotHandled() != null && onEventChanged != null)
onEventChanged.onUnhandledContent(tEvent.getContentIfNotHandled());
}
interfaceOnEventChanged<T> {
voidonUnhandledContent(T data);
}
}
And How you can implement it :
MutableLiveData<Event<String>> data = newMutableLiveData<>();
// And observe like below
data.observe(lifecycleOwner, newEventObserver<String>(data -> {
// your unhandled data would be here for one time.
}));
// And this is how you add data as event to LiveData
data.setValue(newEvent(""));
Refer here for details.
Edit for O.P.:
Yes, data.setValue(new Event(""));
is meant for repository when you've got response from API(Remember to return same LiveData
type you've taken in VM instead of SingleLiveEvent
class though).
So, let's say you've created LiveData
in ViewModel
like below :
privateMutableLiveData<Event<String>> snackbarStringSingleLiveEvent= new MutableLiveData<>();
You provide value to this livedata as Single Event from repository like below :
@OverridepublicvoidonResponse(Call<GenericResponse> call, Response<GenericResponse> response) {
mutableLiveData.setValue(newEvent(response.body().getMessage())); // we set it as Event wrapper class.
}
And observe it on UI (Fragment) like below :
viewModel.getSnackbarStringSingleLiveEvent().observe(this, newEventObserver<String>(data -> {
// your unhandled data would be here for one time.
}));
Solution 2:
Event.java
publicclassEvent<T> {
private T content;
private boolean hasBeenHandled = false;
publicEvent(T content) {
this.content = content;
}
/**
* Returns the content and prevents its use again.
*/public T getContentIfNotHandled() {
if (hasBeenHandled) {
returnnull;
} else {
hasBeenHandled = true;
return content;
}
}
/**
* Returns the content, even if it's already been handled.
*/public T peekContent() {
return content;
}
}
EventObserver.java
publicclassEventObserver<T> implementsObserver<Event<? extendsT>> {
publicinterfaceEventUnhandledContent<T> {
voidonEventUnhandledContent(T t);
}
private EventUnhandledContent<T> content;
publicEventObserver(EventUnhandledContent<T> content) {
this.content = content;
}
@OverridepublicvoidonChanged(Event<? extends T> event) {
if (event != null) {
Tresult= event.getContentIfNotHandled();
if (result != null && content != null) {
content.onEventUnhandledContent(result);
}
}
}
}
Example, In ViewModel Class
publicclassLoginViewModelextendsBaseViewModel {
privateMutableLiveData<Event<Boolean>> _isProgressEnabled = newMutableLiveData<>();
LiveData<Event<Boolean>> isProgressEnabled = _isProgressEnabled;
privateAppService appService;
privateSchedulerProvider schedulerProvider;
privateSharedPreferences preferences;
@InjectLoginViewModel(
AppService appService,
SchedulerProvider schedulerProvider,
SharedPreferences preferences
) {
this.appService = appService;
this.schedulerProvider = schedulerProvider;
this.preferences = preferences;
}
publicvoidlogin(){
appService.login("username", "password")
.subscribeOn(schedulerProvider.executorIo())
.observeOn(schedulerProvider.ui())
.subscribe(_userLoginDetails::setValue,
_userLoginDetailsError::setValue,
() -> _isProgressEnabled.setValue(newEvent<>(false)),
d -> _isProgressEnabled.setValue(newEvent<>(true))
)
}
}
In Login Fragment,
viewModel.isProgressEnabled.observe(this, new EventObserver<>(hasEnabled -> {
if (hasEnabled) {
// showProgress
} else {
// hideProgress
}
}));
Using Event and EventObserver class we can achieve the same like SingleLiveEvent class but if you are thinking a lot of boilerplate code just avoid this method. I hope it would help you and give some idea about why we are using SingleEvent in LiveData.
Solution 3:
I understand that Google gives the guidelines to use LiveData between the ViewModel and UI but there are edge cases where using LiveData as a SingleLiveEvent is like reinventing the wheel. For single time messaging between the view model and user interface we can use the delegate design pattern. When initializing the view model in the activity we just have to set the activity as the implementer of the interface. Then throughout our view model we can call the delegate method.
Interface
publicinterfaceSnackable:
voidshowSnackbarMessage(String message);
UI
publicclassMyActivityextendsAppCompatActivityimplementsSnackable {
privateMyViewModel myViewModel;
@OverrideprotectedvoidonCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_layout);
this.myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
this.myViewModel.setListener(this);
}
@OverridepublicvoidshowSnackbarMessage(String message) {
Toast.makeText(this, "message", Toast.LENGTH_LONG).show();
}
}
View Model
publicclassMyViewModelextendsAndroidViewModel {
privateSnackable listener;
publicMyViewModel(@NonNullApplication application) {
super(application);
}
publicvoidsetListener(MyActivity activity){
this.listener = activity;
}
privatevoidsendSnackbarMessage(String message){
if(listener != null){
listener.showSnackbarMessage(message);
}
}
privatevoidanyFunctionInTheViewModel(){
sendSnackbarMessage("Hey I've got a message for the UI!");
}
}
Post a Comment for "Android Architecture Singleliveevent And Eventobserver Practicle Example In Java"