赞
踩
经过几天的努力,终于把ViewModel和LiveData移植过来了,代码开源地址:
ViewModel和LiveData做安卓开发的小伙伴都很熟悉了,我就不过多介绍了,有了他们,我们可以实现MVVM框架,可以让系统自动管理数据的生命周期了,是安卓开发中不可获取的重要组件。笔者在移植网络的库的时候,需要用到这两个组件,所以移植了过来,代码是基于androidx.life.xxx的2.2.0版本移植而来。
鸿蒙中叫ILifecycle,用以感知生命周期,这个变量可以全局替换
Lifecycle EVENT安卓里和State是分开的,而鸿蒙里是合并了,发生了EVENT代表了置为了相应状态
- //摘录自己安卓的Lifecycle 类
- public enum Event {
- /**
- * Constant for onCreate event of the {@link LifecycleOwner}.
- */
- ON_CREATE,
- /**
- * Constant for onStart event of the {@link LifecycleOwner}.
- */
- ON_START,
- /**
- * Constant for onResume event of the {@link LifecycleOwner}.
- */
- ON_RESUME
-
- .....
- }
-
- public enum State {
- DESTROYED,
- INITIALIZED,
- .....
- RESUMED;
- }
- //摘录自Lifecycle类
- public static enum Event {
- UNDEFINED,
- ON_START,
- ON_INACTIVE,
- ON_ACTIVE,
- ON_BACKGROUND,
- ON_FOREGROUND,
- ON_STOP;
-
- private Event() {
- }
- }
所以原来的代码里有很多状态相关的类,都用鸿蒙的Event代替
修改了一个比较重要的函数 boolean shouldBeActive() ,数据是否继续分发,就是依赖于这个函数,具体看注释
- @Override
- boolean shouldBeActive() {
- //和安卓有所区别,安卓是Event和State分开的,而鸿蒙是放一起的,这里的本意是判断
- //页面是否是判断页面是否已经将要显示,或者已经显示,对应的安卓状态是started和resume
- //而鸿蒙里面对应的状态是 ON_ACTIVE
- return mOwner.getLifecycle().getLifecycleState()
- .compareTo(Lifecycle.Event.ON_ACTIVE) == 0;
- }
鸿蒙的生命周期状态少于安卓,但是基本能对应上,记住几个常用的:
安卓 : 鸿蒙
onCreate:on_start
onResume:on_active
onStart:on_active
onDestory:on_stop
移植的时候,放弃了SavedStateViewModelFactory,这个类的本意是创建的Factory存入Map,以便后面可以复用,由于代码比较复杂,所涉及的安卓库较多,放弃了移植,不过目前根据Demo看来,ViewModel和LiveData的功能都正常
LiveData做了一点修改,Observe的时候,在全局模式的时候,刚创建的Slice2在刚创建的时候会收到之前的Value更新的信息,这个也是安卓使用者,Activity对应多个Fragment中数据串扰的痛点所在,所以本库在保证原汁原味的安卓大部分的代码下,做了创新,多了一个observeNoStick接口,意思创建后,不接收过去的任何信息。避免共享的时候,数据串扰
安卓里面,之所以可以使用ViewModel和LiveData,是因为Activity和Fragment都继承了LifeCycleOwner,ViewModelStoreOwner和HasDefaultViewModelProviderFactory,而鸿蒙里面Ability和Slice只实现了ILifecycle,所以笔者参照Android的代码,自定义了CompatAbility,和CompatSlice,使用ViewModel和LiveData需要继承这两个基础类
- public class CompatSlice extends AbilitySlice implements
- ViewModelStoreOwner, HasDefaultViewModelProviderFactory {
- ......
- }
-
- public class CompatAbility extends Ability implements
- ViewModelStoreOwner, HasDefaultViewModelProviderFactory {
- ......
- }
因为鸿蒙里,使用了Ability为承载单元,Slice为子类单元(类似于谷歌推荐的一个Activity,多个Fragment的方式),所以主要验证这种场景下ViewModel和LiveData是否工作正常,先定义ViewModel的类,以及Model的数据类型,这里只简单打印日志
- public class NoteViewModel extends ViewModel {
-
- public MutableLiveData<List<NoteModel>> notes = new MutableLiveData<>();
-
- public void fetchNotes() {
- notes.setValue(NoteModel.fetchNotes());
- }
-
- public void fetchGlobalNotes() {
- notes.setValue(NoteModel.fetchGlobalNotes());
- }
- }
-
- //用法和Android一样,然后定义个辅助类,验证数据
-
- public class NoteModel {
- public String content;
- public String modifyTime;
-
- private NoteModel(String content, String modifyTime){
- this.content = content;
- this.modifyTime = modifyTime;
- }
-
- public static List<NoteModel> fetchNotes(){
- List<NoteModel> noteModels = new ArrayList<>();
- noteModels.add(new NoteModel("这是一个普通内容","2021-03-31"));
- return noteModels;
- }
-
- public static List<NoteModel> fetchGlobalNotes(){
- List<NoteModel> noteModels = new ArrayList<>();
- noteModels.add(new NoteModel("this is 全局Life","2021-08-31"));
- return noteModels;
- }
- }
然后定义两个Slice,可以相互切换,代码如下:
Slice1代码:
- //调用示例主要片段:
-
- public class LifeAbilitySlice extends CompatSlice {
- private static final String TAG = "LifeAbilitySlice";
- private NoteViewModel vm;
- private NoteViewModel globalVm;
-
- @Override
- protected void onStart(Intent intent) {
- super.onStart(intent);
- setUIContent(ResourceTable.Layout_life_request_layout);
- LifeAbilitySlice2 life2 = new LifeAbilitySlice2();
-
- findComponentById(ResourceTable.Id_btn_life).setClickedListener(component -> {
- vm.fetchNotes();
- });
-
- findComponentById(ResourceTable.Id_btn_life_global).setClickedListener(component -> {
- globalVm.fetchGlobalNotes();
- });
-
- findComponentById(ResourceTable.Id_btn_to_life2).setClickedListener(component -> {
- present(life2,new Intent());
- });
-
-
- initSliceViewModel();
- initGlobalViewModel();
- }
-
- //验证本Slice中的事件响应
- private void initSliceViewModel(){
- ViewModelProvider provider = ViewModelProviders.of(this);
- vm = provider.get(NoteViewModel.class);
- Log.d(TAG, "slice vm addr:" + vm);
-
- vm.notes.observe(this, noteModels -> {
- Log.d(TAG, "noteModels:" + noteModels.get(0).content);
- });
- }
-
- //验证基于所依赖的Ability的事件响应,经常出现的场景是多个Slice公有一个Ability的情况
- private void initGlobalViewModel(){
- ViewModelProvider globalProvider = ViewModelProviders.of((CompatAbility) getAbility());
- globalVm = globalProvider.get(NoteViewModel.class);
-
- Log.d(TAG, "global vm addr:" + globalVm);
-
- globalVm.notes.observe(this, noteModels -> {
- Log.d(TAG, "global noteModels:" + noteModels.get(0).content);
-
- });
- }
-
- }
Slice2的代码
- public class LifeAbilitySlice2 extends CompatSlice {
- private static final String TAG = "LifeAbilitySlice2";
- private NoteViewModel vm;
- private NoteViewModel globalVm;
-
- @Override
- protected void onStart(Intent intent) {
- super.onStart(intent);
- setUIContent(ResourceTable.Layout_life2_request_layout);
-
- findComponentById(ResourceTable.Id_btn_life).setClickedListener(component -> {
- vm.fetchNotes();
- });
-
- findComponentById(ResourceTable.Id_btn_life_global).setClickedListener(component -> {
- globalVm.fetchGlobalNotes();
- });
-
- initSliceViewModel();
- initGlobalViewModel();
- }
-
- private void initSliceViewModel(){
- ViewModelProvider provider = ViewModelProviders.of(this);
- vm = provider.get(NoteViewModel.class);
- Log.d(TAG, "slice vm addr:" + vm);
-
- vm.notes.observe(this, noteModels -> {
- Log.d(TAG, "noteModels:" + noteModels.get(0).content);
- appendtext(noteModels.get(0).content);
- });
- }
-
- private void initGlobalViewModel(){
- ViewModelProvider globalProvider = ViewModelProviders.of((CompatAbility) getAbility());
- globalVm = globalProvider.get(NoteViewModel.class);
-
- Log.d(TAG, "global vm addr:" + globalVm);
-
- globalVm.notes.observe(this, noteModels -> {
- Log.d(TAG, "observe global noteModels:" + noteModels.get(0).content);
- });
-
- globalVm.notes.observeNoSticky(this, noteModels -> {
- Log.d(TAG, "observeNoSticky global noteModels:" + noteModels.get(0).content);
- });
- }
- }
两个的代码基本一样,SLice1只比Slice2多了一个跳转Slice2的功能
我们要验证以下几个:
1)依赖于Slice生命周期的每次创建的对象,是新的对象
2)依赖于全局同一个Ability的生命周期,每次创建的ViewModel对象,是唯一的(只有一个实例)
3)Slice之间的消息不互相串扰,即SLice2和Slice1之间非全局消息互相不干扰
4)全局消息,粘粘(原来的模式)在Observe的消息可以收到,不论是创建之前还是之后的,非粘粘模式下,只收到Observe创建之后的消息
可以看到目前只起来了Slice1,并且分别点击了发送局部Llife事件,和发送全局Life事件,其实只有Slice1收到消息,当然,因为SIlce2还没被创建,然后我们点击跳转Slice2
可以看到发生三件事:
1)Slice1和Slice2的局部VIewModel,他们的地址是不同的,这符合要验证的第一点
2)SLice1和Slice的全局VIewModel(生命周期依赖于Ability)所具有的地址是一样,他们是一个对象,符合我们要验证的第二点
3)Slice2创建的时候,没收到了SLice1的局部事件,收到了全局事件,符合LiveData的粘粘模式,而非粘粘模式监听的没收到,这符合第三点
然后再次点击Slice2的发送全局事件的按钮,看log
此时,因为Slice1处于Inavtive状态,所以Slice的全局事件,它是收不到的,局部事件更不可能收到了,而因为Slice2处于Active状态了,所以他监听的两个全局事件(粘粘模式和非粘粘模式)都收到了事件,符合第四点预期
如果此时点击返回,那么的预想是,SLice1可以收到刚刚Slice2发送的全局事件,那么整个流程就通常了,我们返回看看:
符合预期4!
经过笔者多次的验证,目前的ViewModel已经可以完全正常工作,希望大家多多体验,可以看看笔者开源后的代码!
ViewModel_LiveData_for_ohoshttps://gitee.com/ethan-osc_admin/viewmodel_for_ohos#%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E移植完之后,有个和这个很相似的通讯库叫LiveEventBus,打算下来移植这个,估计还需要一段时间才能和大家见面
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。