android view架构,ViewModel 概览

ViewModel 概览

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

注意:如需将 ViewModel导入 Android 项目,请参阅 Lifecycle 版本说明中关于声明依赖项的说明。

Android 框架可以管理界面控制器(如 Activity 和 Fragment)的生命周期。Android 框架可能会决定销毁或重新创建界面控制器,以响应完全不受您控制的某些用户操作或设备事件。

如果系统销毁或重新创建界面控制器,则存储在其中的任何瞬态界面相关数据都会丢失。例如,应用可能会在它的某个 Activity 中包含用户列表。为配置更改重新创建 Activity 后,新 Activity 必须重新提取用户列表。对于简单的数据,Activity 可以使用

另一个问题是,界面控制器经常需要进行可能需要一些时间才能返回的异步调用。界面控制器需要管理这些调用,并确保系统在其销毁后清理这些调用以避免潜在的内存泄漏。此项管理需要大量的维护工作,并且在为配置更改重新创建对象的情况下,会造成资源的浪费,因为对象可能需要重新发出已经发出过的调用。

诸如 Activity 和 Fragment 之类的界面控制器主要用于显示界面数据、对用户操作做出响应或处理操作系统通信(如权限请求)。如果要求界面控制器也负责从数据库或网络加载数据,那么会使类越发膨胀。为界面控制器分配过多的责任可能会导致单个类尝试自己处理应用的所有工作,而不是将工作委托给其他类。以这种方式为界面控制器分配过多的责任也会大大增加测试的难度。

从界面控制器逻辑中分离出视图数据所有权的操作更容易且更高效。

实现 ViewModel

架构组件为界面控制器提供了 ViewModel 辅助程序类,该类负责为界面准备数据。在配置更改期间会自动保留 ViewModel 对象,以便它们存储的数据立即可供下一个 Activity 或 Fragment 实例使用。例如,如果您需要在应用中显示用户列表,请确保将获取和保留该用户列表的责任分配给 ViewModel,而不是 Activity 或 Fragment,如以下示例代码所示:

Kotlin

class MyViewModel : ViewModel() {

private val users: MutableLiveData> by lazy {

MutableLiveData>().also {

loadUsers()

}

}

fun getUsers(): LiveData> {

return users

}

private fun loadUsers() {

// Do an asynchronous operation to fetch users.

}

}Java

public class MyViewModel extends ViewModel {

private MutableLiveData> users;

public LiveData> getUsers() {

if (users == null) {

users = new MutableLiveData>();

loadUsers();

}

return users;

}

private void loadUsers() {

// Do an asynchronous operation to fetch users.

}

}

然后,您可以从 Activity 访问该列表,如下所示:

Kotlin

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.

// Use the 'by viewModels()' Kotlin property delegate

// from the activity-ktx artifact

val model: MyViewModel by viewModels()

model.getUsers().observe(this, Observer>{ users ->

// update UI

})

}

}Java

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 = new ViewModelProvider(this).get(MyViewModel.class);

model.getUsers().observe(this, users -> {

// update UI

});

}

}

如果重新创建了该 Activity,它接收的 MyViewModel 实例与第一个 Activity 创建的实例相同。当所有者 Activity 完成时,框架会调用 ViewModel 对象的 onCleared() 方法,以便它可以清理资源。

注意:ViewModel 绝不能引用视图、Lifecycle 或可能存储对 Activity 上下文的引用的任何类。

ViewModel 的生命周期

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

图 1 说明了 Activity 经历屏幕旋转而后结束时所处的各种生命周期状态。该图还在关联的 Activity 生命周期的旁边显示了 ViewModel 的生命周期。此图表说明了 Activity 的各种状态。这些基本状态同样适用于 Fragment 的生命周期。

9a65d42f8102c0aa36d8894d392b0740.png

您通常在系统首次调用 Activity 对象的 ViewModel。系统可能会在 Activity 的整个生命周期内多次调用 ViewModel 存在的时间范围是从您首次请求 ViewModel 直到 Activity 完成并销毁。

在 Fragment 之间共享数据

Activity 中的两个或更多 Fragment 需要相互通信是一种很常见的现象。想象一下拆分视图 (master-detail) Fragment 的常见情况,假设您有一个 Fragment,在该 Fragment 中,用户从列表中选择一项,还有另一个 Fragment,用于显示选定项的内容。这种情况不太容易处理,因为这两个 Fragment 都需要定义某种接口描述,并且所有者 Activity 必须将两者绑定在一起。此外,这两个 Fragment 都必须处理另一个 Fragment 尚未创建或不可见的情况。

可以使用 ViewModel 对象解决这一常见的难点。这两个 Fragment 可以使用其 Activity 范围共享 ViewModel 来处理此类通信,如以下示例代码所示:

Kotlin

class SharedViewModel : ViewModel() {

val selected = MutableLiveData()

fun select(item: Item) {

selected.value = item

}

}

class MasterFragment : Fragment() {

private lateinit var itemSelector: Selector

// Use the 'by activityViewModels()' Kotlin property delegate

// from the fragment-ktx artifact

private val model: SharedViewModel by activityViewModels()

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

super.onViewCreated(view, savedInstanceState)

itemSelector.setOnClickListener { item ->

// Update the UI

}

}

}

class DetailFragment : Fragment() {

// Use the 'by activityViewModels()' Kotlin property delegate

// from the fragment-ktx artifact

private val model: SharedViewModel by activityViewModels()

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {

super.onViewCreated(view, savedInstanceState)

model.selected.observe(viewLifecycleOwner, Observer { item ->

// Update the UI

})

}

}Java

public class SharedViewModel extends ViewModel {

private final MutableLiveData selected = new MutableLiveData();

public void select(Item item) {

selected.setValue(item);

}

public LiveData getSelected() {

return selected;

}

}

public class MasterFragment extends Fragment {

private SharedViewModel model;

public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {

super.onViewCreated(view, savedInstanceState);

model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);

itemSelector.setOnClickListener(item -> {

model.select(item);

});

}

}

public class DetailFragment extends Fragment {

public void onViewCreated(@NonNull View view, Bundle savedInstanceState) {

super.onViewCreated(view, savedInstanceState);

SharedViewModel model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);

model.getSelected().observe(getViewLifecycleOwner(), item -> {

// Update the UI.

});

}

}

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

此方法具有以下优势:

Activity 不需要执行任何操作,也不需要对此通信有任何了解。

除了 SharedViewModel 约定之外,Fragment 不需要相互了解。如果其中一个 Fragment 消失,另一个 Fragment 将继续照常工作。

每个 Fragment 都有自己的生命周期,而不受另一个 Fragment 的生命周期的影响。如果一个 Fragment 替换另一个 Fragment,界面将继续工作而没有任何问题。

将加载器替换为 ViewModel

ViewModel 与一些其他类一起使用来替换加载器。使用 ViewModel 可将界面控制器与数据加载操作分离,这意味着类之间的强引用更少。

在使用加载器的一种常见方法中,应用可能会使用

005bddd971b596ef6fb5f7c75cc9e46f.png

图 2. 使用加载器加载数据

ViewModel 与 Room 和 LiveData 一起使用可替换加载器。ViewModel 确保数据在设备配置更改后仍然存在。Room 在数据库发生更改时通知 LiveData,LiveData 进而使用修订后的数据更新界面。

2d5a6c81b107b169b5d4f1f981529267.png

图 3. 使用 ViewModel 加载数据

将协程与 ViewModel 一起使用

ViewModel 支持 Kotlin 协程。如需了解详情,请参阅将 Kotlin 协程与 Android 架构组件一起使用。

更多信息

随着数据变得越来越复杂,您可能会选择使用单独的类加载数据。ViewModel 的用途是封装界面控制器的数据,以使数据在配置更改后仍然存在。如需了解如何在配置更改后加载、保留和管理数据,请参阅保存界面状态。

Android 应用架构指南建议构建存储区类来处理这些功能。

其他资源

如需详细了解 ViewModel 类,请参阅以下资源。

示例

Sunflower,这是一款园艺应用,展示了使用 Android Jetpack 进行 Android 开发的最佳做法。

Codelab

博客

视频

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Android Jetpack是Google提供的一套用于加速Android应用开发的工具包,其中包括了许多架构组件,其中之一就是ViewModelViewModel是一种设计模式,用于保存和管理与UI相关的数据。在传统的Android开发中,当屏幕旋转或者因为其他原因导致Activity或Fragment重建时,之前保存的临时数据就会丢失。而ViewModel的出现解决了这个问题。 ViewModel的主要作用是将数据与UI组件分离。它的工作方式是创建一个ViewModel类,并在其中保存需要与UI组件交互的数据。这样,当屏幕旋转或重建时,ViewModel实例不会销毁,数据也会得到保留。然后,在Activity或Fragment中,通过获取ViewModel实例,可以轻松地访问这些数据。 使用ViewModel的好处有很多。首先,它可以避免内存泄漏,因为ViewModel的生命周期与Activity或Fragment无关。其次,它可以节省资源,因为当Activity或Fragment销毁时,ViewModel实例可以被系统缓存起来,下次再创建时可以直接返回该实例。另外,由于ViewModel保存了与UI相关的数据,可以减少因为屏幕旋转导致的数据重复加载的问题。 在使用ViewModel时,你可以选择使用Android Jetpack中的其他架构组件来进一步提高开发效率,比如通过LiveData实现数据的观察和通知,或者通过DataBinding来实现UI与数据的自动绑定。 总之,ViewModelAndroid Jetpack中非常重要的一个架构组件,它的出现实现了数据与UI的解耦,提高了开发效率,并且解决了数据丢失的问题。希望通过这篇文档的详解,你对ViewModel有了更深入的理解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值