ViewModel和LiveData的高效使用

作者: 几行代码 | 来源:发表于2019-02-22 16:43 被阅读297次

    ViewModel是谷歌的组建架构AAC(Android Architecture Components)中的组件。
    ViewModel类是被设计用来以可感知生命周期的方式存储和管理 UI 相关数据,ViewModel中数据会一直存活(持久化)即使 activity configuration发生变化,比如横竖屏切换的时候。

    我们来看看ViewModel的生命周期:


    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

    相关文章

      网友评论

        本文标题:ViewModel和LiveData的高效使用

        本文链接:https://www.haomeiwen.com/subject/capeyqtx.html