Android Jetpack Components of Lifecycle 学习笔记

Android Jetpack Components of LiveData 学习笔记

Android Jetpack Components of ViewModel 学习笔记

 

Demo 地址:https://github.com/mengzhinan/Lifecycle_LiveData_ViewModel_demo

ViewModel Google 文档:https://developer.android.google.cn/topic/libraries/architecture/viewmodel

 

环境配置:

与 Lifecycle 和 LiveData 略有不同,在其基础上,还需要导入依赖:

// viewmodel 需要添加的配置implementation 'android.arch.lifecycle:extensions:1.1.1'

ViewModel 是什么?

ViewModel 类的设计目的是以生命周期意识的方式存储和管理与UI相关的数据。ViewModel 类允许数据在配置更改(如屏幕旋转)中生存。

 

以我的理解总结为:

1、ViewModel 可以实现在同一个 Activity 对象下的多个 Fragment 之间数据共享。

2、ViewModel 可以实现在手机屏幕旋转前后数据共享,避免不必要的重复数据请求。

 

先从 Demo 使用看起吧。还是上一篇文章的 LiveData Demo:

public class DataUtil {    private MutableLiveData name = new MutableLiveData<>();    public LiveData getNameLiveData(){        return name;    }    public void requestHead() {        // 模拟请求网络或 DB,然后更新数据        name.setValue("requestHead success");    }    public void requestList() {        // 模拟请求网络或 DB,然后更新数据        name.setValue("requestList success");    }}
public class LiveDataActivity extends AppCompatActivity {    private DataUtil dataUtil;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        dataUtil = new DataUtil();        dataUtil.getNameLiveData().observe(this, data -> {            // 得到数据更新        });    }    @Override    protected void onResume() {        super.onResume();        dataUtil.requestHead();        dataUtil.requestList();    }}

上面代码其实有个问题,如果 DataUtil 重复创建的话,将会对应的重新创建 MutableLiveData 对象,故无法实现数据共享。先别钻牛角,看 ViewModel 的用法:

public class ListViewModel extends ViewModel {    private MutableLiveData headLiveData;    private MutableLiveData listLiveData;    public LiveData getHeadLiveData() {        if (headLiveData == null) {            headLiveData = new MutableLiveData<>();        }        return headLiveData;    }    public LiveData getListLiveData() {        if (listLiveData == null) {            listLiveData = new MutableLiveData<>();        }        return listLiveData;    }    public void requestHead() {        // TODO: 2019-07-29        headLiveData.setValue("head request success");    }    public void requestList() {        // TODO: 2019-07-29        listLiveData.setValue("list request success");    }}
public class ViewModelActivity extends AppCompatActivity {    private ListViewModel listViewModel;    @Override    protected void onCreate(@Nullable Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        listViewModel = ViewModelProviders.of(this).get(ListViewModel.class);        listViewModel.getHeadLiveData().observe(this, data->{            // 头部数据更新        });        listViewModel.getListLiveData().observe(this, data->{            // list 数据更新        });    }    @Override    protected void onResume() {        super.onResume();        listViewModel.requestHead();        listViewModel.requestList();    }}

代码说明:

DataUtil 逻辑更改为了 ListViewModel,然后继承了 ViewModel 类。其他的没有本质变化。

在 ViewModelActivity 中,唯一的变化是 ListViewModel 的创建方式变为了:

listViewModel = ViewModelProviders.of(this).get(ListViewModel.class);

 

 

我们先来分析 ViewModel 类:

public abstract class ViewModel {    /**     * This method will be called when this ViewModel is no longer used and will be destroyed.     * 

* It is useful when ViewModel observes some data and you need to clear this subscription to * prevent a leak of this ViewModel. */ @SuppressWarnings("WeakerAccess") protected void onCleared() { }}

这是一个抽象类,其中只有一个方法 onCleared(),当 ViewModel 所在的 Activity 销毁时,回调此方法清理资源。

ViewModel 有一个比较常用的子类 AndroidViewModel,提供 application 对象:

/** * Application context aware {@link ViewModel}. * 

* Subclasses must have a constructor which accepts {@link Application} as the only parameter. *

*/public class AndroidViewModel extends ViewModel { @SuppressLint("StaticFieldLeak") private Application mApplication; public AndroidViewModel(@NonNull Application application) { mApplication = application; } /** * Return the application. */ @SuppressWarnings("TypeParameterUnusedInFormals") @NonNull public T getApplication() { //noinspection unchecked return (T) mApplication; }}

 

 

我们再回头分析 ViewModel 获取的方法:

ViewModelProviders.of(this).get(ListViewModel.class);

先追查 get() 方法:

@NonNull    @MainThread    public  T get(@NonNull Class modelClass) {        String canonicalName = modelClass.getCanonicalName();        if (canonicalName == null) {            throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");        }        return get(DEFAULT_KEY + ":" + canonicalName, modelClass);    }

继续追查 get() 重载方法:

@NonNull    @MainThread    public  T get(@NonNull String key, @NonNull Class modelClass) {        ViewModel viewModel = mViewModelStore.get(key);        if (modelClass.isInstance(viewModel)) {            //noinspection unchecked            return (T) viewModel;        } else {            //noinspection StatementWithEmptyBody            if (viewModel != null) {                // TODO: log a warning.            }        }        viewModel = mFactory.create(modelClass);        mViewModelStore.put(key, viewModel);        //noinspection unchecked        return (T) viewModel;    }

如果传递的 ViewModel 已经缓存了,则把缓存的 ViewModel 对象直接返回;否则才创建新的对象。

那么 mViewModelStore 是如何做到缓存的呢?

public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {        mFactory = factory;        this.mViewModelStore = store;    }

发现 mViewModelStore 是在 ViewModelProvider 的构造函数中赋值的。追查到 ViewModelProviders 的 of 方法中:

@NonNull    @MainThread    public static ViewModelProvider of(@NonNull FragmentActivity activity,            @Nullable Factory factory) {        Application application = checkApplication(activity);        if (factory == null) {            factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);        }        return new ViewModelProvider(ViewModelStores.of(activity), factory);    }

追索到 ViewModelStores 的 of 方法:

@NonNull    @MainThread    public static ViewModelStore of(@NonNull FragmentActivity activity) {        if (activity instanceof ViewModelStoreOwner) {            return ((ViewModelStoreOwner) activity).getViewModelStore();        }        return holderFragmentFor(activity).getViewModelStore();    }

找到 HolderFragment 中的 holderFragmentFor() 方法:

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)    public static HolderFragment holderFragmentFor(FragmentActivity activity) {        return sHolderFragmentManager.holderFragmentFor(activity);    }

其实看到这儿,基本可以看出原理:

在 Activity 中创建一个 HolderFragment 对象,并添加到 FragmentManager 中。在 HolderFragment 中保存 ViewModel 集合。

因此,当 Activity 销毁时,也会同步销毁 HolderFragment。

那为什么说手机屏幕旋转前后,ViewModel 不会销毁呢?

追查代码,HolderFragment 类的构造函数:

public HolderFragment() {        setRetainInstance(true);    }
setRetainInstance(true); 这行代码应该是设置避免在屏幕旋转时重建 Fragment。

 

所以,总结 ViewModel 的特点:

ViewModel 是依附 HolderFragment 保存在 Activity 的 FragmentManager 中的。在同一个 Activity 下的任意位置、任意 Fragment 中通过 ViewModelProviders.of(this).get(xxx) 方式获取 ViewModel,都会是同一个对象,故避免了重复请求,实现数据共享。

由于 HolderFragment 的特点,可避免屏幕旋转后的数据丢失,避免重复请求。

 

 

Demo 地址:https://github.com/mengzhinan/Lifecycle_LiveData_ViewModel_demo

 

 

 

 

 

更多相关文章

  1. android 读取指定路径数据库文件
  2. Android(安卓)transformClassesWithDexForAdh5Debug 的解决方法
  3. Android基站+联网+google数据库定位
  4. android 数据库工具类MyDbHelper
  5. 浅谈Java中Collections.sort对List排序的两种方法
  6. mybatisplus的坑 insert标签insert into select无参数问题的解决
  7. python起点网月票榜字体反爬案例
  8. 类和 Json对象
  9. Python list sort方法的具体使用

随机推荐

  1. Android(安卓)获取View高度宽度
  2. widget入门
  3. Android(安卓)2.3的camera的虚拟对焦的去
  4. Android(安卓)studio怎样隐藏标题栏
  5. Android(安卓)轻松实现语音识别的完整代
  6. 【Android】配置文件属性说明
  7. 【Android基础】Android开发学习笔记
  8. Android中attr自定义标签详解
  9. ant编译android工程用批处理打包
  10. Android声音播放实例代码