一.简介
1.MVVM模式
Model:模型层 即数据模型,用于获取和存储数据。和MVP一致。
View:视图层 即Activity/Fragment 和MVP一致。
ViewModel:视图模型,负责业务逻辑。相当于MVP中的Presenter。
2.MVP缺点
MVP模式中Presenter层需要持有IView接口来回调结果给界面(Activity/Fargment)。而Presenter层常常调用Model层进行异步网络请求。因为网络请求时间不固定。所以可能Presenter层会保存很长一段时间,如果Presenter层持有View层(Activity/Fargment)的上下文对象。这样就可能导致View层(Activity/Fragment)已近销毁。但是还有Presenter层持有它,导致该Activity/Fragment不能被及时回收。造成内存泄漏。
3.LiveData&ViewModel
LiveData是一个具有生命周期感知的观察者,ViewModel是和Activity/Fragment生命周期相同的存储和管理界面相关的数据的组件。两者结合可以实现MVVM模式。
二.代码实现
1.截图
2.代码
Model层
package com.wjn.networkdemo.mvvm.model;
import com.wjn.networkdemo.mvvm.network.RetrofitManager;
import com.wjn.networkdemo.mvvm.viewmodel.FanYiViewModel;
import com.wjn.networkdemo.retrofit.rxjavarxandroid.CustomObservable;
import com.wjn.networkdemo.retrofit.rxjavarxandroid.PostService;
import java.io.IOException;
import java.util.HashMap;
import okhttp3.ResponseBody;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class PostModel extends CustomObservable {
private FanYiViewModel.ServiceCallback mServiceCallback;
/**
* Post请求
*/
public void postServiceData(HashMap<String, String> map, String url, FanYiViewModel.ServiceCallback callback) {
mServiceCallback = callback;
PostService postService = RetrofitManager.getInstance(url).createService(PostService.class);
if (null != postService) {
Call<ResponseBody> getCall = postService.getFanYiByPost(map);
getCall.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if (response.isSuccessful()) {//响应成功
String result = null;//响应报文
if (null != response.body()) {//response.body()不为空
try {
result = response.body().string();
} catch (IOException e) {
e.printStackTrace();
}
}
callBack(result);
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
callBack("");
}
});
}
}
/**
* 回调
*/
private void callBack(String result) {
if (null != mServiceCallback) {
mServiceCallback.getResult(result);
}
}
}
View层
package com.wjn.networkdemo.mvvm.view;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;
import com.wjn.networkdemo.R;
import com.wjn.networkdemo.mvvm.viewmodel.FanYiViewModel;
import com.wjn.networkdemo.mvvm.viewmodel.ViewModelFactory;
import java.util.HashMap;
public class MVVMActivity extends AppCompatActivity {
private ProgressBar mProgressBar;
private TextView mTextView;
private FanYiViewModel mFanYiViewModel;
private String mBaseUrl = "http://fanyi.youdao.com/";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_mvvm);
initView();
}
/**
* 初始化View
*/
private void initView() {
mProgressBar = findViewById(R.id.activity_viewmodel_pb);
mTextView = findViewById(R.id.activity_viewmodel_tv);
initViewModel();
//请求接口
findViewById(R.id.activity_viewmodel_textview).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
HashMap<String, String> map = new HashMap<>();
map.put("keyfrom", "imoocdict123456");
map.put("key", "324273592");
map.put("type", "data");
map.put("doctype", "json");
map.put("version", "1.1");
map.put("q", "red");
mFanYiViewModel.getServiceData(map, mBaseUrl);
}
});
}
/**
* 初始化ViewModel
*/
private void initViewModel() {
//获取ViewModelProvider实例
ViewModelProvider viewModelProvider = new ViewModelProvider(this, new ViewModelFactory());
//获取ViewModel实例
mFanYiViewModel = viewModelProvider.get(FanYiViewModel.class);
//观察接口请求
mFanYiViewModel.getResultLiveData().observe(this, s -> {
mTextView.setText(s);
Log.d("MVVMActivity", "接口请求s----:" + s);
Log.d("MVVMActivity", "接口请求线程----:" + Thread.currentThread().getName());
});
//观察接口请求中...
mFanYiViewModel.getLoadingLiveData().observe(this, aBoolean -> {
mProgressBar.setVisibility(aBoolean ? View.VISIBLE : View.GONE);
Log.d("MVVMActivity", "观察接口请求aBoolean----:" + aBoolean);
Log.d("MVVMActivity", "观察接口请求线程----:" + Thread.currentThread().getName());
});
}
}
VM层
package com.wjn.networkdemo.mvvm.viewmodel;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
import com.wjn.networkdemo.mvvm.model.PostModel;
import java.util.HashMap;
public class FanYiViewModel extends ViewModel {
private MutableLiveData<String> mResultLiveData;//报文
private MutableLiveData<Boolean> mLoadingLiveData;//请求中
/**
* 构造方法
*/
public FanYiViewModel() {
mResultLiveData = new MutableLiveData<>();
mLoadingLiveData = new MutableLiveData<>();
}
/**
* 获取接口数据
*/
public void getServiceData(HashMap<String, String> map, String url) {
mLoadingLiveData.setValue(true);//进度条
PostModel postModel = new PostModel();
postModel.postServiceData(map, url, json -> {
mLoadingLiveData.setValue(false);//进度条
mResultLiveData.setValue(json);//接口报文
});
}
/**
* 获取报文的LiveData
*/
public MutableLiveData<String> getResultLiveData() {
return mResultLiveData;
}
/**
* 获取请求中的LiveData
*/
public MutableLiveData<Boolean> getLoadingLiveData() {
return mLoadingLiveData;
}
public interface ServiceCallback {
void getResult(String json);
}
}
3.结果
D/MVVMActivity: 观察接口请求aBoolean----:true
D/MVVMActivity: 观察接口请求线程----:main
D/MVVMActivity: 观察接口请求aBoolean----:false
D/MVVMActivity: 观察接口请求线程----:main
D/MVVMActivity: 接口请求s----:{"translation":["红色的"],"basic":{"us-phonetic":"red","phonetic":"red","uk-phonetic":"red","explains":["adj. 红的,红色的;(毛发)红褐色的;(脸)涨红的;(眼睛)红肿的;革命的,激进的;(人)红种的;(纸牌中)红桃的,红方块的;(葡萄酒)红的;(表示停止)红(灯),红(旗);被禁止的,危险的;(滑雪道上用红色标志指示)第二高难度的;(物理)表示夸克三种颜色之一的红色;赤色的(尤指冷战期间用于指前苏联);沾有鲜血的;(古或诗\/文)流血的;(科萨人)来自传统部落文化的","n. 红色,红颜料;红衣;红葡萄酒;红色物(或人);赤字,亏空;激进分子","n. (Red) 雷德(人名)"]},"query":"red","errorCode":0,"web":[{"value":["红","红色","赤焰战场"],"key":"RED"},{"value":["红河","红河谷","天是红河岸","红江"],"key":"Red River"},{"value":["红葡萄酒","红酒","干红葡萄酒","酒红色"],"key":"Red Wine"}]}
D/MVVMActivity: 接口请求线程----:main
三.总结
ViewModel+LiveData实现MVVM。可以去除Presener 对View、context的引用。
VM层获取到数据后通过LiveData发送给View层。
View层通过观察LiveData观察方法监听结果。
而由于ViewModel的生命周期性,可以在屏幕旋转,Fragment共享数据等场景获取到ViewModel。
也可以完美匹配网络请求有可能时间比较长,需要原来的MVP中的Presenter层需要长期存在的问题。