ViewModel

一、ViewModel要解决的问题

在ViewModel出现之前,无论是MVP、MVC还是MVVM,我们都需要自己处理数据的状态保存问题。因为展示给用户的页面(Activity、Fragment)随时可能会被系统销毁,比如用户旋转手机屏幕或者手机内存不足等等。等页面重建时,我们需要重新获取数据进行展示。对于简单的数据,我们可以通过使用onSaveInstanceState()来恢复,而不适合大量的列表数据。同时,我们获取数据通常时异步请求的,如果这些调用返回前,发生了销毁。我们需要进行额外的取消清理工作,防止内存泄漏。
这些逻辑的处理往往繁琐并且重复,所以Google官方推出了ViewModel来解决这个问题。ViewModel负责为界面准备数据,并在更改配置期间自动保留ViewMode对象,以便它们存储的数据立即可供下一个Activity或Fragment实例使用。

二、实现ViewModel

class MyViewModel : ViewModel {
    private val users: MutableLiveData> by lazy {
        MutableLiveData().alse {
            loadUsers()
        }
    }

    fun getUsers(): LiveData> {
        return users
    }

    private fun loadUsers() {
        // Do an asynchronous operation to fetch users
    }
}
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)[MyViewModel::class.java]
        model.getusers().observe(this, Observer>{ users ->
            // update UI
        })
    }
}

如果重新创建了该Activity,它接收的 MyViewModel 实例与第一个 Activity 创建的实例相同。当所有者Activity销毁时,框架会调用ViewModel的onCleared()方法,以便它可以清理资源。
ViewModel对象存在的时间比视图或LifecycleOwners的特定实例存在的时间更长。这还意味着,您可以更轻松地编写覆盖ViewModel的测试,因为它不了解视图和Lifecycle对象。ViewModel对象可以包含LifecycleObservers,如LiveData对象。但是,ViewModel对象绝不能观察对生命周期感知型可观测对象(如LiveData对象)的更改。如果ViewModel需要Application上下文(例如,为了查找系统服务),它可以扩展AndroidViewModel类并设置用于接收Application的构造函数,因为Application类会扩展Context。

三、ViewModel的生命周期

ViewModel对象存在的时间范围是获取ViewModel时传给ViewModelProvider的Lifecycle。ViewModel将一直停留在内存中,直到限定其存在时间范围的Lifecycle永久消失:对于Activity,是在Activity Finish的时候。对于Fragment,是在Fragment Destroy的时候。

image.png

您通常在系统首次调用Activity对象的onCreate()方法时请求ViewModel。系统可能会在Activity的整个生命周期内多次调用onCreate(),如在旋转设备时。ViewModel存在的时间范围是从您首次请求ViewModel直到Activity完成并销毁。

四、在Fragment之间共享数据

Activity中的两个或更多Fragment需要互相通信时一种很常见的情况。想象一下主从Fragment的常见情况,假设您有一个Fragment,在该Fragment中,用户从列表中选择一项,还有另一个Fragment,用于显式选定的内容。这种情况不太容易处理,因为这两个Fragment都需要定义某种接口描述,并且所有者Activity必须将两者绑定在一起。此外,这两个Fragment都必须处理另一个Fragment尚未创建或不可见的情况。
可以使用ViewModel对象解决这一常见的难点。这两个Fragment可以使用其Activity范围共享ViewModel来处理此类通信,如以下示例代码所示:

Class SharedViewModel : ViewModel() {
    val selected = MutableLiveData()

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

class MasterFragment :  Fragment() {
    private lateinit var itemSelector : Selector
    private lateinit var model : ShareViewModel

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        model = activity?.run {
            ViewModelProviders.of(this)[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)[SharedViewModel::class.java]
            } ?: throw Exception("Invalid Activity")
            model.selected.observe(this, Observer {
                // Update the UI
            })
        }
    }
}

请注意,这两个Fragment都会检索包含它们的Activity。这样,当两个Fragment各自获取ViewModelProvider时,它们会收到相同的ShardedViewModel实例(其范围限定为该Acitivity)
此方法具有以下优势:

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

1、Android ViewModel,再学不会你砍我

你可能感兴趣的:(ViewModel)