Обработка исключений через mvvm android

Я использую архитектуру MVVM, чтобы поразить веб-службу путем модернизации в студии Android. Я обработал ответ службы в моем классе представления. Но проблема, с которой я столкнулся, заключается в том, как обрабатывать исключения и передавать их моему классу представления. Один из способов - создать конструктор в моем классе Bean и передать ему как ответ, так и ошибку, а также обновить пользовательский интерфейс. Но мне нужен более оптимизированный способ обработки исключений внутри пользовательского интерфейса.

Вот мой код репозитория:

final MutableLiveData<MyBeanClass> myBeanClass = new MutableLiveData<>();
   ApiInterface apiInterface = ApiClient.getClientAuthentication().create(ApiInterface.class);
    Call<MyBeanClass> call = apiInterface.getData(id);
    call.enqueue(new Callback<MyBeanClass>() {
        @Override
        public void onResponse(Call<MyBeanClass> call, Response<MyBeanClass> response) {
            if (response.body()!=null) {
                myBeanClass.setValue(response.body());
            }
        }

        @Override
        public void onFailure(Call<MyBeanClass> call, Throwable t) {
         //How to handle exceptions here and pass the exception to UI without making constructor in bean class
        }
    });

    return myBeanClass;

Еще один способ - взять другие живые данные на предмет ошибки, установить для них свою ошибку и наблюдать за ней в пользовательском интерфейсе.

Jeel Vankhede 23.11.2018 06:34

Вы можете объяснить это с помощью кода?

Ashmeet Arora 23.11.2018 06:43

Привет, Эшмит, как ты справился с этим? Я также сталкиваюсь с той же проблемой и неуверен в процедуре обработки другой ошибки + возникновение исключения.

akash89 28.01.2020 12:31
4
3
7 050
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Посмотрите, как это можно сделать из кода вашего репозитория:

//Take it globally in your repository class, and provide getter for it.
final MutableLiveData<MyBeanClass> myBeanClass = new MutableLiveData<>();
final MutableLiveData<Throwable> error = new MutableLiveData<>();

public void someApiCallMethod() {
    // In your method call for API
    ApiInterface apiInterface = 
    ApiClient.getClientAuthentication().create(ApiInterface.class);
    Call<MyBeanClass> call = apiInterface.getData(id);
    call.enqueue(new Callback<MyBeanClass>() {
        @Override
        public void onResponse(Call<MyBeanClass> call, Response<MyBeanClass> response) {
            if (response.body()!=null) {
                myBeanClass.setValue(response.body());
            }
            // Even you can handle your response error if it's in your response.
        }

        @Override
        public void onFailure(Call<MyBeanClass> call, Throwable t) {
            //Set your error live data from here
            error.setValue(t);
        }
    });
}

Из вашего класса ViewModel создайте метод, который вызывает ваш метод API репо, а другой - для предоставления ваших данных в реальном времени, которые будут наблюдаться в вашем пользовательском интерфейсе.

Надеюсь, поможет !.

да, я понял это до репозитория .. но я столкнулся с проблемами в модели просмотра ... не могли бы вы рассказать мне о том, как кодировать модель просмотра, чтобы получить два разных типа данных, то есть ошибку / ответ

Ashmeet Arora 07.02.2019 07:44

На самом деле ответ довольно старый, недавно я узнал, как мы можем обернуть обе вещи отсюда: developer.android.com/jetpack/docs/guide#addendum. Сообщите мне, удовлетворяет ли это ваше дело, и я соответствующим образом отредактирую свой ответ.

Jeel Vankhede 07.02.2019 07:47

Я не могу получить решение по этой ссылке ... я хочу получить имя этого конкретного исключения, которое я получаю в моем классе репозитория, в моем представлении через модель представления ... и я получил ответ от моего класса репо через представление модель на мой взгляд ... но как это можно сделать в случае любого исключения ... как принять это исключение на мой взгляд ........

Ashmeet Arora 07.02.2019 07:52

Вместо создания двух изменяемых классов. Вы можете просто создать объект-оболочку как для состояния ошибки, так и для состояния успеха или даже для состояния загрузки.

data class Resource<out T>(val status: Status, val data: T?, val message: String?) {
    companion object {
        fun <T> success(data: T?): Resource<T> {
            return Resource(SUCCESS, data, null)
        }

        fun <T> error(msg: String, data: T?): Resource<T> {
            return Resource(ERROR, data, msg)
        }

        fun <T> loading(data: T?): Resource<T> {
            return Resource(LOADING, data, null)
        }
    }
}

А затем используйте данные MutableLive в качестве этого типа

final MutableLiveData<Resource<MyBeanClass>> myBeanClass = new MutableLiveData<>();
           ApiInterface apiInterface = ApiClient.getClientAuthentication().create(ApiInterface.class);
            Call<MyBeanClass> call = apiInterface.getData(id);
            call.enqueue(new Callback<MyBeanClass>() {
                @Override
                public void onResponse(Call<MyBeanClass> call, Response<MyBeanClass> response) {
                    if (response.body()!=null) {
                    myBeanClass.setValue(Resource<MyBeanClass>.success(response.body));
                    }
                }

                @Override
                public void onFailure(Call<MyBeanClass> call, Throwable t) {
     myBeanClass.setValue(Resource<MyBeanClass>.error(t.getLocalizedMessage()));
                }
            });

            return myBeanClass;

Вы можете проверить этот образец Google https://github.com/googlesamples/android-architecture-components/tree/master/GithubBrowserSample

да, я сделал это .. теперь моя проблема в том, как обработать исключение в пользовательском интерфейсе ..?

Ashmeet Arora 26.11.2018 06:58

поместите целое число в качестве свойства в свой объект, чтобы указать статус объекта ресурса (Mybeanclass), например, если ресурс успешен, он будет 1, если ресурс не работает, он будет 0, в этом случае вы можете проверить целочисленное значение объекта и будет ли он 1 или 0 и обработать его

Kaung Khant Thu 27.11.2018 04:51

но я хочу сказать, как получить имя конкретного исключения из репозитория в пользовательский интерфейс?

Ashmeet Arora 27.11.2018 10:26

с использованием case класса оболочки невозможно получить данные для модификации, это нарушает структуру ответа данных

Nguyen Hoà 10.04.2019 10:02

Вы можете взаимодействовать здесь. Вызовите метод интерфейса из onFailure и предоставьте реализацию этого интерфейса со стороны пользовательского интерфейса, чтобы при возникновении ошибки yiu находился на стороне вашего пользовательского интерфейса.

Ответ принят как подходящий

Вот полная реализация mvvm с обработкой ошибок. Сначала создайте класс с состоянием пользовательского интерфейса и ресурсом.

public class Resource<T> {

    @NonNull public final Status status;
    @Nullable public final T data;
    @Nullable public final String message;

    private Resource(@NonNull Status status, @Nullable T data,
                     @Nullable String message) {
        this.status = status;
        this.data = data;
        this.message = message;
    }

    public static <T> Resource<T> success(@NonNull T data) {
        return new Resource<>(Status.SUCCESS, data, null);
    }

    public static <T> Resource<T> error(String msg, @Nullable T data) {
        return new Resource<>(Status.ERROR, data, msg);
    }

    public static <T> Resource<T> loading(@Nullable T data) {
        return new Resource<>(Status.LOADING, data, null);
    }


    public enum Status { SUCCESS, ERROR, LOADING }
}

В вашем классе репозитория сделайте

public LiveData<Resource<MyBeanClass>> getDetail(String movieId) {
        final MutableLiveData<Resource<MyBeanClass>> myBeanClass = new MutableLiveData<>();
        ApiInterface apiInterface = new ApiClient().getClient().create(ApiInterface.class);

   Call<MyBeanClass> call = apiInterface.getData(id);
        call.enqueue(new Callback<MyBeanClass>() {

            @Override
            public void onResponse(Call<MyBeanClass> call, Response<MyBeanClass> response) {
                if (response.body() != null) {
                    MyBeanClass body = response.body();
                    myBeanClass.setValue(Resource.success(body));
                }
            }

            @Override
            public void onFailure(Call<MyBeanClass> call, Throwable t) {
                myBeanClass.setValue(Resource.error(t.getMessage(),null));
            }
        });

        return myBeanClass;
    }

В вашем классе viewModel

public class MyViewModel extends ViewModel {

    private LiveData<Resource<MyBeanClass>> myLiveData;

    public void init(String id) {
        movieLiveData = new MyRepository().getInstance().getDetail(id);

    }

    
    public LiveData<Resource<MyBeanClass>> getMyLiveData() {
        return myLiveData;
    }
}

И в вашем классе активности

final MyViewModel viewModel =
                ViewModelProviders.of(this).get(MyViewModel.class);
        viewModel.init(id);
        viewModel.getMyLiveData().observe(this, finalData -> {

            switch (finalData.status) {
                case SUCCESS:
                    loadDetail(finalData.data);
                    break;
                case LOADING:
                    break;
                case ERROR:
                    Toast.makeText(this, "no Internet", Toast.LENGTH_SHORT).show();
                    break;
            }

        });

Если поможет, не забудьте проголосовать. Удачного кодирования

public MutableLiveData<String> responseMessage = new MutableLiveData<>();
public MutableLiveData<String> errorMessage = new MutableLiveData<>();                                           ApiInterface apiInterface = ApiClient.getClientAuthentication().create(ApiInterface.class);
Call<MyBeanClass> call = apiInterface.getData(id);
call.enqueue(new Callback<MyBeanClass>() {
    @Override
    public void onResponse(Call<MyBeanClass> call, Response<MyBeanClass> response) {
        if (response.body()==null) {
          //pick server error message
          JSONObject jObjError = new JSONObject(response.errorBody().string());
          Log.d("Error",jObjError.getString("message"))
        }else{
        myBeanClass.setValue(Resource<MyBeanClass>.success(response.body));
        }
    }

    @Override
    public void onFailure(Call<MyBeanClass> call, Throwable t) {
     Log.d("Error", t.getMessage());
     errorMessage.setValue(t.getMessage());
    }
});

просто используйте два MutableLiveData: один для успешного ответа, а другой - для errorResponse, и обновите свой пользовательский интерфейс на основе этих ответов.

Другие вопросы по теме