使用ViewModel+Data Binding解决内存泄漏问题
使用ViewModel+Data Binding解决内存泄漏问题
1.在我们写APP的时候经常会遇到这种情况,点击一个按钮后,通过网络异步操作从后台获取信息,然后再展示到UI,例如
public class MyActivity extends BaseActivity { private void getUser(){ LoadingDialog loadingDialog=new LoadingDialog(this,"加载中"); loadingDialog.show(); Request request = new Request.Builder() .url("getuser.php") .build(); Call call =HttpUtils.getInstance().newCall(request); call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { //更新UI } }); } }
2.由于子线程中不能直接操作UI,所以我们这个时候我们需要利用Handler或者其他方式在主线程中进行
private static <T> Callback getCallBack() { final Handler handler = new Handler() { @Override public void handleMessage(Message msg) { //更新UI } }; return new Callback() { @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { Message message = handler.obtainMessage(1, response); handler.sendMessage(message); } }; }
3.Handler在创建的时候会自动持有Activity对象,所以在Activity被系统回收时,会没办法释放导致内存泄漏,如果去网上搜索,大多数都是让你使用弱引用或者静态内部类来解决,但是这两种方式都很麻烦而且使代码变的很难看,目前为止我绝得最好的方式是使用ViewModel+Data Binding
4.ViewModel有以下好处
- ViewModel不会持有Activity对象
- ViewModel会监视Activity的生命周期,在Activity的生命周期里可能触发多次OnCreate,但是ViewModel只会创建一次
- ViewModel可以自动帮你保存数据,让Activity销毁再创建后可以恢复数据
5.ViewModel代码如下,网络请求开始时会设置Result为0,结束时会设置Result为1,这里我只是打个比方,你也可以使用ObservableField或者BaseObservable传递更复杂的数据,UserInfoViewModel也可以继承AndroidViewModel,它是一个拥有上下文的ViewModel
public class UserInfoViewModel extends ViewModel { private final ObservableInt mResult=new ObservableInt(); public ObservableInt getResult() { return mResult; } public void getUser(){ Request request = new Request.Builder() .url("getuser.php") .build(); Call call =HttpUtils.getInstance().newCall(request); mResult.set(0); call.enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { } @Override public void onResponse(Call call, Response response) throws IOException { mResult.set(1); } }); } }
6.下面是Activity里的代码,Activity可以监视Result来更新UI
private void subscribeUi() { mUserInfoViewModel.getResult().addOnPropertyChangedCallback(new Observable.OnPropertyChangedCallback() { @Override public void onPropertyChanged(Observable sender, int propertyId) { int result=mUserInfoViewModel.getResult().get(); switch (result){ case 0: mLoadingDialog.show("加载中"); break; case 1: mLoadingDialog.dismiss(); ToastUtils.show("获取数据成功"); break; default: break; } } }); }