如何使用LiveData处理错误状态?

Kir*_*man 56 android android-architecture-components

LiveData在某些情况下,new 可以用作RxJava可观察对象的替代品.但是,与之不同的是Observable,LiveData没有错误回调.

我的问题是:我应该如何处理错误LiveData,例如,当某些网络资源由于某个网络资源而无法检索时IOException

小智 43

在Google 针对Android架构组件示例应用程序中,他们将LiveData发出的对象包装在一个类中,该类可以包含发出的对象的状态,数据和消息.

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

使用此方法,您可以使用状态来确定是否存在错误.

  • 样本在kotlin中。在Java中有人吗? (2认同)

小智 19

您可以扩展MutableLiveData并创建一个持有人模型来包装您的数据。

这是你的包装模型

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
    }
}
Run Code Online (Sandbox Code Playgroud)

这是您扩展的LiveData对象

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());
    }

}
Run Code Online (Sandbox Code Playgroud)

这就是你的使用方式

StateLiveData<List<Book>> bookListLiveData;
bookListLiveData.postLoading();
bookListLiveData.postSuccess(books);
bookListLiveData.postError(e);
Run Code Online (Sandbox Code Playgroud)

以及如何观察它:

private void observeBooks() {
        viewModel.getBookList().observe(this, this::handleBooks);
    }

    private void handleBooks(@NonNull StateData<List<Book>> books) {
      switch (stepIds.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;
        }
    }
Run Code Online (Sandbox Code Playgroud)

  • 我无法从“StateLiveData”类中转换“LiveData” (2认同)

roy*_*oyB 16

使用某种错误消息传递从LiveData返回的数据

public class DataWrapper<T>T{
    private T data;
    private ErrorObject error; //or A message String, Or whatever
}
Run Code Online (Sandbox Code Playgroud)

//现在在你的LifecycleRegistryOwner课堂上

LiveData<DataWrapper<SomeObjectClass>> result = modelView.getResult();

result.observe(this, newData ->{
    if(newData.error != null){ //Can also have a Status Enum
        //Handle Error
    }
    else{
       //Handle data
    }

});
Run Code Online (Sandbox Code Playgroud)

只是抓住一个Exception或扔掉它.使用错误Object将此数据传递给UI.

MutableLiveData<DataWrapper<SomObject>> liveData = new...;

//On Exception catching:
liveData.set(new DataWrapper(null, new ErrorObject(e));
Run Code Online (Sandbox Code Playgroud)


Nik*_*ski 9

另一种方法是使用不同类型的MediatorLiveData来源LiveData.这将使您分离每个事件:

例如:

open class BaseViewModel : ViewModel() {
    private val errorLiveData: MutableLiveData<Throwable> = MutableLiveData()
    private val loadingStateLiveData: MutableLiveData<Int> = MutableLiveData()
    lateinit var errorObserver: Observer<Throwable>
    lateinit var loadingObserver: Observer<Int>
    fun <T> fromPublisher(publisher: Publisher<T>): MediatorLiveData<T> {
        val mainLiveData = MediatorLiveData<T>()
        mainLiveData.addSource(errorLiveData, errorObserver)
        mainLiveData.addSource(loadingStateLiveData, loadingObserver)
        publisher.subscribe(object : Subscriber<T> {

            override fun onSubscribe(s: Subscription) {
                s.request(java.lang.Long.MAX_VALUE)
                loadingStateLiveData.postValue(LoadingState.LOADING)
            }

            override fun onNext(t: T) {
                mainLiveData.postValue(t)
            }

            override fun onError(t: Throwable) {
                errorLiveData.postValue(t)
            }

            override fun onComplete() {
                loadingStateLiveData.postValue(LoadingState.NOT_LOADING)
            }
        })

        return mainLiveData 
    }

}
Run Code Online (Sandbox Code Playgroud)

在此示例中,LiveData一旦MediatorLiveData具有活动观察者,将开始观察加载和错误.