Android JetPack学习笔记之ViewModel

  • 前言
    • ViewModel
    • LiveData(简要说明)
    • ViewModel源码分析
    • ViewModel的使用

前言

Jetpack 是 Android 软件组件的集合,使您可以更轻松地开发出色的 Android 应用。这些组件可帮助您遵循最佳做法、让您摆脱编写样板代码的工作并简化复杂任务,以便您将精力集中放在所需的代码上。
最近有空边学习边把学习笔记做了。巩固知识,输入输出,强化学习,如有不对望指出,感谢
(以下是对官方代码文档的翻译和自己的部分见解)

如果引用JetPack库

    implementation 'android.arch.lifecycle:extensions:1.1.1'

ViewModel

ViewModel是一个负责用于准备和管理Activity或者Fragment的数据的类,它也负责对Application中其他的Activity和Fragment进行数据通信(比如:调用业务逻辑类,Fragment之间的数据同步,Activity和Fragment的数据同步。后面的列子会讲到)

  1. ViewModel也可以在Activity/Fragment的作用域中创建,生命周期跟随作用域,跟随着Activity的finish销毁而销毁。
  2. 换句话说,这也意味着,如果ViewModel的持有者(Activity/Fragment)因为配置的改变(例如:rotation)而销毁但是ViewModel没有被销毁,那么当持有者(Activity/Fragment)重新生成实例后将重新与已存在的这个ViewModel重新绑定。
  3. ViewModel的目的是用于为一个Activity/Fragment 获取和保存必要的信息,Activity/Fragment 应该能够观察ViewModel内容的变化。ViewModel通常和LiveData或者Android Data Binding来暴露这些信息。您还可以使用您喜欢的框架中的任何Observer类。
  4. ViewModel只负责管理UI的数据,它不应该直接访问你的视图层次和持有你的Activity/Fragment的引用。(例如:不把视图对象或者Activity/Fragment的Context作为对象传入到ViewModel中。避免内存泄漏)

LiveData(简要说明)

LiveData是一个用于保管数据的类。

ViewModel源码分析

启动 Android Studio 3.2 或以上版本,就能使用具有ViewModel的Fragment和Activity。
生成目录结构如下

系统自动生成了MainActivity,MainFragment,MainViewModel。

PS:MainViewModel继承于抽象类ViewModel,ViewModel中有个onCleared的方法,这个方法适用于ViewModel长时间没有被使用,这对于当ViewModel观察一些数据并且你需要清理ViewModel的订阅以防止泄漏很有用。

ViewModel的产生过程如图:

Created with Raphaël 2.2.0 ViewModelProviders.of() 获得ViewModelProvider对象调用get方法 ViewModelProvider.Factory创建ViewModel ViewModelStore是否有ViewModel 返回ViewModel实例 yes no

以下是生成源码分析

//MainFragment中将生成如下代码@Override    public void onActivityCreated(@Nullable Bundle savedInstanceState) {        super.onActivityCreated(savedInstanceState);        mViewModel = ViewModelProviders.of(getActivity()).get(MainViewModel.class);        // TODO: Use the ViewModel        //我在这里创建了个LiveData并        //添加了一个Observer用于观察User数据的变化,        //并为TextView赋值         mViewModel.getUserLiveData().observe(this, new Observer<User>() {            @Override            public void onChanged(@Nullable User user) {                message.setText(user.name);            }        });    }

ViewModel是通过ViewModelProviders.get方法获得的。而get方法是用于返回一个与当前Activity/Fragment绑定的已存在ViewModel或者创建一个新的绑定的ViewModel。那这里是如何判断是否已存在ViewModel或者创建一个新的ViewModel呢?源码如下:

//1.ViewModelProviders.of()方法获得ViewModelProvider对象,//ViewModelProvider方法调用get如下@NonNull    @MainThread    public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {    //2.返回当前类的更具体的名字        String canonicalName = modelClass.getCanonicalName();        if (canonicalName == null) {            throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");        }        //3.把这个canonicalName作为key获取        return get(DEFAULT_KEY + ":" + canonicalName, modelClass);    }@NonNull    @MainThread    public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {    //4.通过key获得之前已存在的ViewModel对象        ViewModel viewModel = mViewModelStore.get(key);        if (modelClass.isInstance(viewModel)) {            //noinspection unchecked            return (T) viewModel;        } else {            //noinspection StatementWithEmptyBody            if (viewModel != null) {                // TODO: log a warning.            }        }        //5.如果ViewModel为空则通过ViewModelProvider.Factory创建一个新的ViewModel        //        viewModel = mFactory.create(modelClass);        //6.并把viewModel存入ViewModelStore中.        mViewModelStore.put(key, viewModel);        //noinspection unchecked        return (T) viewModel;    }//7.ViewModelProvider.Factory如何创建的ViewModel?//AndroidViewModelFactory是ViewModelProvider的静态内部类public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {//部分代码已省略@NonNull        @Override        public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {            if (AndroidViewModel.class.isAssignableFrom(modelClass)) {                //noinspection TryWithIdenticalCatches                try {                //8.通过反射机制创建实例/如果失败调用默认构造器创建实例                    return modelClass.getConstructor(Application.class).newInstance(mApplication);                } catch (NoSuchMethodException e) {                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);                } catch (IllegalAccessException e) {                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);                } catch (InstantiationException e) {                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);                } catch (InvocationTargetException e) {                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);                }            }            return super.create(modelClass);        }}//9.ViewModel的存储类ViewModelStorepublic class ViewModelStore {//10.整个Application的ViewModel实例都被存储于Map中。    private final HashMap<String, ViewModel> mMap = new HashMap<>();    final void put(String key, ViewModel viewModel) {        ViewModel oldViewModel = mMap.put(key, viewModel);        if (oldViewModel != null) {            oldViewModel.onCleared();//清除ViewModel中长期不用的引用        }    }    final ViewModel get(String key) {        return mMap.get(key);    }    /**     *  Clears internal storage and notifies ViewModels that they are no longer used.     */    public final void clear() {        for (ViewModel vm : mMap.values()) {            vm.onCleared();        }        mMap.clear();    }}

ViewModel的使用

一个简单的例子。Activity中的一个按钮,点击以后,Fragment内部的文字实现变化。
在JetPack出现之前。我们大概会使用如下方法:Fragment暴露个方法给Activity中调用,EventBus,BoradCastRecevie等。但这都有缺陷,当然还有RxBus.现在有了JetPack,谷歌统一框架后,我们就能优雅的在Fragment和Activity之间共享数据了。
示例代码如下:

MainActivity.class

public class MainActivity extends AppCompatActivity {    private MainViewModel mainViewModel;    private Button send;    int count=1;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.main_activity);        mainViewModel = ViewModelProviders.of(this).get(MainViewModel.class);        if (savedInstanceState == null) {            getSupportFragmentManager().beginTransaction()                    .replace(R.id.container, MainFragment.newInstance())                    .commitNow();        }        send=findViewById(R.id.send);        send.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View view) {                count++;                mainViewModel.post("1001","Test"+count);            }        });    }}

MainFragment

public class MainFragment extends Fragment {    private MainViewModel mViewModel;    private TextView message;    public static MainFragment newInstance() {return new MainFragment();}    @Nullable    @Override    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,                             @Nullable Bundle savedInstanceState) {        View view=inflater.inflate(R.layout.main_fragment, container, false);        message=view.findViewById(R.id.message);        return view;    }    @Override    public void onActivityCreated(@Nullable Bundle savedInstanceState) {        super.onActivityCreated(savedInstanceState);        mViewModel = ViewModelProviders.of(getActivity()).get(MainViewModel.class);        // TODO: Use the ViewModel        mViewModel.getUserLiveData().observe(this, new Observer<User>() {            @Override            public void onChanged(@Nullable User user) {                message.setText(user.name);            }        });}}

MainViewModel

public class MainViewModel extends ViewModel {   private MutableLiveData<User> userLiveData;    public LiveData<User> getUserLiveData() {        if(userLiveData==null){            userLiveData=new MutableLiveData<>();        }        return userLiveData;    }    public void post(String id, String name){        userLiveData.setValue(new User(id,name));    }}

代码很优雅,逻辑很清晰。
这里没有直接使用LiveData而是MutableLiveData。JetPack中不允许我们直接操作LiveData而是使用MutableLiveData(可变数据)。

public class MutableLiveData<T> extends LiveData<T> {    @Override    public void postValue(T value) {        super.postValue(value);    }    @Override    public void setValue(T value) {        super.setValue(value);    }}

MutableLiveData中postValue和setValue有什么区别呢?
其实源码中的注释描述的很清楚。
postValue是创建一个任务在主线程中用于设置你给的value。
而setValue是直接在主线程执行该方法。

     liveData.postValue("a");     liveData.setValue("b");     The value "b" would be set at first and later the main thread would override it with the value "a".

官方给的例子很明显,同时调用后,“a"参数将覆盖"b”。

下次我们仔细来看看LiveData的源码吧。

更多相关文章

  1. 关于Android自定义相机进行拍照(小米手机出现异常的原因)
  2. 对“Android输入事件流程中的EventHub分析及源码演示”的补充
  3. [置顶] android中自定义View
  4. Android创建和使用数据库SQLIte
  5. Android实现下拉框(Spinner)
  6. Android触摸事件传递
  7. [置顶] Android存储选择
  8. Android(安卓)Service完全解析
  9. Android(安卓)ICON生成及优化

随机推荐

  1. 建站内容管理系统的漏洞
  2. 百家号和百度X盟星怎么做流量?
  3. JavaScript对象模拟数组
  4. thinkphp引入图片处理扩展 Intervention/
  5. android中TextView嵌套在ScrollView中并
  6. Android(安卓)完全掌握Service
  7. Android虚拟键盘挡住输入框的处理方法
  8. Android按返回键弹出对话框退出应用程序
  9. Android分享功能
  10. Using Android's Compatibility Test Sui