Android - ViewModel 理解的历程

为什么要对 ViewModel 进行理解。

一切都是因为一个bug 而起。

开发模式( 一个Activity + 多个fragment 组合的回退栈模式 )

过程描述:

第一步: 当用户点击 新闻列表
第二步: 然后点击详情 进入详情界面
第三步: 看见在详情界面有不喜欢一栏。
第四步: 点击不喜欢 回到上一个界面 列表数据会自动 删除掉。

看样子 合理来说是正常的对吧。可以删除。

错。

还有一种情况。

在我们按 home 键的时候, 系统内存不足 把 app 杀掉。或者 我们 把 开发者模式打开 (进入下一个页面 不保留当前activity )进入下一个页面

然后 按照过程描述 操作 就会出现崩溃。
因为这个时候 item == null 。。

我当时查看情况是这样的

app 被系统重建
savedInstanceState 有值。

然后我就想起来

NewListVM viewModel = ViewModelProviders.of(this(fragment)).get(NewListVM.class);

不是应该可以在这种情况下 可以获取之前保存的 ViewModel 吗?

怀着这样的想法 我就试了试。(可以当之前我是直接New NewListVM() 设置进去的。 )

然后发现还是报错。 然后我就生气了,这tm 算什么 可以重用之前的ViewModel ????

debug 大法。


ViewModelProviders.class

 @NonNull
    @MainThread
    public static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) {
        Application application = checkApplication(checkActivity(fragment));
        if (factory == null) {
            factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
        }
        return new ViewModelProvider(ViewModelStores.of(fragment), factory);
    }
@NonNull
    @MainThread
    public static ViewModelStore of(@NonNull Fragment fragment) {
        if (fragment instanceof ViewModelStoreOwner) {
            return ((ViewModelStoreOwner) fragment).getViewModelStore();
        }
        return holderFragmentFor(fragment).getViewModelStore();
    }

这里明明写的。 为什么就不行。

当时我想到了 是不是 没有处理 fragment 回收场景。

代码是这样的。

  public  Fragment initFragment(Class aClass, String title) {
        Fragment fragment = fragmentManager.findFragmentByTag(title);
        if (fragment == null) {
            Bundle bundle = new Bundle();
            bundle.putString(TITLT_KEY, title);
            fragment = Fragment.instantiate(mContext, aClass.getName(), bundle);
        }
        return fragment;
    }

明显的有处理 内存回复的情况。

还是莫名其妙 搞不懂。

然后我就想是不是谁吧 存在 getViewModelStore() ViewModel 给它clear掉了。

然后就找到了 HolderFragment 毕竟clear 方法是写在这个里面的。

HolderFragment 主要作用:
依附于 activity 或者 fragment 之上 存储 + 感知 是否被销毁掉(onDestroy)。
存储 基于 activity 或 fragment 作用域 的值。

然后我就想起来 我在fragment的 onDestroy 打一个Log 就可以了。

但是由于我使用的时kill 就一直没有走 onDestroy 方法。
但是不走 不等于没有被清除。

(有一个重点标记 kill 掉或者被杀掉 不会都走 onDestroy 如果要在 该方法做标记就需要注意了 )

然后我就很奇怪, 然后就找到了另外一个方法 就是 查看内存地址。

既然 HolderFragment 是依附于 fragment 那么 fragment 变化(不是之前的一个) 这个 getViewModelStore() 也就不是之前的。

(重点标记二) kill 进程之后 从 getSupportFragmentManager().getFragments() 取出来的值并不是 之前的fragment 系统会默认帮你创建一个无参数的构造方法。


解决办法:
就是 配合

 public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
 	
 	if(savedInstanceState != null){
 		 ArrayList item = savedInstanceState.getParcelableArrayList("newList");
 		 //  逻辑赋值
	}else{
		 //  正常情况
	}
 	
 	
 }
  @Override
    public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);

        outState.putParcelableArrayList("newList", viewModel.getItems());

    }

意外 收获:

内存回收掉之后。

fragment.
onSaveInstanceState -> onCreateView() (savedInstanceState !=null ) -> onActivityResult

参考:
https://medium.com/androiddevelopers/viewmodels-persistence-onsaveinstancestate-restoring-ui-state-and-loaders-fc7cc4a6c090

https://developer.android.com/reference/android/app/Activity.html#onSaveInstanceState(android.os.Bundle,%20android.os.PersistableBundle)

https://developer.android.com/topic/libraries/architecture/viewmodel-savedstate
https://developer.android.com/topic/libraries/architecture/saving-states.html
https://developer.android.com/topic/libraries/architecture/viewmodel

https://developer.android.com/guide/components/activities/?hl=zh-cn

你可能感兴趣的:(android_开发)