ViewModel和LiveData的高效使用

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 selected = new MutableLiveData();

    public void select(Item item) {
        selected.setValue(item);
    }

    public LiveData 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 maps;

    /**
     * 构造函数(在ViewModelProvider里通过class.newInstance创建实例)
     */
    public BaseViewModel() {
        maps = new ConcurrentHashMap<>();  //初始化集合(线程安全)
    }

    /**
     * 通过指定的数据实体类获取对应的 LiveData 类
     */
    protected  MutableLiveData get(Class clazz) {
        return get(null, clazz);
    }

    /**
     * 通过指定的key或者数据实体类获取对应的 LiveData 类
     */
    protected  MutableLiveData get(String key, Class clazz) {
        String keyName;
        if (TextUtils.isEmpty(key)) {
            keyName = clazz.getCanonicalName();
        } else {
            keyName = key;
        }
        MutableLiveData 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 getPersonMutableLiveData() {
        return get(Person.class);
    }
}
  • 创建对应的ViewModel:
/**
     * 创建ViewModel对象
     * 在Activity或Fragment需要获取对应的 ViewModel 的时候调用
     * @param clazz 
     * @return 对应的 T 的 ViewModel
     * 泛型中的限定,必须是ViewModel的子类
     */
    public  T get(Class 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 personMutableLiveData = demoViewModel.getPersonMutableLiveData();
        // 1.添加数据更改监听器  监听数据的回调
        personMutableLiveData.observe(this, new Observer() {
            @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 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 extends AndroidViewModel {

    public MutableLiveData 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 extends BaseFragment {

    protected T mViewModel;

    @Override
    public void initView() {
        mViewModel = createViewModel(this, (Class) DemoUtil.getInstance(this, 0));
        if (null != mViewModel) {
            MutableLiveData loadState = mViewModel.loadState;
            loadState.observe(this, observer);
            dataObserver();
        }
    }

    /**
     * 创建 自定义的 ViewModel
     */
    protected  T createViewModel(Fragment fragment, @NonNull Class modelClass) {
        ViewModelProvider viewModelProvider = ViewModelProviders.of(fragment);
        return viewModelProvider.get(modelClass);
    }

    /**
     *  LiveData 观察者回调实现的方法
     */
    protected abstract void dataObserver();

    // lifecycle 中 liveData的监听者
    protected Observer observer = new Observer() {
        @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 getNewInstance(Object object, int i) {
        if(object!=null){
            try {
                return ((Class) ((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 getInstance(Object object, int i) {
        if (object != null) {
            return (T) ((ParameterizedType) object.getClass()
                    .getGenericSuperclass())
                    .getActualTypeArguments()[i];
        }
        return null;
    }

    // 检查引用是否为空
    public static @NonNull
     T checkNotNull(final T reference) {
        if (reference == null) {
            throw new NullPointerException();
        }
        return reference;
    }
}
  • 创建回调接口:
public interface CallBack {
    // 没网络
    void onNoNetWork();
    // 成功
    void onNext(T t);
    // 失败
    void onError(String e);
}

准备工作做好了接下来看如何使用:

  • HomeDataModel:
/**
 * 网络请求和数据库的操作
 * ApiDataModel 这个类中主要创建 serviceApi 接口
 */
public class HomeDataModel extends ApiDataModel {

    public void requestNetWorHomekData(CallBack listener) {
        Observable homeResponseObservable = serviceApi.requestHomeData();
        addSubscribe(
                homeResponseObservable
                        .compose(RxSchedulers.io_main())
                        .subscribe(new RxSubscriber() {

                            @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 {

    public HomeViewModel(@NonNull Application application) {
        super(application);
    }

    private MutableLiveData homeMutableLiveData;  // 存储首页数据的 MutableLiveData

    public MutableLiveData getHomeMutableLiveData(){
        if (homeMutableLiveData == null) {
            homeMutableLiveData = new MutableLiveData<>();
        }
        return homeMutableLiveData;
    }

    // 发起网络请求
    public void getRequestHomeData() {

        mDataModel.requestNetWorHomekData(new CallBack() {
            @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 {
  
    public static HomeFragment newInstance() {
        return new HomeFragment();
    }

    @Override
    protected void dataObserver() {
        mViewModel.getHomeMutableLiveData().observe(this, new Observer() {
            @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 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的高效使用)