Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to handle error states with LiveData?

The new LiveData can be used as a replacement for RxJava's observables in some scenarios. However, unlike Observable, LiveData has no callback for errors.

My question is: How should I handle errors in LiveData, e.g. when it's backed by some network resource that can fail to be retrieved due to an IOException?

like image 631
Kirill Rakhman Avatar asked May 26 '17 19:05

Kirill Rakhman


People also ask

Is LiveData deprecated?

This function is deprecated. This extension method is not required when using Kotlin 1.4.

What is the difference between LiveData and RxJava?

The RxJava's approach to choose a thread during the subscription, not in time of the sending is much more appropriate. Actually the only advantage of LiveData over RxJava we have noticed is they automatically subscribe and unsubscribe on Activity life cycle events (or over android components implementing life cycle).

What is the use of MutableLiveData?

MutableLiveData is commonly used since it provides the postValue() , setValue() methods publicly, something that LiveData class doesn't provide. LiveData/MutableLiveData is commonly used in updating data in a RecyclerView from a collection type(List, ArrayList etc).


2 Answers

In one of Google's sample apps for Android Architecture Components they wrap the LiveData emitted object in a class that can contain a status, data, and message for the emitted object.

https://github.com/googlesamples/android-architecture-components/blob/master/GithubBrowserSample/app/src/main/java/com/android/example/github/vo/Resource.kt

With this approach you can use the status to determine if there was an error.

like image 112
Chris Cook Avatar answered Sep 25 '22 12:09

Chris Cook


You can extend from MutableLiveData and create a holder Model to wrap your data.

This is your Wrapper Model

public class StateData<T> {      @NonNull     private DataStatus status;      @Nullable     private T data;      @Nullable     private Throwable error;      public StateData() {         this.status = DataStatus.CREATED;         this.data = null;         this.error = null;     }      public StateData<T> loading() {         this.status = DataStatus.LOADING;         this.data = null;         this.error = null;         return this;     }      public StateData<T> success(@NonNull T data) {         this.status = DataStatus.SUCCESS;         this.data = data;         this.error = null;         return this;     }      public StateData<T> error(@NonNull Throwable error) {         this.status = DataStatus.ERROR;         this.data = null;         this.error = error;         return this;     }      public StateData<T> complete() {         this.status = DataStatus.COMPLETE;         return this;     }      @NonNull     public DataStatus getStatus() {         return status;     }      @Nullable     public T getData() {         return data;     }      @Nullable     public Throwable getError() {         return error;     }      public enum DataStatus {         CREATED,         SUCCESS,         ERROR,         LOADING,         COMPLETE     } } 

This is your extended LiveData Object

public class StateLiveData<T> extends MutableLiveData<StateData<T>> {      /**      * Use this to put the Data on a LOADING Status      */     public void postLoading() {         postValue(new StateData<T>().loading());     }      /**      * Use this to put the Data on a ERROR DataStatus      * @param throwable the error to be handled      */     public void postError(Throwable throwable) {         postValue(new StateData<T>().error(throwable));     }      /**      * Use this to put the Data on a SUCCESS DataStatus      * @param data      */     public void postSuccess(T data) {         postValue(new StateData<T>().success(data));     }      /**      * Use this to put the Data on a COMPLETE DataStatus      */     public void postComplete() {         postValue(new StateData<T>().complete());     }  } 

And this is how you use it

StateLiveData<List<Book>> bookListLiveData; bookListLiveData.postLoading(); bookListLiveData.postSuccess(books); bookListLiveData.postError(e); 

And how it can be observed:

private void observeBooks() {         viewModel.getBookList().observe(this, this::handleBooks);     }        private void handleBooks(@NonNull StateData<List<Book>> books) {       switch (books.getStatus()) {             case SUCCESS:                 List<Book> bookList = books.getData();                 //TODO: Do something with your book data                 break;             case ERROR:                 Throwable e = books.getError();                 //TODO: Do something with your error                 break;             case LOADING:                 //TODO: Do Loading stuff                 break;             case COMPLETE:                 //TODO: Do complete stuff if necessary                 break;         }     } 
like image 33
Eliel Martinez Avatar answered Sep 24 '22 12:09

Eliel Martinez