Jetpack:如何管理界面相关的数据

栏目: IOS · Android · 发布时间: 5年前

内容简介:以注重生命周期的方式管理和界面相关的数据,Jetpack为我们带来了ViewModel,从本文你可以学习到使用ViewModel的正确姿势。ViewModel被用来以注重生命周期的方式来保存数据和管理界面相关的数据。同时可以在相关配置发生变化是保存数据,例如屏幕旋转。由于Android framework管理着像Activity、Fragment这样具有生命周期的UI控制器,所以在用户的某些操作或者系统分发的某些事件,会导致framework在没有经过我们控制下,销毁和重建UI控制器。例如,屏幕发生旋转时,

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

一、ViewModel

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

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

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

为此,使用ViewModel可以轻松解决以上问题。

1. 实现ViewModel

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

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中访问数据:

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。

2. ViewModel的生命周期

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

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

Jetpack:如何管理界面相关的数据
从图可以看出,在系统第一次调用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自动重新加载数据和更新用户界面:

Jetpack:如何管理界面相关的数据

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

Jetpack:如何管理界面相关的数据

其他更多信息可阅读官网

总结

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

Welcom to visit my github

Jetpack:如何管理界面相关的数据

本文是Jetpack系列文章第四篇

第一篇: Jetpack:你还在findViewById么

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

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


以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Java编程思想

Java编程思想

埃克尔 / 机械工业出版社 / 2007-5-1 / 79.00元

《Java编程思想(英文版•第4版)》内容简介:特色:1.适合初学者与专业人员的经典的面向对象的叙述方式;为更新的Java SE5/6的相关内容增加了新的示例和章节。2.测验框架显示程序输出。3.设计模式贯穿于众多示例中:适配器、桥接器、职责链、命令、装饰器、外观、工厂方法、享元、点名、数据传输对象、空对象、代理、单例、状态、策略、模板方法以及访问者。4.为数据传输引入了XML;为用户界面引入了S......一起来看看 《Java编程思想》 这本书的介绍吧!

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

XML 在线格式化
XML 在线格式化

在线 XML 格式化压缩工具