通过 mvvm android 进行异常处理
exception handling through mvvm android
我在 android studio 中使用 MVVM 架构通过改造来访问 Web 服务。在我看来,我已经处理了服务的响应 class。但是我面临的问题是如何处理异常并将它们传递给我的视图class。一种方法是在我的 Bean class 中创建构造函数并将响应和错误都传递给它并更新 UI。但我想要更优化的方式来处理 UI.
中的异常
这是我的存储库代码:
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;
查看如何从您的存储库代码中完成:
//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
Class,创建一个调用你的 repo API 方法的方法,另一个提供你的实时数据以在你的 UI 上观察的方法。
希望对您有所帮助!
而不是创建两个 Mutable 类。
您可以只为错误和成功状态甚至加载状态创建一个包装器对象
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
您可以在此处进行交互。从 onFailure 调用接口方法并从 UI 端提供该接口的实现,因此无论何时出错,yiu 都会在您的 UI 端
这里是带有错误处理的 mvvm 的完整实现。
首先用 UI 状态和资源创建一个 class。
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 }
}
在你的存储库上class做
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 上 class
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;
}
}
还有你的 Activity class
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,一个用于成功响应,另一个用于错误响应,并根据这些响应更新您的 UI。
我在 android studio 中使用 MVVM 架构通过改造来访问 Web 服务。在我看来,我已经处理了服务的响应 class。但是我面临的问题是如何处理异常并将它们传递给我的视图class。一种方法是在我的 Bean class 中创建构造函数并将响应和错误都传递给它并更新 UI。但我想要更优化的方式来处理 UI.
中的异常这是我的存储库代码:
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;
查看如何从您的存储库代码中完成:
//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
Class,创建一个调用你的 repo API 方法的方法,另一个提供你的实时数据以在你的 UI 上观察的方法。
希望对您有所帮助!
而不是创建两个 Mutable 类。 您可以只为错误和成功状态甚至加载状态创建一个包装器对象
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
您可以在此处进行交互。从 onFailure 调用接口方法并从 UI 端提供该接口的实现,因此无论何时出错,yiu 都会在您的 UI 端
这里是带有错误处理的 mvvm 的完整实现。 首先用 UI 状态和资源创建一个 class。
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 }
}
在你的存储库上class做
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 上 class
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;
}
}
还有你的 Activity class
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,一个用于成功响应,另一个用于错误响应,并根据这些响应更新您的 UI。