GVKun编程网logo

Android架构组件JetPack之ViewModel(二)(android jetpack mvvm框架搭建)

6

在本文中,我们将给您介绍关于Android架构组件JetPack之ViewModel(二)的详细内容,并且为您解答androidjetpackmvvm框架搭建的相关问题,此外,我们还将为您提供关于An

在本文中,我们将给您介绍关于Android架构组件JetPack之ViewModel(二)的详细内容,并且为您解答android jetpack mvvm框架搭建的相关问题,此外,我们还将为您提供关于Android Jetpack -- ViewModel篇(一)、Android Jetpack 架构组件 (一) 与 AndroidX、Android Jetpack-ViewModel、android Jetpack—ViewModel使用方法和详细原理解析的知识。

本文目录一览:

Android架构组件JetPack之ViewModel(二)(android jetpack mvvm框架搭建)

Android架构组件JetPack之ViewModel(二)(android jetpack mvvm框架搭建)

阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680

概述

viewmodel,从字面上理解的话,它肯定是跟视图(View)以及数据(Model)相关的。正像它字面意思一样,它是负责准备和管理和UI组件(Fragment/Activity)相关的数据类,也就是说viewmodel是用来管理UI相关的数据的,同时viewmodel还可以用来负责UI组件间的通信。

之前存在的问题

viewmodel用来存储和管理UI相关的数据,可于将一个Activity或Fragment组件相关的数据逻辑抽象出来,并能适配组件的生命周期,如当屏幕旋转Activity重建后,viewmodel中的数据依然有效。

引入viewmodel之前,存在如下几个问题:

通常Android系统来管理UI controllers(如Activity、Fragment)的生命周期,由系统响应用户交互或者重建组件,用户无法操控。当组件被销毁并重建后,原来组件相关的数据也会丢失,如果数据类型比较简单,同时数据量也不大,可以通过onSaveInstanceState()存储数据,组件重建之后通过onCreate(),从中读取Bundle恢复数据。但如果是大量数据,不方便序列化及反序列化,则上述方法将不适用。
UI controllers经常会发送很多异步请求,有可能会出现UI组件已销毁,而请求还未返回的情况,因此UI controllers需要做额外的工作以防止内存泄露。
当Activity因为配置变化而销毁重建时,一般数据会重新请求,其实这是一种浪费,最好就是能够保留上次的数据。
UI controllers其实只需要负责展示UI数据、响应用户交互和系统交互即可。但往往开发者会在Activity或Fragment中写许多数据请求和处理的工作,造成UI controllers类代码膨胀,也会导致单元测试难以进行。我们应该遵循职责分离原则,将数据相关的事情从UI controllers中分离出来。

viewmodel基本使用

public class Myviewmodel extends viewmodel { private mutablelivedata<List<User>> users; public LiveData<List<User>> getUsers() { if (users == null) { users = new mutablelivedata<List<Users>>(); loadUsers(); } return users; } private void loadUsers() { // 异步调用获取用户列表 } }

新的Activity如下:

public class MyActivity extends AppCompatActivity { public void onCreate(Bundle savedInstanceState) { Myviewmodel model = viewmodelProviders.of(this).get(Myviewmodel.class); model.getUsers().observe(this, users -> { // 更新 UI }); } }

如果Activity被重新创建了,它会收到被之前Activity创建的相同Myviewmodel实例。当所属Activity终止后,框架调用viewmodel的onCleared()方法清除资源。

因为viewmodel在指定的Activity或Fragment实例外存活,它应该永远不能引用一个View,或持有任何包含Activity context引用的类。如果viewmodel需要Application的context(如获取系统服务),可以扩展Androidviewmodel,并拥有一个构造器接收Application。

在Fragment间共享数据

一个Activity中的多个Fragment相互通讯是很常见的。之前每个Fragment需要定义接口描述,所属Activity将二者捆绑在一起。此外,每个Fragment必须处理其他Fragment未创建或不可见的情况。通过使用viewmodel可以解决这个痛点,这些Fragment可以使用它们的Activity共享viewmodel来处理通讯:

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 onActivityCreated() { model = viewmodelProviders.of(getActivity()).get(Sharedviewmodel.class); itemSelector.setonClickListener(item -> { model.select(item); }); } } public class DetailFragment extends LifecycleFragment { public void onActivityCreated() { Sharedviewmodel model = viewmodelProviders.of(getActivity()).get(Sharedviewmodel.class); model.getSelected().observe(this, { item -> // update UI }); } }

注意:上面两个Fragment都用到了如下代码来获取viewmodel,getActivity()返回的是同一个宿主Activity,因此两个Fragment之间返回的是同一个Sharedviewmodel对象。

Sharedviewmodel model = viewmodelProviders.of(getActivity()).get(Sharedviewmodel.class);

这种方式的好处包括:

1.Activity不需要做任何事情,也不需要知道通讯的事情
2.Fragment不需要知道彼此,除了Sharedviewmodel进行联系。如果它们(Fragment)其中一个消失了,其余的仍然能够像往常一样工作。
3.每个Fragment有自己的生命周期,而且不会受其它Fragment生命周期的影响。事实上,一个Fragment替换另一个Fragment,UI的工作也不会受到任何影响。

viewmodel的生命周期

viewmodel对象的范围由获取viewmodel时传递至viewmodelProvider的Lifecycle所决定。viewmodel始终处在内存中,直到Lifecycle永久地离开—对于Activity来说,是当它终止(finish)的时候,对于Fragment来说,是当它分离(detached)的时候。

 

  19956127-3f03922ab943aba3.png​  

 

上图左侧为Activity的生命周期过程,期间有一个旋转屏幕的操作;右侧则为viewmodel的生命周期过程。

一般通过如下代码初始化viewmodel:

viewmodel = viewmodelProviders.of(this).get(UserProfileviewmodel.class);

this参数一般为Activity或Fragment,因此viewmodelProvider可以获取组件的生命周期。

Activity在生命周期中可能会触发多次onCreate(),而viewmodel则只会在第一次onCreate()时创建,然后直到最后Activity销毁。

viewmodel相关类图

  19956127-c3814feecf9d1720.png​  

viewmodelProviders是viewmodel工具类,该类提供了通过Fragment和Activity得到viewmodel的方法,而具体实现又是由viewmodelProvider实现的。

viewmodelProvider是实现viewmodel创建、获取的工具类。在viewmodelProvider中定义了一个创建viewmodel的接口类——Factory。viewmodelProvider中有个viewmodelStore对象,用于存储viewmodel对象。

viewmodelStore是存储viewmodel的类,具体实现是通过HashMap来保存ViewModle对象。

viewmodel是个抽象类,里面只定义了一个onCleared()方法,该方法在viewmodel不在被使用时调用。viewmodel有一个子类Androidviewmodel,这个类是便于要在viewmodel中使用Context对象,因为我们前面提到不能在viewmodel中持有Activity的引用。

viewmodelStores是viewmodelStore的工厂方法类,它会关联HolderFragment,HolderFragment有个嵌套类——HolderFragmentManager。

viewmodel相关时序图

追溯创建一个viewmodel的源码,会察觉需要的步骤有点多。下面以在Fragment中得到viewmodel对象为例看下整个过程的时序图。

 

  19956127-7571dacd95f6f3f3.png​  

 

时序图看起来比较复杂,但是它只描述了两个过程:

得到viewmodel对象。
HolderFragment被销毁时,viewmodel收到onCleared()通知。

viewmodel相关源码分析

viewmodelProviders类的具体实现:

public class viewmodelProviders { private static Application checkApplication(Activity activity) { Application application = activity.getApplication(); if (application == null) { throw new IllegalStateException("Your activity/fragment is not yet attached to " + "Application. You can't request viewmodel before onCreate call."); } return application; } private static Activity checkActivity(Fragment fragment) { Activity activity = fragment.getActivity(); if (activity == null) { throw new IllegalStateException("Can't create viewmodelProvider for detached fragment"); } return activity; } @NonNull @MainThread public static viewmodelProvider of(@NonNull Fragment fragment) { viewmodelProvider.AndroidviewmodelFactory factory = viewmodelProvider.AndroidviewmodelFactory.getInstance( checkApplication(checkActivity(fragment))); return new viewmodelProvider(viewmodelStores.of(fragment), factory); } @NonNull @MainThread public static viewmodelProvider of(@NonNull FragmentActivity activity) { viewmodelProvider.AndroidviewmodelFactory factory = viewmodelProvider.AndroidviewmodelFactory.getInstance( checkApplication(activity)); return new viewmodelProvider(viewmodelStores.of(activity), factory); } @NonNull @MainThread public static viewmodelProvider of(@NonNull Fragment fragment, @NonNull Factory factory) { checkApplication(checkActivity(fragment)); return new viewmodelProvider(viewmodelStores.of(fragment), factory); } @NonNull @MainThread public static viewmodelProvider of(@NonNull FragmentActivity activity, @NonNull Factory factory) { checkApplication(activity); return new viewmodelProvider(viewmodelStores.of(activity), factory); }

viewmodelProviders提供了四个of()方法,四个方法功能类似,其中of(FragmentActivity activity, Factory factory)和of(Fragment fragment, Factory factory)提供了自定义创建viewmodel的方法。

  1. 判断Fragment的是否Attached to Activity,Activity的Application对象是否为空。
  2. 创建viewmodel对象看似很简单,一行代码搞定。
new viewmodelProvider(viewmodelStores.of(fragment), factory)

先看看viewmodelStores.of()方法:

@NonNull @MainThread public static viewmodelStore of(@NonNull Fragment fragment) { if (fragment instanceof viewmodelStoreOwner) { return ((viewmodelStoreOwner) fragment).getviewmodelStore(); } return holderFragmentFor(fragment).getviewmodelStore(); }

继续深入发现其实是实现了一个接口:

public interface viewmodelStoreOwner { @NonNull viewmodelStore getviewmodelStore(); }

holderFragmentFor()是HolderFragment的静态方法,HolderFragment继承自Fragment。我们先看holderFragment()方法的具体实现

@RestrictTo(RestrictTo.Scope.LIBRARY_GROUP) public static HolderFragment holderFragmentFor(Fragment fragment) { return sHolderFragmentManager.holderFragmentFor(fragment); } @NonNull @Override public viewmodelStore getviewmodelStore() { return mviewmodelStore; }

继续看HolderFragmentManager.holderFragmentFor()方法的具体实现

HolderFragment holderFragmentFor(Fragment parentFragment) { FragmentManager fm = parentFragment.getChildFragmentManager(); HolderFragment holder = findHolderFragment(fm); if (holder != null) { return holder; } holder = mNotCommittedFragmentHolders.get(parentFragment); if (holder != null) { return holder; } parentFragment.getFragmentManager() .registerFragmentLifecycleCallbacks(mParentDestroyedCallback, false); holder = createHolderFragment(fm); mNotCommittedFragmentHolders.put(parentFragment, holder); return holder; } private FragmentLifecycleCallbacks mParentDestroyedCallback = new FragmentLifecycleCallbacks() { @Override public void onFragmentDestroyed(FragmentManager fm, Fragment parentFragment) { super.onFragmentDestroyed(fm, parentFragment); HolderFragment fragment = mNotCommittedFragmentHolders.remove( parentFragment); if (fragment != null) { Log.e(LOG_TAG, "Failed to save a viewmodel for " + parentFragment); } } }; private static HolderFragment createHolderFragment(FragmentManager fragmentManager) { HolderFragment holder = new HolderFragment(); // 创建HolderFragment对象 fragmentManager.beginTransaction().add(holder, HOLDER_TAG).commitAllowingStateLoss(); return holder; } public HolderFragment() { //这个是关键,这就使得Activity被recreate时,Fragment的onDestroy()和onCreate()不会被调用 setRetainInstance(true); }

setRetainInstance(boolean) 是Fragment中的一个方法。将这个方法设置为true就可以使当前Fragment在Activity重建时存活下来, 如果不设置或者设置为 false, 当前 Fragment 会在 Activity 重建时同样发生重建, 以至于被新建的对象所替代。

在setRetainInstance(boolean)为true的 Fragment 中放一个专门用于存储viewmodel的Map, 自然Map中所有的viewmodel都会幸免于Activity重建,让Activity, Fragment都绑定一个这样的Fragment, 将viewmodel存放到这个 Fragment 的 Map 中, viewmodel 组件就这样实现了。

到此为止,我们已经得到了ViewStore对象,前面我们在创建viewmodelProvider对象是通过这行代码实现的new viewmodelProvider(viewmodelStores.of(fragment), sDefaultFactory)现在再看下viewmodelProvider的构造方法

public viewmodelProvider(@NonNull viewmodelStore store, @NonNull Factory factory) { mFactory = factory; this.mviewmodelStore = store; }

现在就可以通过viewmodelProvider.get()方法得到viewmodel对象,继续看下该方法的具体实现

@NonNull @MainThread public <T extends viewmodel> T get(@NonNull String key, @NonNull Class<T> modelClass) { viewmodel viewmodel = mviewmodelStore.get(key); //从缓存中查找是否有已有viewmodel对象。 if (modelClass.isinstance(viewmodel)) { //noinspection unchecked return (T) viewmodel; } else { //noinspection StatementWithEmptyBody if (viewmodel != null) { // Todo: log a warning. } } viewmodel = mFactory.create(modelClass); //创建viewmodel对象,然后缓存起来。 mviewmodelStore.put(key, viewmodel); //noinspection unchecked return (T) viewmodel; }

viewmodelProvider.get()方法比较简单,注释中都写明了。最后我们看下viewmodelStore类的具体实现

public class viewmodelStore { private final HashMap<String, viewmodel> mMap = new HashMap<>(); final void put(String key, viewmodel viewmodel) { viewmodel oldviewmodel = mMap.get(key); if (oldviewmodel != null) { oldviewmodel.onCleared(); } mMap.put(key, viewmodel); } final viewmodel get(String key) { return mMap.get(key); } public final void clear() { for (viewmodel vm : mMap.values()) { vm.onCleared(); } mMap.clear(); } }

viewmodelStore是缓存viewmodel的类,put()、get()方法用于存取viewmodel对象,另外提供了clear()方法用于清空缓存的viewmodel对象,在该方法中会调用viewmodel.onCleared()方法通知viewmodel对象不再被使用。

viewmodel收到onCleared()通知

HolderFragment的onDestroy()方法

@Override public void onDestroy() { super.onDestroy(); mviewmodelStore.clear(); }

在onDestroy()方法中调用了viewmodelStore.clear()方法,我们知道在该方法中会调用viewmodel的onCleared()方法。在你看了HolderFragment源码后,或许你会有个疑问,mviewmodelStore保存的viewmodel对象是在哪里添加的呢? 细心的话,你会发现在viewmodelProvider的构造方法中,已经将HolderFragment中的ViwModelStore对象mviewmodelStore的引用传递给了viewmodelProvider中的mviewmodelStore,而在viewmodelProvider.get()方法中会向mviewmodelStore添加viewmodel对象。

总结

viewmodel职责是为Activity或Fragment管理、请求数据,具体数据请求逻辑不应该写在viewmodel中,否则viewmodel的职责会变得太重,此处需要一个引入一个Repository,负责数据请求相关工作。具体请参考 Android架构组件。
viewmodel可以用于Activity内不同Fragment的交互,也可以用作Fragment之间一种解耦方式。
viewmodel也可以负责处理部分Activity/Fragment与应用其他模块的交互。
viewmodel生命周期(以Activity为例)起始于Activity第一次onCreate(),结束于Activity最终finish时。

原文链接:https://blog.csdn.net/qq_24442769/article/details/79426609
阿里P7移动互联网架构师进阶视频(每日更新中)免费学习请点击:https://space.bilibili.com/474380680

Android Jetpack -- ViewModel篇(一)

Android Jetpack -- ViewModel篇(一)

ViewModel的出现主要为了解决两个问题:
1.当Actvitiy销毁重建过程中的数据恢复问题,虽然原来可以使用onSaveInstanceState()来完成,但是只支持能被序列化的数据而且是小量数据,对于大量数据则显得有点无力。
2.UI控制器的工作繁忙,UI控制器主要用于处理显示,交互,其他的额外操作可以委托给其他类完成,将不应该分配给UI的任务分离出来是必要的,这也就是上面所说的分离关注点原则。
下面是示意图

ViewModel实例

ViewModel在配置更改期间能自动保留其对象,以便它们所持有的数据可立即用于下一个 Activity 或片段 Fragment

具体的实例我在以前的一篇博客中讲过了,想要了解请点击  Android学习进度二  进行查看。

 

回到最上面的那个图,图说明了ViewModel的作用域涉及到整个生命周期,当获取ViewModel时,ViewModel的生命周期限定为传入ViewModelProvider的对象的生命周期。也就是对于以下场景(引用官方示例)

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,所以其作用域为整个Activity,不同的Fragment可以通过ViewModelProviders获取到同一个ViewModel,这样有以下的好处:

  • Activity无须参与Fragment之间的交互。Activity与Fragment无关
  • Fragment之间也无需互相建立联系,Fragment与Fragment无关
  • 每个Fragment都有自己的生命周期,即使被替换也不会有任何影响

ViewModel加强,支持异常生命周期

有些时候在Activity被意外杀死,如清理后台等会直接跳过onDestory()而是回调onSaveInstanceState()异常杀死下的生命周期,这个时候ViewModel也会被杀死,再次恢复的时候便会被重建,这样,原来的数据也就丢失了,因此我们需要改进一下ViewModel以支持异常退出情况下的重建。
首先很容易是想到通过onSaveInstanceState() 来保存,然后通过SaveInstanceState 来恢复,虽然也是一种可行的方法,但是跟ViewModel没什么关联,ViewModel也提供了类似SavedInstanceState的方法。

SavedStateHandle :用于保存状态的数据类型,是一个key-value的map,类似于Bundle。

具体用法

public class ViewModelWithData extends ViewModel {
 
     private MutableLiveData<Integer> number;
     private SavedStateHandle handle;
 
     private static final String KEY_NUMBER = "number";
 
     public ViewModelWithData(SavedStateHandle handle) {
         this.handle = handle;
         number = new MutableLiveData<>();
         number.setValue(0);
     }
 
     public MutableLiveData<Integer> getNumber() {
         if (!handle.contains(KEY_NUMBER)) {
             handle.set(KEY_NUMBER, 0);
         }
         return handle.getLiveData(KEY_NUMBER);
     }
 
     public void addNumber(int n) {
         getNumber().setValue(getNumber().getValue() + n);
     }
 }
public class LiveDataActivity extends AppCompatActivity {
 
     private ViewModelWithData viewModelWithData;
 
     ActivityLiveDataBinding binding;
 
     @Override
     protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         binding = DataBindingUtil.setContentView(this, R.layout.activity_live_data);
         viewModelWithData = ViewModelProviders.of(this, new SavedStateVMFactory(this)).get(ViewModelWithData.class);
         binding.setData(viewModelWithData);
         binding.setLifecycleOwner(this);
     }
 
 }

Android Jetpack 架构组件 (一) 与 AndroidX

Android Jetpack 架构组件 (一) 与 AndroidX

一、 概述

自 2008 年 9 月 22 日谷歌发布 Android 1.0 版本到前不久 Android 12 版本到发布,Android 已经陪伴我们走过了 12 个年头。可以说,经过 12 年的打磨和沉淀,Android 的技术体系已经非常的成熟了。比如说,一开始时框架很少,也没有什么规范,所有的代码都是要自己写,但是现在,我们很少会关系这种基础代码,因为一些框架和工具的出现正在帮助开发者完成这方面的工作。

不过,虽然我们可以使用这些框架和技术来达到快速迭代的目的,但是越来越杂的技术选型也让 Android 开发者无从选择,最终导致做出来的应用质量参差不齐。长久以来,Android 一直没有制定一个规范来姐姐这一问题,只要能够实现功能,代码怎么编写都是可以的。虽然 Android 官方没有推出开发标准,但是一些技术社区出于更高效的进行协同开发,逐渐引入了 MVP 和 MVVM 等应用开发架构,使用这些框架开发出来的应用,无论从项目质量还是代码的可读性和可维护性来说,都更加出色,于是这些框架和技术逐渐流行起来。

这些情况被谷歌发现后,最终在 Goole I/O 2018 大会上推出了全新的 Android Jetpack 应用开发架构。或许称 Android Jetpack 为一个架构有点不准确,更多的地方将它称为 Android 应用开发的工具集,Jetpack 是一套库、工具和指南的集合,旨在帮助开发者更轻松地编写优质应用。事实上,Android Jetpack 所包含的内容是比较庞大的,主要由基础组件、架构组件、行为组件和 UI 组件构成,如下图所示。
在这里插入图片描述
并且,

本文同步分享在 博客 “xiangzhihong8”(CSDN)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与 “OSC 源创计划”,欢迎正在阅读的你也加入,一起分享。

Android Jetpack-ViewModel

Android Jetpack-ViewModel

一、概述

为什么需要viewmodel或者说viewmodel的优势是什么?

如果Activity或者Fragment销毁或者重建,存储在其中的数据会丢失,对于简单的数据比如Activity可以使用onSaveInstanceState()方法来从onCreate()中恢复数据,但这个方法只适合可以序列化再反序列化的少量数据,而不适合较大的数据。

另外一个问题是,界面经常需要异步操作,比如网络请求等,当界面销毁时,往往需要手动维护异步取消的动作,这无疑显得特别繁琐。并且把所有代码都写在界面中,会变得特别臃肿。

于是就需要将视图数据与界面分离,让层次清晰且高效。且viewmodel可以维护自己的生命周期,不需要手动操作,这无疑大大降低开发难度。

二、简单实现viewmodel

简单的viewmodel实现

class UserInfoviewmodel : viewmodel() {

    //延迟创建LiveData对象
    val userInfoLiveData: mutablelivedata<UserInfo> by lazy {
        //创建LiveData
        mutablelivedata<UserInfo>()
    }

    /**
     * 请求用户信息
     */
    fun requestUserInfo() {
        //伪代码:请求到了用户信息
        var userInfo = UserInfo("zhangsan", 18)
        //将请求到的值userInfo设置给LiveData,更新数据
        userInfoLiveData.value = userInfo
    }

}

在Activity中调用

class MainActivity : AppCompatActivity() {

    //创建viewmodel对象
    private val userInfoviewmodel: UserInfoviewmodel by lazy {
        UserInfoviewmodel()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        var textview = findViewById<TextView>(R.id.tv_start)

        //调用viewmodel的方法请求数据
        userInfoviewmodel.requestUserInfo()
        //通知修改数据
        userInfoviewmodel.userInfoLiveData.observe(this, Observer<UserInfo> {
            //拿到了请求到的UserInfo对象,通知修改数据
            textview.text = it?.name
        })
    }
}

需要注意的点:

  • 如果Activity重新创建,它接收的viewmodel实例与第一个Activity创建的实例相同。
  • 当Activity完成(不能简单理解为destroy)时,框架会调用viewmodelonCleared()方法,以便它可以清理资源。
  • viewmodel的生命周期比视图的生命周期长,所以viewmodel绝不能持有视图、Lifecycle或Activity的上下文等引用,否则就会造成内存泄漏。
  • viewmodel绝不能观察对生命周期感知型对象(如LiveData对象)的更改。
  • 如果viewmodel需要持有上下文,只能是Application的上下文,扩展Androidviewmodel类并通过构造方法传入,如下代码:
/**
 * 继承Androidviewmodel,创建时需要通过构造方法传入Application对象
 */
class CustomApplicationviewmodel(application: Application) : Androidviewmodel(application) {

    override fun onCleared() {
        super.onCleared()
    }
}

//因为这个viewmodel持有Application的引用,所以它的生命周期会很长
//于是可以在Application类中创建全局的viewmodel
class App : Application() {

    //创建全局viewmodel对象
    val mCustomApplicationviewmodel: CustomApplicationviewmodel by lazy {
        CustomApplicationviewmodel(this)
    }

    override fun onCreate() {
        super.onCreate()
    }
}

//调用
var app: App = application as App
app.mCustomApplicationviewmodel...

三、viewmodel的初始化方式

1、懒加载的初始化方式

这种方式是最简单的方式,但是封装架构的时候一般不这样用。代码见本文第二章节最上面viewmodel的代码。

2、简单工厂初始化viewmodel

viewmodel的类

class UserInfoviewmodel : viewmodel() {
...
}

创建viewmodel对象

var userInfoviewmodel = viewmodelProvider.NewInstanceFactory()
.create(UserInfoviewmodel::class.java)

或另一种写法

var userInfoviewmodel =
    viewmodelProvider(this).get(UserInfoviewmodel::class.java)

二者的区别create是创建一个新的实例,而get是先从HashMap中找,找不到就创建新的实例。看下源码也就知道为什么重新创建的viewmodel是同一个对象。

public <T extends viewmodel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
    //viewmodelStore底层是HashMap集合
    //通过key从集合中取出viewmodel对象
    viewmodel viewmodel = mviewmodelStore.get(key);
    //判断这个viewmodel类的实例对象是否是需要viewmodel类的实例对象
    if (modelClass.isinstance(viewmodel)) {
        if (mFactory instanceof OnRequeryFactory) {
            ((OnRequeryFactory) mFactory).onRequery(viewmodel);
        }
        //如果是直接返回
        return (T) viewmodel;
    } else {
        //noinspection StatementWithEmptyBody
        if (viewmodel != null) {
            // Todo: log a warning.
        }
    }
    //如果不存在就创建
    if (mFactory instanceof KeyedFactory) {
        viewmodel = ((KeyedFactory) mFactory).create(key, modelClass);
    } else {
        viewmodel = mFactory.create(modelClass);
    }
    //并且将创建的viewmodel实例对象存在HashMap中
    mviewmodelStore.put(key, viewmodel);
    return (T) viewmodel;
}

3、使用ktx扩展(推荐)

添加依赖

implementation 'androidx.activity:activity-ktx:1.4.0'
implementation 'androidx.fragment:fragment-ktx:1.4.1'

viewmodel的类

class UserInfoviewmodel : viewmodel() {
...
}

在Activity中创建viewmodel的方式

class MainActivity :AppCompatActivity() {

    //通过ktx扩展创建viewmodel对象
    private  val userInfoviewmodel by viewmodels<UserInfoviewmodel>{
        viewmodelProvider.NewInstanceFactory()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        var textview = findViewById<TextView>(R.id.tv_start)

        //调用viewmodel的方法请求数据
        userInfoviewmodel.requestUserInfo()
        //通知修改数据
        userInfoviewmodel.userInfoLiveData.observe(this, Observer<UserInfo> {
            //拿到了请求到的UserInfo对象,通知修改数据
            textview.text = it?.name
        })
    }
}

在Fragment中创建viewmodel的方式

class CustomFragment:Fragment() {

    //通过ktx扩展创建viewmodel对象
    private  val userInfoviewmodel by activityviewmodels<UserInfoviewmodel>{
        viewmodelProvider.NewInstanceFactory()
    }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

    }
}

四、viewmodel的生命周期

viewmodel对象存在的时间范围是获取 viewmodel时传递给 viewmodelProviderLifecycleviewmodel将一直留在内存中,直到限定其存在时间范围的 Lifecycle永久消失:对于 activity,是在 activity 完成时;而对于 fragment,是在 fragment 分离时。

如下官方给的生命周期示例图:

上图说明了 Activity 经历屏幕旋转而后结束时所处的各种生命周期状态。该图还在 Activity 生命周期的旁边显示了 viewmodel 的生命周期。此图表说明了 Activity 的各种状态。这些基本状态同样适用于 Fragment 的生命周期。所以不要简单理解Activity的完成状态就是Destroy状态,上图屏幕旋转会经历一次onDestroy

通过上图可以看到,viewmodel创建后,它并不关心onDestroy之前的生命周期,它只关系视图控件(Activity,Fragment等)何时退出,我们跟踪一下源码。

1、Activity中viewmodel何时退出

首先通过上面的分析,可以知道viewmodel创建时会放入一个HashMap集合(viewmodelStore.mMap)中,调用的时候也是从这个集合中取,那么何时从这个集合中删除?

//ComponentActivity部分源码
//ComponentActivity的构造方法,创建Activity时调用
public ComponentActivity() {
    ...
    getLifecycle().addobserver(new LifecycleEventObserver() {
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            //当收到Activity的ON_DESTROY事件时
            if (event == Lifecycle.Event.ON_DESTROY) {
                // Clear out the available context
                mContextAwareHelper.clearavailableContext();
                // And clear the viewmodelStore
                //isChangingConfigurations()永远返回false
                if (!isChangingConfigurations()) {
                    //清除viewmodelStore
                    getviewmodelStore().clear();
                }
            }
        }
    });
    getLifecycle().addobserver(new LifecycleEventObserver() {
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            //担保viewmodelStore,如果不是正常的onDestroy这里会恢复viewmodelStore
            ensureviewmodelStore();
            getLifecycle().removeObserver(this);
        }
    });
    ...
 }

可以看到当触发onDestroy事件时,viewmodel的集合确实会被清除掉,但是下面又有担保的方式恢复,看下担保恢复的方法:

@SuppressWarnings("WeakerAccess") /* synthetic access */
void ensureviewmodelStore() {
    if (mviewmodelStore == null) {
        //取出之前配置的实例
        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        if (nc != null) {
            //恢复viewmodelStore
            // Restore the viewmodelStore from NonConfigurationInstances
            mviewmodelStore = nc.viewmodelStore;
        }
        //如果viewmodel还是null,创建新的viewmodelStore给这个新的Activity用
        if (mviewmodelStore == null) {
            mviewmodelStore = new viewmodelStore();
        }
    }
}

可以看到配置的实例中如果还有就取出来重新用,如果没有就创建一个新的viewmodelStore给新的Activity用。继续跟源码,跟到Activity类就是系统方法了,并没有找到答案。

@Nullable
public Object getLastNonConfigurationInstance() {
    //如果不为null返回一个Activity实例
    return mLastNonConfigurationInstances != null
            ? mLastNonConfigurationInstances.activity : null;
}

//给上面的Activity实例赋值的地方
...
NonConfigurationInstances retainNonConfigurationInstances() {
    Object activity = onRetainNonConfigurationInstance();
...

/**
 * Called by the system,as part of destroying an
 * activity due to a configuration change,...
 */
public Object onRetainNonConfigurationInstance() {
    return null;   //系统调用的方法,只能看到null
}

2、Fragment中viewmodel何时退出

与上面的原理类似,看viewmodelStore何时移除

//FragmentStateManager
//销毁时的方法
void destroy() {
    ...
    //是否Fragment应该被移除
    boolean beingRemoved = mFragment.mRemoving && !mFragment.isInBackStack();
    // Clear any prevIoUs saved state
    if (beingRemoved && !mFragment.mBeingSaved) {
        mFragmentStore.setSavedState(mFragment.mWho, null);
    }
    //Fragment是否应该被销毁
    boolean shouldDestroy = beingRemoved
            || mFragmentStore.getNonConfig().shouldDestroy(mFragment);
    //如果应该被销毁
    if (shouldDestroy) {
        FragmentHostCallback<?> host = mFragment.mHost;
        boolean shouldClear;
        if (host instanceof viewmodelStoreOwner) {
            shouldClear = mFragmentStore.getNonConfig().isCleared();
        } else if (host.getContext() instanceof Activity) {
            Activity activity = (Activity) host.getContext();
            shouldClear = !activity.isChangingConfigurations();
        } else {
            shouldClear = true;
        }
        if ((beingRemoved && !mFragment.mBeingSaved) || shouldClear) {
            //移除的关键代码
            mFragmentStore.getNonConfig().clearNonConfigState(mFragment);
        }
       ...
}

void clearNonConfigState(@NonNull Fragment f) {
    if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
        Log.d(TAG, "Clearing non-config state for " + f);
    }
    clearNonConfigStateInternal(f.mWho);
}

void clearNonConfigState(@NonNull String who) {
    if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
        Log.d(TAG, "Clearing non-config state for saved state of Fragment " + who);
    }
    clearNonConfigStateInternal(who);
}

private void clearNonConfigStateInternal(@NonNull String who) {
    // Clear and remove the Fragment's child non config state
    FragmentManagerviewmodel childNonConfig = mChildNonConfigs.get(who);
    if (childNonConfig != null) {
        childNonConfig.onCleared();
        mChildNonConfigs.remove(who);
    }
    // Clear and remove the Fragment's viewmodelStore
    viewmodelStore viewmodelStore = mviewmodelStores.get(who);
    if (viewmodelStore != null) {
        //移除viewmodelStore
        viewmodelStore.clear();
        mviewmodelStores.remove(who);
    }
}

五、在Fragment之间共享数据

Activity 中的两个或更多 Fragment 需要相互通信是一种很常见的现象。多个 fragment 可以在其 activity 范围内共享 viewmodel存储的数据。 先看下官方的示例代码,这里做了精简:

class Sharedviewmodel : viewmodel() {
     //创建LiveData
    val selected = mutablelivedata<Item>()

    //为LiveData赋值
    fun select(item: Item) {
        selected.value = item
    }
}

class ListFragment : Fragment() {
    //创建(获取)viewmodel对象
    private val model: Sharedviewmodel by activityviewmodels()
    ...
}

class DetailFragment : Fragment() {
    //创建(获取)viewmodel对象
    private val model: Sharedviewmodel by activityviewmodels()
    ...
}

请注意,这两个 Fragment 都会检索包含它们的 Activity。这样,当这两个 Fragment 各自获取 viewmodelProvider时,它们会收到相同的 Sharedviewmodel 实例(其范围限定为该 Activity)。

此方法具有以下优势:

  • Activity 不需要执行任何操作,也不需要对此通信有任何了解。
  • 除了 Sharedviewmodel 约定之外,Fragment 不需要相互了解。如果其中一个 Fragment 消失,另一个 Fragment 将继续照常工作。
  • 每个 Fragment 都有自己的生命周期,而不受另一个 Fragment 的生命周期的影响。如果一个 Fragment 替换另一个 Fragment,界面将继续工作而没有任何问题。

简单看下源码是如何实现的,Fragment在Attach时会调用FragmentManager的下面的方法:

@SuppressWarnings("deprecation")
@SuppressLint("SyntheticAccessor")
void attachController(@NonNull FragmentHostCallback<?> host,
        @NonNull FragmentContainer container, @Nullable final Fragment parent) {
        ...
    // Get the FragmentManagerviewmodel
    if (parent != null) {
        mNonConfig = parent.mFragmentManager.getChildNonConfig(parent);
    } else if (host instanceof viewmodelStoreOwner) {
        //获取viewmodelStore赋值给FragmentManager自己的viewmodelStore
        viewmodelStore viewmodelStore = ((viewmodelStoreOwner) host).getviewmodelStore();
        mNonConfig = FragmentManagerviewmodel.getInstance(viewmodelStore);
    } else {
        mNonConfig = new FragmentManagerviewmodel(false);
    }
       ...

getviewmodelStore()方法获取的就是Activity的viewmodelStore

@NonNull
@Override
public viewmodelStore getviewmodelStore() {
    return FragmentActivity.this.getviewmodelStore();
}

android Jetpack—ViewModel使用方法和详细原理解析

android Jetpack—ViewModel使用方法和详细原理解析

关注我的公众号 “安安安安卓” 免费学知识

大部分人更关心用法,所以我先讲用法, 再讲对 viewmodel 的理解,最后讲源码

1、ViewModel 初始化方式

来到 androidx,ViewModel 的创建方式与老版本有了很大的不同,所以这里还是要将 Viewmodel 的初始化讲一下

1.1、安卓工厂初始化

每次都会重新创建 model,并且不受 ViewModelStore 管控,所以无特殊需求禁止使用该种方式

使用 AndroidViewModelFactory 工厂创建

  1. viewmodel 类定义
class AndroidFactoryViewModel(app:Application): AndroidViewModel(app) {
    fun print(){
        logEE("使用安卓默认工厂创建viewmodel")
    }
}
  1. 创建 viewmodel 实例代码
val model = ViewModelProvider.AndroidViewModelFactory.getInstance(application)
                .create(AndroidFactoryViewModel::class.java)
            model.print()

1.2、简单工厂初始化 ViewModel

每次都会重新创建 model,并且不受 ViewModelStore 管控,所以无特殊需求禁止使用该种方式

NewInstanceFactory

  1. viewmodel 类定义代码
class SimpleFactoryViewModel: ViewModel() {
    fun print(){
        logEE("使用简单工厂创建viewmodel")
    }
}
  1. 创建 viewmodel 代码
 val model =ViewModelProvider.NewInstanceFactory().create(SimpleFactoryViewModel::class.java)
 model.print()

1.3、自定义安卓工厂初始化

多次创建可以复用 model,不会重新创建

默认的工厂只能创建带 Application 的 ViewModel 实例的,我们通过自定义工厂实现自定义构造参数的目的

  1. 定义安卓工厂
class CustomAndroidViewModelFactory(val app: Application, private val data: String) :
    ViewModelProvider.AndroidViewModelFactory(app) {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        if (AndroidViewModel::class.java.isAssignableFrom(modelClass)) {
            return try {
                modelClass.getConstructor(Application::class.java, String::class.java)
                    .newInstance(app, data)
            } ...
        }
        return super.create(modelClass)
    }
}

省略了 catch 中的代码,您可以到源码中查看

在我们的自定义工厂的构造中传入一个自定义的 data 参数,代表我们的自定义构造参数

  1. viewmodel 类定义

    必须是继承 AndroidViewModel 才可以

class CustomAndroidViewModel(private val app: Application, private val data: String) :
    AndroidViewModel(app) {
    fun print() {
        logEE(data)
    }
}

我们的 CustomAndroidViewModel 类中也有一个 data:String 参数,这个参数就是对应上一步中自定义工厂中的 data 参数

  1. 实例化 viewmodel
val model = ViewModelProvider(
                viewModelStore,
                CustomAndroidViewModelFactory(application, "自定义安卓工厂创建viewmodel")
            ).get(CustomAndroidViewModel::class.java)
            model.print()

1.4、自定义简单工厂初始化

多次获取可以复用 model,不会重新创建

自定义简单工厂也是为了实现 viewmodel 构造传参的目的,废话不多说,直接上代码吧

  1. 定义安卓工厂
class CustomSimpleViewModelFactory(app:Application,private val data:String) : ViewModelProvider.AndroidViewModelFactory(app) {
    override fun <T : ViewModel?> create(modelClass: Class<T>): T {
        return try {
            modelClass.getConstructor(String::class.java).newInstance(data)
        } ......
    }
}
  1. viewmodel 类定义
class CustomSimpleViewModel(private val data: String) : ViewModel() {
    fun print() {
        logEE(data)
    }
}
  1. 实例化 viewmodel
val model = ViewModelProvider(
                viewModelStore,
                CustomSimpleViewModelFactory(application, "自定义简单工厂创建viewmodel")
            ).get(CustomSimpleViewModel::class.java)
            model.print()

1.5 使用委托机制创建 viewmodel(推荐)

多次创建可以复用 model,不会重新创建

google 官方给我们提供了 activity-ktx 库,通过它我们可以使用委托机制创建 viewmodel

实现方式如下:

  1. 加入依赖
implementation ''androidx.activity:activity-ktx:1.2.2''
  1. 创建 viewmodel 类
class EnTrustModel : ViewModel() {
    fun print(){
        logEE("关注公众号 \"安安安安卓\" 免费学知识")
    }
}
  1. 实例化 viewmodel
private val wtModel: EnTrustModel by viewModels<EnTrustModel> {
        ViewModelProvider.NewInstanceFactory()
    }
  1. 调用 viewmodel 的方法
 wtModel.print()

2、 viewmodel 概览

ViewModel 类旨在以注重生命周期的方式存储和管理界面相关的数据。ViewModel 类让数据可在发生屏幕旋转等配置更改后继续留存。

我们知道 android 中的 Activity 和 Fragment 都是可以对生命周期进行管理的,如果 Activity/Fragment 被系统销毁,例如屏幕旋转就必须重新创建 Activity/Fragment,这个时候就涉及到一个数据恢复的问题。通常我们会使用 onSaveInstanceState 和 onRestoreSaveInstance 两个方法对数据进行保存和恢复,但是这两个方法只能处理数据量较小的情况。

如果是大数据量的情况那么用 viewmodel 就是不错的选择了

同时 viewmodel 还可以帮助我们将业务逻辑从 Activity/Fragment 中分离出来

3、 viewmodel 实现 Fragment 之间数据共享

同一个 activity 中出现多个 Fragment,并且这些 Fragment 之间需要进行通信,这样的需求是很常见的

以往我们可能会采用下列方式实现数据共享:

  1. EventBus
  2. 接口回调
  3. 全局共享数据池

但是当我们学了 viewmodel 后就会发现,viewmodel 可以轻松实现 Fragment 之间的数据共享

我们可以让多个 Fragment 共用同一个 ViewModel 实现数据的共享。

本例中我们要实现下面的功能:

activity 中有两个 fragment,FragmentA 和 FragmentB,我们在 ViewModel 的构造方法中开始倒计时 2000s,在 FragmentA 中观察倒计时的数据并展示在页面上。然后再切换到 FragmentB,如果 FragmentB 中的倒计时的秒数没有重置为 2000,说明我们的数据共享成功了。

上代码:

  1. 创建 ViewModel
class ShareDataModel: ViewModel() {
    val liveData = MutableLiveData<String>()
    var total = 2000L
    init {
        /**
         * 实现倒计时,一秒钟倒计时一次
         */
        val countDownTimer = object :CountDownTimer(1000 * total, 1000) {
            override fun onTick(millisUntilFinished: Long) {
                liveData.postValue("剩余倒计时时间 ${--total}")
            }
            override fun onFinish() {
                logEE("倒计时完成")
            }
        }
        countDownTimer.start()
    }
}
  1. 创建 FragmentA
class FragmentA : Fragment() {
    private val model: ShareDataModel by activityViewModels()
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_a, container, false).apply {
            model.liveData.observe(viewLifecycleOwner,
                { value -> findViewById<TextView>(R.id.tv_aresult).text = value })
        }
    }
}
  1. 创建 FragmentB
class FragmentB : Fragment() {
    private val model: ShareDataModel by activityViewModels()
    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View? {
        return inflater.inflate(R.layout.fragment_b, container, false).apply {
            model.liveData.observe(viewLifecycleOwner,
                { value -> findViewById<TextView>(R.id.tv_bresult).text = value })
        }
    }
}
  1. 展示结果

通过 gif 我们发现,即使 replace 后倒计时的数据仍然没有改变,说明我们成功实现了数据共享

4、 关于 viewmodel 的几个知识点

  1. viewmodel 绝对不可以引用视图
  2. 在 activity 的存在期间可能会多次走 onCreate 方法,但是我们的 viewmodel 只有 actvity 结束并销毁的情况下才会被回收
  3. viewmodel 通过 lifecycle 来观察 activity/fragment 的生命周期

5、源码解析

5.1、创建 ViewModel 源码解析

先看一下创建 ViewModel 的代码:

val model = ViewModelProvider(
                viewModelStore,
                CustomSimpleViewModelFactory(application, "自定义简单工厂创建viewmodel")
            ).get(CustomSimpleViewModel::class.java)

那么就从 ViewModelProvider 构造方法和 get 方法说起吧,

  1. ViewModelProvider 构造方法

ViewModelProvider 构造方法传入两个参数,ViewModelStore(用来存储管理 ViewModel)和 Factory(创建 ViewModel 的工厂)

public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
        mFactory = factory;
        mViewModelStore = store;
    }
  1. ViewModelProvider 的 get 方法
public <T extends ViewModel> T get(@NonNull Class<T> 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);
    }

getCanonicalName 方法可以获取一个能唯一标识 Class<T>的字符串,最终会用作生成我们 ViewModelStore 中存储 ViewModel 的 key。

获取 key 后我们将 key 和 modelClass 做为参数调用重载 get 方法

  1. 重载 get 方法

方法的解读写在代码中了

 public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
        ViewModel viewModel = mViewModelStore.get(key);//从ViewModelStore中根据key获取ViewModel,如果有就会返回

        if (modelClass.isInstance(viewModel)) {//判断获取的ViewModel是否是传入的modelClass类型
            if (mFactory instanceof OnRequeryFactory) {//不看这里
                ((OnRequeryFactory) mFactory).onRequery(viewModel);
            }
            return (T) viewModel;//如果是就返回viewmodel
        } else {
            //noinspection StatementWithEmptyBody
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }
        if (mFactory instanceof KeyedFactory) {
            viewModel = ((KeyedFactory) mFactory).create(key, modelClass);//一般不会用这个工厂
        } else {
            viewModel = mFactory.create(modelClass);//创建ViewModel
        }
        mViewModelStore.put(key, viewModel);//将ViewModel添加到mViewModelStore中
        return (T) viewModel;
    }

5.2、ViewModelStore 类解析

ViewModelStore 中有三个重要方法 get、put、clear,并且维护了一个 HashMap<String,ViewModel>

  1. get
 final ViewModel get(String key) {
        return mMap.get(key);
    }
很简单就是根据key获取ViewModel
  1. put
 final void put(String key, ViewModel viewModel) {
        ViewModel oldViewModel = mMap.put(key, viewModel);//oldViewModel指的是被覆盖的ViewModel
        if (oldViewModel != null) {
            oldViewModel.onCleared();
        }
    }

将一个 ViewModel 添加到 map 中,并且将被覆盖的 ViewModel 数据清理(因为同一个 activity 中只能存在一个同类型的 ViewModel)

  1. clear

下一节会讲

clear 方法的调用时机(重点)

先看一下 clear 方法

public final void clear() {
      for (ViewModel vm : mMap.values()) {
          vm.clear();
      }
      mMap.clear();
  }

clear 方法的调用位置在 ComponentActivity 的构造方法中,代码如下:

getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                if (event == Lifecycle.Event.ON_DESTROY) {
                    // Clear out the available context
                    mContextAwareHelper.clearAvailableContext();
                    // And clear the ViewModelStore
                    if (!isChangingConfigurations()) {//当有配置信息存在的时候返回:true(屏幕旋转,后台被杀死),当没有配置信息的时候返回:false(应用被主动杀死)。
                        getViewModelStore().clear();
                    }
                }
                }
            });

恍然大悟,原来 ViewModel 通过 LifeCycle 观察 Activity 生命周期的方式来处理数据的清理操作

关注我的公众号 “安安安安卓” 免费学知识粗体

我们今天的关于Android架构组件JetPack之ViewModel(二)android jetpack mvvm框架搭建的分享已经告一段落,感谢您的关注,如果您想了解更多关于Android Jetpack -- ViewModel篇(一)、Android Jetpack 架构组件 (一) 与 AndroidX、Android Jetpack-ViewModel、android Jetpack—ViewModel使用方法和详细原理解析的相关信息,请在本站查询。

本文标签: