Jetpack:ViewModel来拯救臃肿的Activity or Fragment

以注重生命周期的方式管理和界面相关的数据,Jetpack为咱们带来了ViewModel,从本文你能够学习到使用ViewModel的正确姿式。java

1、ViewModel

ViewModel被用来以注重生命周期的方式来保存数据和管理界面相关的数据。同时能够在相关配置发生变化是保存数据,例如屏幕旋转。android

因为Android framework管理着像Activity、Fragment这样具备生命周期的UI控制器,因此在用户的某些操做或者系统分发的某些事件,会致使framework在没有通过咱们控制下,销毁和重建UI控制器。例如,屏幕发生旋转时,framwork会调用Activity的onSaveIntanceState()保存数据,在新Activity的onCreate()方法中恢复这些数据,不过这仅仅是恢复可序列化和反序列化的小数据上,像list或者bitmap这种大数据就不合适了。此外,也会致使大量已经存在的数据被销毁,而后从新生成,形成资源的浪费。git

LiveData也说到,不要在Activity和Fragment作大量的逻辑操做,会致使代码臃肿,难以维护,建议把相关逻辑抽到单独的类进行维护,让UI控制器负责它们的本质工做。github

为此,使用ViewModel能够轻松解决以上问题。数据库

1. 实现ViewModel

Architecture Components提供ViewModel工具类,用来为UI提供数据。ViewModel对象在配置发生变化时会自动保存数据,而且会在新建的Activity或Fragment实例使用。例如,在APP中须要显示持有多个user对象的list,应该将请求和保存users数据的动做在ViewModel对象实现,而不是Activity或Fragment。api

class MyViewModel : ViewModel() {
    private val users: MutableLiveData<List<User>> by lazy {
        MutableLiveData().also {
            loadUsers()
        }
    }

    fun getUsers(): LiveData<List<User>> {
        return users
    }

    private fun loadUsers() {
        // Do an asynchronous operation to fetch users.
    }
}
复制代码

在Activity中访问数据:bash

class MyActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        // 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.
        val model = ViewModelProviders.of(this).get(MyViewModel::class.java)
        model.getUsers().observe(this, Observer<List<User>>{ users ->
            // update UI
        })
    }
}
复制代码

当Activity被重建时,它会接收到来自第一个Activity的ViewModel对象,因此数据不会发生变化。当Activity销毁后,framework会自动调用ViewModel对象的onCleared()方法来进行释放资源。记得,ViewModel必定不要持有View、Lifecycle或者任何有Activity context对象的引用。由于ViewModel的生命周期比它们的长,会致使内存泄漏。若是ViewModel须要持有应用的conetxt,例如用来获取系统服务,能够继承AndroidViewModel类,在它的构造方法中对接收应用的context。架构

若是Android Studio找不到ViewModelProviders,添加下面依赖哦。async

api "android.arch.lifecycle:extensions:1.1.1"
复制代码

2. ViewModel的生命周期

ViewModelProvider获取ViewModel对象时,ViewModel的生命周期做用域会传递给ViewModelProvider,ViewModel会一直保持在内存中,直到其生命周期做用域失效。在下面两种状况,ViewModel对象生命周期会失效:一种是Activity对象finished,一种是Fragment对象detached。ide

下图(图来自官网)显示了Activity的生命周期和ViewModel的做用域,第一列显示了Activity对象的状态,第二列显示Activity生命周期方法,第三列ViewModel的做用域。

从图能够看出,在系统第一次调用Activity对象的 onCreate()方法,咱们一般要在第一次时间建立ViewModel对象。在Activity对象的生命周期内, onCreate()方法可能因为系统配置改变而被系统调用屡次,而ViewModel对象只有一次,ViewModel对象会一直存在直到Activity被终结和销毁掉。

3. 在Fragment之间共享数据

在实际开发中,常常会在两个或多个fragement对象共享数据,一般作法是实定义接口,由Activity绑定在fragment中。此外,Activity还要处理fragment的建立和可见的状况。

fragment之间能够在Activity的做用域内共享同个ViewModel对象来处理这个麻烦的数据交互问题。例如:

class SharedViewModel : ViewModel() {
    val selected = MutableLiveData<Item>()

    fun select(item: Item) {
        selected.value = item
    }
}

class MasterFragment : Fragment() {

    private lateinit var itemSelector: Selector

    private lateinit var model: SharedViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        model = activity?.run {
            ViewModelProviders.of(this).get(SharedViewModel::class.java)
        } ?: throw Exception("Invalid Activity")
        itemSelector.setOnClickListener { item ->
            // Update the UI
        }
    }
}

class DetailFragment : Fragment() {

    private lateinit var model: SharedViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        model = activity?.run {
            ViewModelProviders.of(this).get(SharedViewModel::class.java)
        } ?: throw Exception("Invalid Activity")
        model.selected.observe(this, Observer<Item> { item ->
            // Update the UI
        })
    }
}
复制代码

因为两个Fragment对象绑定在同一个Activity对象,它们经过ViewModelProvider获取在Activity范围内的同一个ViewModel对象。

这样作的好处是:

  • Activity对象不会感知两个Fragment对象的交互,因此也不用作任何事。
  • Fragment对象不须要知道另一个Fragment对象,除了和ViewModel的约定。当一个对象消失,另一个对象还能正常使用。
  • Fragment对象的生命周期不受其余的对象影响,一个Fragment对象替换另外一个,UI还能正常运行。

4. ViewModel替代Loader

加载器类像CursorLoader,常常用来保持UI中的数据与数据库的同步。能够经过ViewModel,和其余的类,替换Loader类。使用ViewModel分离UI控制器的数据加载动做,意味着能够减小更多的类强引用。 使用Loader一个常见的方法,就是在应用程序中使用一个CursorLoader观察的数据库内容,当数据库的值发生变化时,Loader自动从新加载数据和更新用户界面:

使用ViewModel,并和Room或LiveData一块儿代替Loader。ViewModel对象在配置发生变化是保持数据,而Room通知LiveData数据库数据改变,LiveData则将修改后的数据更新到UI上。

其余更多信息可阅读官网

总结

Jetpack讲到这里,基本都明白Jetpack是干吗了,Jetpack总结咱们日常开发的各类效率和架构,为咱们提供更标准的组件。Room操做数据库,LiveData通知数据更改,DataBinding更新View,Lifecycle管理周期,及其后面要讲的其余组件。都在给咱们应用层开发定义一套统一开发架构标准,以即可以开发更好APP。经过这么一套架构组件,能够快速开发可维护性高,扩展性好的APP。

Welcom to visit my github

本文是Jetpack系列文章第四篇

第一篇: Jetpack:你还在findViewById么

第二篇:Jetpack:你如何管理Activity和Fragment的生命周期

第三篇:Jetpack:在数据变化时如何优雅更新Views数据

相关文章
相关标签/搜索