- MV-VM模式,日益在大前端设计占据主流,Android原生开发JetPack库,为此打造了一套基础设施API,并在此基础上打造一套完整的UI生态, 本文结合ViewModel、LiveData组合Fragment,完成一个基础的“基于数据驱动方式”应用系统。
重点:本文所做的全部努力是:如何pojo对象打造成为一个“响应式”对象,即数据(Model)的修改,将会直接更新视图(Model)
本案例完整代码见:https://gitee.com/johnyucn525/view-model-live-data-demo.git
完成图
一、pojo 如何变成“响应式对象”
- User对象
/**
* 一般的pojo对象,并不具备任何的"响应式特性",无法使用"数据驱动模式"
*/
public class User {
private String uname;
public String getUname() {
return uname;
}
public void setUname(String uname) {
this.uname = uname;
}
}
- 将User对象变成主题(Subject)
(1) 扮演 Subject 角色的类是: androidx.lifecycle.LiveData
,可以在【某个地方1】如下编码:
//...获取user对象的过程略
MutableLiveData<User> liveUser=new MutableLiveData<>();
liveUser.setValue(user);
此时liveUser,就是我们需要的主题(Subject)对象。
下面有两个问题没有解决:
- 如何注册观察者
- 如何保证此对象在UI控制器(即:Activity 和 Fragment ) 生存期中,保证可以随时使用一个“单例保活”的 LiveData。
(2)注册观察者:
在【某个地方 2】如下编码,完成将一个观察者(Observer)注册到 liveUser
liveUser.observe(LifecycleOwner, Observer)
LifecycleOwner
它可以Activity 或 Fragment 的实例。
Observer
是一个函数式接口,其可以使用 Lamda 完成,而Lamda 的参数就是 pojo 对象User,当我们在 【某个地方 3】对 liveUser 进行了修改时(liveUser.setValue(newUser)
),Observer 就会发生回调处理,在这个回调处理中,我们可以编写Model 和 View 的 Bind 逻辑,从而完成“数据驱动方式”编程。
(3) “单例保活”的 LiveData,获取方法
答案是: 使用 androidx.lifecycle.ViewModel
我们可以扩展一个自定义的 ViewModel 类,对LiveData进行包装,此时即为 【某个地方1】:
package cn.johnyu.a0428;
import androidx.lifecycle.MutableLiveData;
import androidx.lifecycle.ViewModel;
public class UserViewModel extends ViewModel {
// MV-VM中的 Model 就在此处
private MutableLiveData<User> liveUser=new MutableLiveData<>();
//此Api调用时,将会通知给Observer
public void setUser(User user){
liveUser.setValue(user);
}
//调用此API,获取LiveData,并注册观察者
public MutableLiveData<User> getUser(){
return liveUser;
}
}
随后在Activity或Fragment的生命周期方法中(一般会是onCreateView),使用工厂方法(注意不能是new方法)获取ViewModel对象,此方法会缓存ViewModel对象,即:只有第一次才进行实例化的工作,以后每次只是获取同一个单例对象,此对象只有在相应的Activity或Fragment销毁时才销毁;本例,此方法会在消息发布和消息订阅的两个Fragment中进行调用,而获取的是一个与MainActivity相关联的ViewModel
- 在ListFragment中:
//消息发布的Fragment
public class ListFragment extends Fragment {
private UserViewModel userViewModel;
public ListFragment() {
super(R.layout.fragment_list);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view,savedInstanceState);
//跟随MainActivity的单例模式的ViewModel,在Activity的Destroy后,自动调用ViewModel的onDestroy进行数据的清理
userViewModel =new ViewModelProvider(requireActivity()).get(UserViewModel.class);
//其它代码.....
- 在DetailFragment中:
//消息订阅的Fragment
public class DetailFragment extends Fragment {
private UserViewModel userViewModel;
private TextView textView;
public DetailFragment() {
super(R.layout.fragment_detail);
}
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
textView=view.findViewById(R.id.uname);
//此处获取的是同一个与MainActivity相关的ViewModel
userViewModel =new ViewModelProvider(requireActivity()).get(UserViewModel.class);
//其它代码。。。
现在我们就可以利用这个“保活”的ViewModel来获取“保活”的LiveData了,即:我们把pojo通过层层包装变成了“响应式对象”了。
二、响应式对象的使用:
在ListFragment中修改主题,完成消息发布【某个地方 3】:
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view,savedInstanceState);
//跟随MainActivity的单例模式的ViewModel,在Activity的Destroy后,自动调用ViewModel的onDestroy进行数据的清理
userViewModel =new ViewModelProvider(requireActivity()).get(UserViewModel.class);
//其它代码...
//为"详细信息"按钮添加事件处理器
view.findViewById(R.id.detailBtn).setOnClickListener(event->{
User user=new User();
user.setUname("john"+Math.random());
//消息发布:即,修改主题(向主题的所有观察者发布消息)
userViewModel.setUser(user);
});
}
在DetailFragment中订阅主题,并完成回调修改视图【某个地方 2】:
@Override
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
textView=view.findViewById(R.id.uname);
//此处获取的是同一个与MainActivity相关的ViewModel
userViewModel =new ViewModelProvider(requireActivity()).get(UserViewModel.class);
//其它代码。。。
//订阅主题,完成回调修改视图,完成了数据与视图的绑定工作,以后只要user进行了修改,回调会自动进行
userViewModel.getUser().observe(getViewLifecycleOwner(), user -> {
textView.setText(user.getUname());
});
}
网友评论