ViewModel是谷歌的组建架构AAC(Android Architecture Components)中的组件。
ViewModel类是被设计用来以可感知生命周期的方式存储和管理 UI 相关数据,ViewModel中数据会一直存活(持久化)即使 activity configuration发生变化,比如横竖屏切换的时候。
我们来看看ViewModel的生命周期:
由上图可知,ViewModel 生命周期是贯穿整个 Activity 生命周期,包括 Activity 因旋转造成的重新创建,直到 Activity 真正意义上销毁后才会结束。既然如此,用来存放数据再好不过了。
在使用过程中ViewModel一般都是结合LiveData来使用的,这样还能实现数据的异步回调(因为使用ViewModel不用去考虑生命周期,所以能很好地避免一些耗时的异步回调,判断Activity或者Fragment是否存在等问题)并解耦,由于它数据的持久化,可以实现多个fragment之间共享数据:
看一个官网的例子:
public class SharedViewModel extends ViewModel {
private final MutableLiveData<Item> selected = new MutableLiveData<Item>();
public void select(Item item) {
selected.setValue(item);
}
public LiveData<Item> getSelected() {
return selected;
}
}
public class MasterFragment extends Fragment {
private SharedViewModel model;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item -> {
model.select(item);
});
}
}
public class DetailFragment extends Fragment {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
model.getSelected().observe(this, { item ->
// Update the UI.
});
}
}
上面这是 一个Activity 与其内部的 fragment 可以共用一个ViewModel的案例。
总结:
- Activity 不需要做任何操作,甚至不需要知道这次交互,完美解耦。
- Fragment 只需要 与 ViewModel 交互,不需要知道对方 Fragment 的状态甚至是否存在,更不需要持有其引用。
- Fragment 与 Fragment 的生命周期之间互不影响,即使对方 Fragment 销毁,也不影响自身任何工作。
来看一个简单的demo:
/**
* 基础ViewModel类,管理LiveData
*/
public class BaseViewModel extends ViewModel {
private Map<String, MutableLiveData> maps;
/**
* 构造函数(在ViewModelProvider里通过class.newInstance创建实例)
*/
public BaseViewModel() {
maps = new ConcurrentHashMap<>(); //初始化集合(线程安全)
}
/**
* 通过指定的数据实体类获取对应的 LiveData 类
*/
protected <T> MutableLiveData<T> get(Class<T> clazz) {
return get(null, clazz);
}
/**
* 通过指定的key或者数据实体类获取对应的 LiveData 类
*/
protected <T> MutableLiveData<T> get(String key, Class<T> clazz) {
String keyName;
if (TextUtils.isEmpty(key)) {
keyName = clazz.getCanonicalName();
} else {
keyName = key;
}
MutableLiveData<T> mutableLiveData = maps.get(keyName);
// 判断集合是否已经存在 LiveData 对象,若存在就返回
if (mutableLiveData != null) {
return mutableLiveData;
}
// 如果 Map 集合中没有对应实体类的 LiveData 对象,就创建并添加至集合中
mutableLiveData = new MutableLiveData<>();
assert keyName != null;
maps.put(keyName, mutableLiveData);
return mutableLiveData;
}
/**
* 在对应的FragmentActivity销毁之后调用
*/
@SuppressWarnings("unchecked")
@Override
protected void onCleared() {
super.onCleared();
if (maps != null) {
maps.clear();
}
}
}
- ViewModel类中的操作:
public class DemoViewModel extends BaseViewModel {
// 获取 Person 对象对应的 MutableLiveData
MutableLiveData<Person> getPersonMutableLiveData() {
return get(Person.class);
}
}
- 创建对应的ViewModel:
/**
* 创建ViewModel对象
* 在Activity或Fragment需要获取对应的 ViewModel 的时候调用
* @param clazz
* @return 对应的 T 的 ViewModel
* 泛型中的限定,必须是ViewModel的子类
*/
public <T extends ViewModel> T get(Class<T> clazz) {
return viewModelProvider.get(clazz);
}
/**
* 初始化 ViewModelProvider 对象
* 建议在Activity初始化的时候执行
* @return ViewModelProvider
*/
private ViewModelProvider getViewModelProvider() {
return ViewModelProviders.of(this);
}
- 在Activity 或 Fragment 中通过 ViewModel 获取到创建好的 LiveData 观察数据的变化:
@Route(path = "/test/demo")
public class DemoActivity extends BaseActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
DemoViewModel demoViewModel = get(DemoViewModel.class);
MutableLiveData<Person> personMutableLiveData = demoViewModel.getPersonMutableLiveData();
// 1.添加数据更改监听器 监听数据的回调
personMutableLiveData.observe(this, new Observer<Person>() {
@Override
public void onChanged(@Nullable Person person) {
Log.e("DemoActivity = ", "DemoActivity中接收person:" + person.toString());
Log.e("DemoActivity = ", "线程 = :" + Thread.currentThread().getName()); // 打印结果主线程
}
});
}
public void onClick(View view){
new Thread(new Runnable() {
@Override
public void run() {
getData();
Log.e("DemoActivity = ", "线程 ***** &&&&& = :" + Thread.currentThread().getName());
}
}).start();
}
// 更改数据
public void getData() {
Person person = new Person();
person.setName("Jack");
person.setSex("男");
DemoViewModel demoViewModel = get(DemoViewModel.class);
MutableLiveData<Person> personMutableLiveData = demoViewModel.getPersonMutableLiveData();
//同步更改setValue ; 异步更改postValue
personMutableLiveData.setValue(person);
// personMutableLiveData.postValue(person); // 添加数据
}
}
通过上面的案例大家应该知道怎么使用了,接下来我们进阶使用一下:
先给大家画张图:
先来创建几个base基础类:
- BaseDataModel:
/**
* 在生命周期的某个时刻取消订阅。
* 一个很常见的模式就是使用CompositeSubscription来持有所有的Subscriptions,然后在onDestroy()或者onDestroyView()里取消所有的订阅
*/
public abstract class BaseDataModel {
// 可以缓解Rx内存占用不能释放的问题
private CompositeSubscription mCompositeSubscription;
public BaseDataModel() {
}
// 添加订阅
protected void addSubscribe(Subscription subscription) {
if (mCompositeSubscription == null) {
mCompositeSubscription = new CompositeSubscription();
}
mCompositeSubscription.add(subscription);
}
// 移除订阅
public void unSubscribe() {
if (mCompositeSubscription != null && mCompositeSubscription.hasSubscriptions()) {
mCompositeSubscription.clear();
}
}
}
- BaseViewModel:
public class BaseViewModel<T extends BaseDataModel> extends AndroidViewModel {
public MutableLiveData<String> loadState; // 网络加载状态的 LiveData
public T mDataModel;
public BaseViewModel(@NonNull Application application) {
super(application);
loadState = new MutableLiveData<>();
mDataModel = DemoUtil.getNewInstance(this, 0);
}
@Override
protected void onCleared() {
super.onCleared();
if (mDataModel != null) {
mDataModel.unSubscribe(); // 清除所有订阅 释放内存 (Rx))
}
}
}
- BaseLifecycleFragment:
public abstract class BaseLifecycleFragment<T extends BaseViewModel> extends BaseFragment {
protected T mViewModel;
@Override
public void initView() {
mViewModel = createViewModel(this, (Class<T>) DemoUtil.getInstance(this, 0));
if (null != mViewModel) {
MutableLiveData loadState = mViewModel.loadState;
loadState.observe(this, observer);
dataObserver();
}
}
/**
* 创建 自定义的 ViewModel
*/
protected <T extends ViewModel> T createViewModel(Fragment fragment, @NonNull Class<T> modelClass) {
ViewModelProvider viewModelProvider = ViewModelProviders.of(fragment);
return viewModelProvider.get(modelClass);
}
/**
* LiveData 观察者回调实现的方法
*/
protected abstract void dataObserver();
// lifecycle 中 liveData的监听者
protected Observer<String> observer = new Observer<String>() {
@Override
public void onChanged(@Nullable String state) {
if (!TextUtils.isEmpty(state)) {
if (StateConstants.ERROR_STATE.equals(state)) {
showToast("加载错误");
} else if (StateConstants.NET_WORK_STATE.equals(state)) {
showToast("网络不好,请稍后重试");
} else if (StateConstants.LOADING_STATE.equals(state)) {
showToast("加载中");
} else if (StateConstants.SUCCESS_STATE.equals(state)) {
showToast("加载成功");
}
}
}
};
}
工具类:
public class DemoUtil {
public static <T> T getNewInstance(Object object, int i) {
if(object!=null){
try {
return ((Class<T>) ((ParameterizedType) (object.getClass()
.getGenericSuperclass())).getActualTypeArguments()[i])
.newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (ClassCastException e) {
e.printStackTrace();
}
}
return null;
}
// 获取泛型类型
public static <T> T getInstance(Object object, int i) {
if (object != null) {
return (T) ((ParameterizedType) object.getClass()
.getGenericSuperclass())
.getActualTypeArguments()[i];
}
return null;
}
// 检查引用是否为空
public static @NonNull
<T> T checkNotNull(final T reference) {
if (reference == null) {
throw new NullPointerException();
}
return reference;
}
}
- 创建回调接口:
public interface CallBack<T> {
// 没网络
void onNoNetWork();
// 成功
void onNext(T t);
// 失败
void onError(String e);
}
准备工作做好了接下来看如何使用:
- HomeDataModel:
/**
* 网络请求和数据库的操作
* ApiDataModel 这个类中主要创建 serviceApi 接口
*/
public class HomeDataModel extends ApiDataModel {
public void requestNetWorHomekData(CallBack listener) {
Observable<HomeResponse> homeResponseObservable = serviceApi.requestHomeData();
addSubscribe(
homeResponseObservable
.compose(RxSchedulers.io_main())
.subscribe(new RxSubscriber<Object>() {
@Override
protected void onNoNetWork() {
super.onNoNetWork();
listener.onNoNetWork();
}
@Override
public void onSuccess(Object o) {
listener.onNext(o);
}
@Override
public void onFailure(String msg) {
listener.onError(msg);
}
}));
}
}
- HomeViewModel:
/**
* 业务逻辑处理
*/
public class HomeViewModel extends NetWorkBaseViewModel<HomeDataModel> {
public HomeViewModel(@NonNull Application application) {
super(application);
}
private MutableLiveData<HomeResponse> homeMutableLiveData; // 存储首页数据的 MutableLiveData
public MutableLiveData<HomeResponse> getHomeMutableLiveData(){
if (homeMutableLiveData == null) {
homeMutableLiveData = new MutableLiveData<>();
}
return homeMutableLiveData;
}
// 发起网络请求
public void getRequestHomeData() {
mDataModel.requestNetWorHomekData(new CallBack<Object>() {
@Override
public void onNoNetWork() {
Log.e("HomeViewModel 错误 = ", "网络异常");
loadState.postValue(StateConstants.NET_WORK_STATE);
}
@Override
public void onNext(Object object) {
if (object instanceof HomeResponse) {
HomeResponse homeResponse = (HomeResponse) object;
homeMutableLiveData.postValue(homeResponse);
loadState.postValue(StateConstants.SUCCESS_STATE);
}
}
@Override
public void onError(String e) {
Log.e("HomeViewModel 错误 = ", e);
}
});
}
}
- HomeFragment展示给用户显示:
public class HomeFragment extends BaseLifecycleFragment<HomeViewModel> {
public static HomeFragment newInstance() {
return new HomeFragment();
}
@Override
protected void dataObserver() {
mViewModel.getHomeMutableLiveData().observe(this, new Observer<HomeResponse>() {
@Override
public void onChanged(@Nullable HomeResponse homeResponse) {
showData(homeResponse);
}
});
}
/**
* 列表展示数据
*/
private void showData(HomeResponse homeResponse) {
Log.e("HomeFragment = ",homeResponse.toString());
}
@Override
protected View initLayout(LayoutInflater inflater, ViewGroup container) {
return inflater.inflate(R.layout.activity_target, null);
}
@Override
public void initView() {
super.initView();
}
@Override
protected void initData(Bundle savedInstanceState) {
mViewModel.getRequestHomeData();
}
}
运行起来打印数据:
网络请求是用的 Retrofit + OkHttp,具体怎么使用:
Retrofit:https://www.jianshu.com/p/dac9a1c02525
OkHttp:https://www.jianshu.com/p/500abf06f447
这样只要DataModel中数据一变化,View中就可以立即监听到数据变化,做出相应操作。
对这个方法的具体解释:
public static <T> T getInstance(Object object, int i) {
if (object != null) {
return (T) ((ParameterizedType) object.getClass()
.getGenericSuperclass())
.getActualTypeArguments()[i];
}
return null;
}
关于怎么获取泛型中参数类型的分析:https://www.jianshu.com/p/27772c32fa41