当前位置:   article > 正文

安卓应用移植鸿蒙(四):移植Android的ViewModel和LiveData_鸿蒙开发者工具导入android应用

鸿蒙开发者工具导入android应用

经过几天的努力,终于把ViewModel和LiveData移植过来了,代码开源地址:

ViewModel_LiveData_for_ohoshttps://gitee.com/ethan-osc_admin/viewmodel_for_ohosicon-default.png?t=L892https://gitee.com/ethan-osc_admin/viewmodel_for_ohos

一.基本介绍

        ViewModel和LiveData做安卓开发的小伙伴都很熟悉了,我就不过多介绍了,有了他们,我们可以实现MVVM框架,可以让系统自动管理数据的生命周期了,是安卓开发中不可获取的重要组件。笔者在移植网络的库的时候,需要用到这两个组件,所以移植了过来,代码是基于androidx.life.xxx的2.2.0版本移植而来。

二.基本修改点

1.安卓中的LifeCycleOwner

鸿蒙中叫ILifecycle,用以感知生命周期,这个变量可以全局替换

2.Lifecycle

Lifecycle EVENT安卓里和State是分开的,而鸿蒙里是合并了,发生了EVENT代表了置为了相应状态

  1. //摘录自己安卓的Lifecycle 类
  2. public enum Event {
  3. /**
  4. * Constant for onCreate event of the {@link LifecycleOwner}.
  5. */
  6. ON_CREATE,
  7. /**
  8. * Constant for onStart event of the {@link LifecycleOwner}.
  9. */
  10. ON_START,
  11. /**
  12. * Constant for onResume event of the {@link LifecycleOwner}.
  13. */
  14. ON_RESUME
  15. .....
  16. }
  17. public enum State {
  18. DESTROYED,
  19. INITIALIZED,
  20. .....
  21. RESUMED;
  22. }
  1. //摘录自Lifecycle类
  2. public static enum Event {
  3. UNDEFINED,
  4. ON_START,
  5. ON_INACTIVE,
  6. ON_ACTIVE,
  7. ON_BACKGROUND,
  8. ON_FOREGROUND,
  9. ON_STOP;
  10. private Event() {
  11. }
  12. }

所以原来的代码里有很多状态相关的类,都用鸿蒙的Event代替

3.boolean shouldBeActive()

修改了一个比较重要的函数 boolean shouldBeActive() ,数据是否继续分发,就是依赖于这个函数,具体看注释

  1. @Override
  2. boolean shouldBeActive() {
  3. //和安卓有所区别,安卓是Event和State分开的,而鸿蒙是放一起的,这里的本意是判断
  4. //页面是否是判断页面是否已经将要显示,或者已经显示,对应的安卓状态是started和resume
  5. //而鸿蒙里面对应的状态是 ON_ACTIVE
  6. return mOwner.getLifecycle().getLifecycleState()
  7. .compareTo(Lifecycle.Event.ON_ACTIVE) == 0;
  8. }

4.安卓和鸿蒙的基础单元的生命周期

鸿蒙的生命周期状态少于安卓,但是基本能对应上,记住几个常用的:

安卓 : 鸿蒙

onCreate:on_start

onResume:on_active

onStart:on_active

onDestory:on_stop

5.SavedStateViewModelFactory

移植的时候,放弃了SavedStateViewModelFactory,这个类的本意是创建的Factory存入Map,以便后面可以复用,由于代码比较复杂,所涉及的安卓库较多,放弃了移植,不过目前根据Demo看来,ViewModel和LiveData的功能都正常

6.增加非粘粘模式(NoStick)

LiveData做了一点修改,Observe的时候,在全局模式的时候,刚创建的Slice2在刚创建的时候会收到之前的Value更新的信息,这个也是安卓使用者,Activity对应多个Fragment中数据串扰的痛点所在,所以本库在保证原汁原味的安卓大部分的代码下,做了创新,多了一个observeNoStick接口,意思创建后,不接收过去的任何信息。避免共享的时候,数据串扰

三.如果使用鸿蒙里的ViewModel

1.集成和AppCompatActivity以及Fragment一样的类

安卓里面,之所以可以使用ViewModel和LiveData,是因为Activity和Fragment都继承了LifeCycleOwner,ViewModelStoreOwner和HasDefaultViewModelProviderFactory,而鸿蒙里面Ability和Slice只实现了ILifecycle,所以笔者参照Android的代码,自定义了CompatAbility,和CompatSlice,使用ViewModel和LiveData需要继承这两个基础类

  1. public class CompatSlice extends AbilitySlice implements
  2. ViewModelStoreOwner, HasDefaultViewModelProviderFactory {
  3. ......
  4. }
  5. public class CompatAbility extends Ability implements
  6. ViewModelStoreOwner, HasDefaultViewModelProviderFactory {
  7. ......
  8. }

2.举个例子

因为鸿蒙里,使用了Ability为承载单元,Slice为子类单元(类似于谷歌推荐的一个Activity,多个Fragment的方式),所以主要验证这种场景下ViewModel和LiveData是否工作正常,先定义ViewModel的类,以及Model的数据类型,这里只简单打印日志

  1. public class NoteViewModel extends ViewModel {
  2. public MutableLiveData<List<NoteModel>> notes = new MutableLiveData<>();
  3. public void fetchNotes() {
  4. notes.setValue(NoteModel.fetchNotes());
  5. }
  6. public void fetchGlobalNotes() {
  7. notes.setValue(NoteModel.fetchGlobalNotes());
  8. }
  9. }
  10. //用法和Android一样,然后定义个辅助类,验证数据
  11. public class NoteModel {
  12. public String content;
  13. public String modifyTime;
  14. private NoteModel(String content, String modifyTime){
  15. this.content = content;
  16. this.modifyTime = modifyTime;
  17. }
  18. public static List<NoteModel> fetchNotes(){
  19. List<NoteModel> noteModels = new ArrayList<>();
  20. noteModels.add(new NoteModel("这是一个普通内容","2021-03-31"));
  21. return noteModels;
  22. }
  23. public static List<NoteModel> fetchGlobalNotes(){
  24. List<NoteModel> noteModels = new ArrayList<>();
  25. noteModels.add(new NoteModel("this is 全局Life","2021-08-31"));
  26. return noteModels;
  27. }
  28. }

然后定义两个Slice,可以相互切换,代码如下:

Slice1代码:

  1. //调用示例主要片段:
  2. public class LifeAbilitySlice extends CompatSlice {
  3. private static final String TAG = "LifeAbilitySlice";
  4. private NoteViewModel vm;
  5. private NoteViewModel globalVm;
  6. @Override
  7. protected void onStart(Intent intent) {
  8. super.onStart(intent);
  9. setUIContent(ResourceTable.Layout_life_request_layout);
  10. LifeAbilitySlice2 life2 = new LifeAbilitySlice2();
  11. findComponentById(ResourceTable.Id_btn_life).setClickedListener(component -> {
  12. vm.fetchNotes();
  13. });
  14. findComponentById(ResourceTable.Id_btn_life_global).setClickedListener(component -> {
  15. globalVm.fetchGlobalNotes();
  16. });
  17. findComponentById(ResourceTable.Id_btn_to_life2).setClickedListener(component -> {
  18. present(life2,new Intent());
  19. });
  20. initSliceViewModel();
  21. initGlobalViewModel();
  22. }
  23. //验证本Slice中的事件响应
  24. private void initSliceViewModel(){
  25. ViewModelProvider provider = ViewModelProviders.of(this);
  26. vm = provider.get(NoteViewModel.class);
  27. Log.d(TAG, "slice vm addr:" + vm);
  28. vm.notes.observe(this, noteModels -> {
  29. Log.d(TAG, "noteModels:" + noteModels.get(0).content);
  30. });
  31. }
  32. //验证基于所依赖的Ability的事件响应,经常出现的场景是多个Slice公有一个Ability的情况
  33. private void initGlobalViewModel(){
  34. ViewModelProvider globalProvider = ViewModelProviders.of((CompatAbility) getAbility());
  35. globalVm = globalProvider.get(NoteViewModel.class);
  36. Log.d(TAG, "global vm addr:" + globalVm);
  37. globalVm.notes.observe(this, noteModels -> {
  38. Log.d(TAG, "global noteModels:" + noteModels.get(0).content);
  39. });
  40. }
  41. }

Slice2的代码

  1. public class LifeAbilitySlice2 extends CompatSlice {
  2. private static final String TAG = "LifeAbilitySlice2";
  3. private NoteViewModel vm;
  4. private NoteViewModel globalVm;
  5. @Override
  6. protected void onStart(Intent intent) {
  7. super.onStart(intent);
  8. setUIContent(ResourceTable.Layout_life2_request_layout);
  9. findComponentById(ResourceTable.Id_btn_life).setClickedListener(component -> {
  10. vm.fetchNotes();
  11. });
  12. findComponentById(ResourceTable.Id_btn_life_global).setClickedListener(component -> {
  13. globalVm.fetchGlobalNotes();
  14. });
  15. initSliceViewModel();
  16. initGlobalViewModel();
  17. }
  18. private void initSliceViewModel(){
  19. ViewModelProvider provider = ViewModelProviders.of(this);
  20. vm = provider.get(NoteViewModel.class);
  21. Log.d(TAG, "slice vm addr:" + vm);
  22. vm.notes.observe(this, noteModels -> {
  23. Log.d(TAG, "noteModels:" + noteModels.get(0).content);
  24. appendtext(noteModels.get(0).content);
  25. });
  26. }
  27. private void initGlobalViewModel(){
  28. ViewModelProvider globalProvider = ViewModelProviders.of((CompatAbility) getAbility());
  29. globalVm = globalProvider.get(NoteViewModel.class);
  30. Log.d(TAG, "global vm addr:" + globalVm);
  31. globalVm.notes.observe(this, noteModels -> {
  32. Log.d(TAG, "observe global noteModels:" + noteModels.get(0).content);
  33. });
  34. globalVm.notes.observeNoSticky(this, noteModels -> {
  35. Log.d(TAG, "observeNoSticky global noteModels:" + noteModels.get(0).content);
  36. });
  37. }
  38. }

两个的代码基本一样,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_ohosicon-default.png?t=L892https://gitee.com/ethan-osc_admin/viewmodel_for_ohos#%E4%BD%BF%E7%94%A8%E8%AF%B4%E6%98%8E移植完之后,有个和这个很相似的通讯库叫LiveEventBus,打算下来移植这个,估计还需要一段时间才能和大家见面

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/从前慢现在也慢/article/detail/98242
推荐阅读
相关标签
  

闽ICP备14008679号