Android架构组件:ViewMode概述
作⽤:
ViewModel 类旨在以注重⽣命周期的⽅式存储和管理界⾯相关的数据。
问题:
(1) Android 框架可以管理界⾯控制器(如 Activity, Fragment)的⽣命周期。由Android 框架响应的某些⽤户操作或设备事件,⽤户⽆法控制。
当系统销毁或重新创建界⾯控制器,则存储在其中的任何临时性界⾯相关数据都会丢失。对于简单的数据,Activity可以使⽤onSaveInstanceState()存储数据,组件重建后从onCreate()中的Bundle恢复其数据,但此⽅法仅适合可以序列化再反序列化的(2)界⾯控制器经常需要进⾏异步调⽤,这些调⽤可能需要⼀些时间才能返回结果,有可能会出现UI组件已销毁,⽽请求还未返回的情况。在因配置更改⽽重新创建对象的情况下,对象可能需要重新发送请求,会造成资源的浪费
(3)应该遵循职责分离原则,将视图数据从界⾯控制器逻辑中分离出来,这样不会导致界⾯控制器类代码膨胀
ViewModel的⽤法:
架构组件为界⾯控制器提供了 ViewModel 辅助程序类,该类负责为界⾯准备数据。
在配置更改期间会⾃动保留 ViewModel 对象,以便它们存储的数据⽴即可供下⼀个Activity/Fragment实例使⽤。如以下⽰例代码所⽰:
view 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.
}
}
可以从 Activity 访问该列表
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);
/
/ update UI
});
}
}
如果Activity被重新创建了,它会收到被之前Activity创建的相同MyViewModel实例。当所属Activity终⽌后,框架调⽤ViewModel的onCleared()⽅法清除资源。
因为ViewModel在指定的Activity或Fragment实例外存活,它应该永远不能引⽤⼀个View,或持有任何包含Activity context引⽤的类。如果ViewModel需要Application的context(如获取系统服务),可以扩展AndroidViewmodel,并拥有⼀个构造器接ViewModel 的⽣命周期
ViewModel 对象存在的时间范围是获取ViewModel时传递给ViewModelProvider的Lifecycle。ViewModel将⼀直留在内存中,直到限定其存在时间范围的Lifecycle 永久消失:对
于 Activity,是在Activity完成时;⽽对于Fragment,是在Fragment分离时。
上图左侧为Activity的⽣命周期过程,期间有⼀个旋转屏幕的操作;右侧则为ViewModel的⽣命周期过程。
⼀般通过如下代码初始化ViewModel:
viewModel = ViewModelProviders.of(this).get(UserProfileViewModel.class);
// this参数⼀般为Activity或Fragment,因此ViewModelProvider可以获取组件的⽣命周期。
Activity在⽣命周期中可能会触发多次onCreate(),⽽ViewModel则只会在第⼀次onCreate()时创建,然后直到最后Activity销毁。
在Fragment间共享数据
⼀个Activity中的多个Fragment相互通讯是很常见的。假设有⼀个Fragment,在该Fragment 中,⽤户从列表中选择⼀项,还有另⼀个Fragment,⽤于显⽰选定项的内容。这种情
况不太容易处理,因为这两个 Fragment都需要定义某种接⼝描述,并且所有者Activity必须将两者绑定在⼀起。此外,这两个 Fragment 都必须处理另⼀个Fragment尚未创建或
不可见的情况。
可以使⽤ ViewModel 对象解决这⼀常见的难点。这两个Fragment可以使⽤其 Activity 范围共享 ViewModel 来处理此类通信,如以下⽰例代码所⽰:
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) {
model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
itemSelector.setOnClickListener(item -> {
model.select(item);
});
}
}
public class DetailFragment extends Fragment {
public void onCreate(Bundle savedInstanceState) {
SharedViewModel model = ViewModelProviders.of(getActivity()).get(SharedViewModel.class);
// Update the UI.
});
}
}
注意:这两个Fragment都会检索包含它们的Activity。这样,当这两个Fragment各⾃获取ViewModelProvider时,它们会收到相同的SharedViewModel实例(其范围限定为该
Activity)。
此⽅法具有以下优势:
* Activity 不需要执⾏任何操作,也不需要对此通信有任何了解。
* 除了SharedViewModel约定之外,Fragment不需要相互了解。如果其中⼀个Fragment 消失,另⼀个Fragment将继续照常⼯作。
* 每个Fragment 都有⾃⼰的⽣命周期,⽽不受另⼀个Fragment的⽣命周期的影响。如果⼀个Fragment替换另⼀个Fragment,界⾯将继续⼯作⽽没有任何问题。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论