AAC---ViewModel

ViewModel介绍

ViewModel是用来保存并且管理与LifeCycle以及UI相关数据的数据结构。ViewModel允许数据在Configuration改变时(比如屏幕旋转)保存,并且在旋转后恢复。

UI Controller相关的Android框架则是Activity与Fragment。而FrameWork可能由于用户的操作,设备系统事件决定销毁或者重建UI Controller,而这些操作则完全不可控。而当UI Controller被重建或者销毁时候,任何transient UI相关的数据都会丢失。

例如你的APP可能包括了很多用户的数据,当Activity因为Configuration改变而重建时,新的Activity需要重新获取这些数据,而一般会使用onSaveInstanceState方法保存,并且使用onCreate中的Bundle进行恢复,但是这种只适合非常小并且实现了序列化以及反序列化的数据,而不能保存大数据,比如Bitmap等。

最后,ViewModel非常有效的帮我们从UI Controller隔离了View与数据之间的逻辑关系。

使用ViewModel

  1. 在build.gradle中添加配置
dependencies {
    def lifecycle_version = "1.1.1"

    // ViewModel and LiveData
    implementation "android.arch.lifecycle:extensions:$lifecycle_version"
    // alternatively - just ViewModel
    implementation "android.arch.lifecycle:viewmodel:$lifecycle_version" // use -ktx for Kotlin
    // alternatively - just LiveData
    implementation "android.arch.lifecycle:livedata:$lifecycle_version"
    // alternatively - Lifecycles only (no ViewModel or LiveData).
    //     Support library depends on this lightweight import
    implementation "android.arch.lifecycle:runtime:$lifecycle_version"

    annotationProcessor "android.arch.lifecycle:compiler:$lifecycle_version"
    // alternately - if using Java8, use the following instead of compiler
    implementation "android.arch.lifecycle:common-java8:$lifecycle_version"

}
  1. 实现ViewModel与LiveData绑定。
  • 在ViewModel中提供数据来源repository,如Room或者网络
  • 在数据返回后,使用LiveData向UI Controller提供UI相关数据
public class MyViewModel extends ViewModel {
    private MutableLiveData<List<User>> users;
    public LiveData<List<User>> getUsers() {
        if (users == null) {
            users = new MutableLiveData<List<User>>();
            loadUsers();
        }
        return users;
    }

    private void loadUsers() {
        // Do an asynchronous operation to fetch users.
    }
}
  1. 在Activity或者Fragment中生成对应的ViewModel
public class MyActivity extends AppCompatActivity {
    public void onCreate(Bundle savedInstanceState) {
        // Create a ViewModel the first time the system calls an activity's onCreate() method.
        // Re-created activities receive the same MyViewModel instance created by the first activity.
        MyViewModel model = ViewModelProviders.of(this).get(MyViewModel.class);
        model.getUsers().observe(this, users -> {
            // update UI
        });
    }
}

ViewModel的生命周期

这样即使Activity被重建了,通过ViewModelProviders得到的ViewModel对象还是第一个Activity创建的对象。而当Activity被销毁时,Framework会回调ViewModel对象的onCleared方法,以至于可以让我们在该方法内部进行资源清理,避免内存泄漏。

生命周期

ViewModel绝对不能引用View,LifeCycle或者任何一个引用了Activity的对象,否则可能会导致内存泄漏。如果ViewModel需要引用到Application的话,那么则需要使用AndroidViewModel对象。

在Fragment之间共享数据

通过同一个Activity获取到的ViewModel对象相同,所以可以通过ViewModelProvider获取到的ViewModel对象是同一个。而这么做的好处有:

  • Activity不需要做任何事情,或者不需要知道Fragment之间有什么交流
  • Fragment也不需要知道ViewModel相互之间的关系,一旦另外一个Fragment消失,另外一个也会运行正常。
  • 每个Fragment都有自己的生命周期,这样ViewModel不会被任何一个Fragment的周期干扰。一旦一个Fragment替换了另一个,那么UI也不会出问题
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.
        });
    }
}

参考资料

ViewModel Lifecycle Aware Data Loading with Architecture Components Jetpack

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏李蔚蓬的专栏

Content Provider 之 最终弹 实战体验跨程序数据共享(结合SQLiteDemo)

本模块共有四篇文章,参考郭神的《第一行代码》,对Content Provider的学习做一个详细的笔记,大家可以一起交流一下:

13140
来自专栏移动开发

Android开启StrictMode模式

StrictMode帮助我们侦测导致主线程阻塞的活动,如无意的在主线程执行磁盘访问或者网络调用,这对编写代码是很有帮助的. 下面的代码可以在debug模式下...

19920
来自专栏指尖下的Android

菜鸡的MVP架构漫谈

相信大家在网上看过关于MVP架构的博客数不胜数,至于MVP到底是什么,也不需要我再从百度百科复制一遍了,通俗的说MVP就是解决Model和View的耦合,没有使...

10120
来自专栏androidBlog

ARouter 使用教程

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/gdutxiaoxu/article/de...

40210
来自专栏緣來來來

安卓基础干货(四):安卓网络编程的学习

21510
来自专栏移动开发面面观

Android插件化——资源加载

17840
来自专栏双十二技术哥

Android AsyncLayoutInflater 限制及改进

上一篇文章中我们介绍了 AsyncLayoutInflater 的用法及源码实现,那么本文来分析下 AsyncLayoutInflater 使用的注意事项及改进...

35220
来自专栏Android干货

Android项目实战(三十四):蓝牙4.0 BLE 多设备连接

1.2K60
来自专栏Hellovass 的博客

动态生成分享图片

本文描述了如何实现该需求的思路,代码可能不通用,但是该思路应该可以解决很多类似的需求…

51030
来自专栏编程思想之路

Android6.0源码分析之蓝牙显示接收到的文件

在蓝牙界面有个menu:显示接收到的文件。本文分析显示接收到的文件 chapter one---显示接收到的文件 /android/packages/app...

25960

扫码关注云+社区

领取腾讯云代金券