ViewModel总结

本文详细探讨了Android的ViewModel组件,解释了其在屏幕旋转时保持数据不变的特性。ViewModel通过与Activity或Fragment生命周期关联,确保数据在配置变更时不丢失。创建ViewModel必须通过ViewModelProviders,并利用AndroidViewModelFactory进行反射创建。存储方面,ViewModel存在于Activity或Fragment的ViewModelStore中,当Activity/Fragment销毁时,ViewModel也随之清除。此外,通过在保留实例的Fragment中存储ViewModel,实现了屏幕旋转时的存活。了解这些有助于更好地利用ViewModel进行数据持久化和跨页面共享。
摘要由CSDN通过智能技术生成

ViewModel是存储UI相关数据并不会因为旋转而销毁的类。
最为重要的就是ViewModel具有下面的生命周期,这就是ViewModel的最可贵之处:

下面写一个测试生命周期的demo:
Activity主要代码

public class MainActivity extends AppCompatActivity {
    ActivityMainBinding mBinding;
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        Log.e("mvvm_tag", "MainActivity onCreate");
        super.onCreate(savedInstanceState);
        mBinding = ActivityMainBinding.inflate(LayoutInflater.from(this));
        setContentView(mBinding.getRoot());

        mBinding.btn1.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                FragmentOne fragmentOne = new FragmentOne();
                Bundle bundle = new Bundle();
                bundle.putString("content", "fragment one");
                fragmentOne.setArguments(bundle);

                getSupportFragmentManager()
                        .beginTransaction()
                        .addToBackStack("product")
                        .replace(R.id.content_1, fragmentOne, null).commit();
            }
        });

        TestViewModel testViewModel = ViewModelProviders.of(this).get(TestViewModel.class);
    }

    @Override
    protected void onStart() {
        Log.e("mvvm_tag", "MainActivity onStart");
        super.onStart();
    }

    @Override
    protected void onResume() {
        Log.e("mvvm_tag", "MainActivity onResume");
        super.onResume();
    }

    @Override
    protected void onPause() {
        Log.e("mvvm_tag", "MainActivity onPause");
        super.onPause();
    }

    @Override
    protected void onStop() {
        Log.e("mvvm_tag", "MainActivity onStop");
        super.onStop();
    }

    @Override
    protected void onDestroy() {
        Log.e("mvvm_tag", "MainActivity onDestroy");
        super.onDestroy();
    }
}
public class TestViewModel extends AndroidViewModel {
    public TestViewModel(@NonNull Application application) {
        super(application);
    }

    @Override
    protected void onCleared() {
        Log.e("mvvm_tag", "TestViewModel onCleared");
        super.onCleared();
    }
}

Fragment主要代码

public class FragmentOne extends Fragment {
    FragmentOneBinding mBinding;

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        Log.e("mvvm_tag", "FragmentOne onCreateView");
        mBinding = FragmentOneBinding.inflate(LayoutInflater.from(getContext()));
        return mBinding.getRoot();
    }

    @Override
    public void onActivityCreated(@Nullable Bundle savedInstanceState) {
        Log.e("mvvm_tag", "FragmentOne onActivityCreated");
        super.onActivityCreated(savedInstanceState);

        OneViewModel oneViewModel = ViewModelProviders.of(this).get(OneViewModel.class);
        oneViewModel.setContent(getArguments().getString("content"));
        mBinding.setViewModel(oneViewModel);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        Log.e("mvvm_tag", "FragmentOne onViewCreated");
        super.onViewCreated(view, savedInstanceState);
    }

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        Log.e("mvvm_tag", "FragmentOne onCreate");
        super.onCreate(savedInstanceState);
    }

    @Override
    public void onStart() {
        Log.e("mvvm_tag", "FragmentOne onStart");
        super.onStart();
    }

    @Override
    public void onResume() {
        Log.e("mvvm_tag", "FragmentOne onResume");
        super.onResume();
    }

    @Override
    public void onPause() {
        Log.e("mvvm_tag", "FragmentOne onPause");
        super.onPause();
    }

    @Override
    public void onAttach(Context context) {
        Log.e("mvvm_tag", "FragmentOne onAttach");
        super.onAttach(context);
    }
}
public class OneViewModel extends AndroidViewModel {

    public ObservableField<String> content = new ObservableField<>();

    public OneViewModel(@NonNull Application application) {
        super(application);
    }

    @Override
    protected void onCleared() {
        Log.e("mvvm_tag", "OneViewModel onCleared");
    }

    public void setContent(String c) {
        content.set(c);
    }
}

布局如下:
在这里插入图片描述
点击显示:
在这里插入图片描述
操作一个完整流程:
启动app->点击“显示”->点击返回键->再次点击返回键关闭app
打印出来的log如下:

01-16 15:27:46.655  E/mvvm_tag: MainActivity onCreate
01-16 15:27:46.751  E/mvvm_tag: MainActivity onStart
01-16 15:27:46.753  E/mvvm_tag: MainActivity onResume
01-16 15:27:53.512  E/mvvm_tag: FragmentOne onAttach
01-16 15:27:53.512  E/mvvm_tag: FragmentOne onCreate
01-16 15:27:53.513  E/mvvm_tag: FragmentOne onCreateView
01-16 15:27:53.517  E/mvvm_tag: FragmentOne onViewCreated
01-16 15:27:53.517  E/mvvm_tag: FragmentOne onActivityCreated
01-16 15:27:53.519  E/mvvm_tag: FragmentOne onStart
01-16 15:27:53.519  E/mvvm_tag: FragmentOne onResume
01-16 15:28:16.485  E/mvvm_tag: FragmentOne onPause
01-16 15:28:16.485  E/mvvm_tag: OneViewModel onCleared
01-16 15:28:21.124  E/mvvm_tag: MainActivity onPause
01-16 15:28:21.601  E/mvvm_tag: MainActivity onStop
01-16 15:28:21.602  E/mvvm_tag: MainActivity onDestroy
01-16 15:28:21.603  E/mvvm_tag: TestViewModel onCleared

说明,在fragment中viewmodel与fragment的生命周期一致,而不是activity。
在activity中viewmodel与activity的生命周期一致。
下面测试屏幕旋转时,生命周期的变化。
启动app->点击“显示”->旋转屏幕

01-16 16:05:26.893 E/mvvm_tag: MainActivity onCreate
01-16 16:05:26.976 E/mvvm_tag: MainActivity onStart
01-16 16:05:26.977 E/mvvm_tag: MainActivity onResume
01-16 16:05:29.330 E/mvvm_tag: FragmentOne onAttach
01-16 16:05:29.331 E/mvvm_tag: FragmentOne onCreate
01-16 16:05:29.331 E/mvvm_tag: FragmentOne onCreateView
01-16 16:05:29.335 E/mvvm_tag: FragmentOne onViewCreated
01-16 16:05:29.335 E/mvvm_tag: FragmentOne onActivityCreated
01-16 16:05:29.335 E/mvvm_tag: FragmentOne onStart
01-16 16:05:29.336 E/mvvm_tag: FragmentOne onResume
// 旋转
01-16 16:05:39.520 E/mvvm_tag: MainActivity onPause
01-16 16:05:39.520 E/mvvm_tag: FragmentOne onPause
01-16 16:05:39.524 E/mvvm_tag: MainActivity onStop
01-16 16:05:39.525 E/mvvm_tag: MainActivity onDestroy
01-16 16:05:39.551 E/mvvm_tag: MainActivity onCreate
01-16 16:05:39.554 E/mvvm_tag: FragmentOne onAttach
01-16 16:05:39.554 E/mvvm_tag: FragmentOne onCreate
01-16 16:05:39.591 E/mvvm_tag: MainActivity onStart
01-16 16:05:39.591 E/mvvm_tag: FragmentOne onCreateView
01-16 16:05:39.594 E/mvvm_tag: FragmentOne onViewCreated
01-16 16:05:39.594 E/mvvm_tag: FragmentOne onActivityCreated
01-16 16:05:39.594 E/mvvm_tag: FragmentOne onStart
01-16 16:05:39.595 E/mvvm_tag: MainActivity onResume
01-16 16:05:39.598 E/mvvm_tag: FragmentOne onResume

可以看出,旋转屏幕时,activity和fragment都重新走了一遍生命周期,销毁之后重新创建,但是viewmodel并没有销毁重建。

这篇文字要弄清楚下面几个问题:

  • ViewModel是怎么创建的?
  • ViewModel是怎么存储的?
  • ViewModel为什么可以实现旋转屏幕不销毁?

详情参考:【大揭秘】Android架构组件ViewModel来龙去脉

先放简单讲一下ViewModel的基本使用方法,我们在获取ViewModel的时候绝对不能直接使用new关键字去创建,需要使用 ViewModelProviders 去使用系统提供的反射方法去创建我们想要的ViewModel,下面是官方架构组件android.arch.lifecycle包下面的ViewModelProviders工具类用来获取ViewModel,才能与Activity或者Fragment的生命周期关联起来。
ViewModel 的存在是依赖 Activity 或者 Fragment的,不管你在什么地方获取ViewModel ,只要你用的是相同的Activity 或者 Fragment,那么获取到的ViewModel将是同一个 (前提是key值是一样的),所以ViewModel 也具有数据共享的作用!
一句话总结ViewModel是怎么被创建的:
创建一个ViewModelProvider,使用ViewModelProvider内部的全局单例AndroidViewModelFactory来反射创建 ViewModel,并把创建的ViewModel存入传入的ViewModelStore中!
到这里我们要知道:

  • 第一: AndroidViewModelFactory在正常情况下是全局单例只有一个,只是一个反射创建对象的工具类。
  • 第二:ViewModelProvider是每次获取创建ViewModel的时候都会创建一个新的。
  • 第三:ViewModelStore是每一个Activity或者Fragment都有一个。

ViewModel是怎么被存储的
ViewModel是存储在当前Activity / Fragment的HolderFragment中的ViewModelStore的HashMap中,我们可以get,put或者在Activity / Fragment 销毁的时候HolderFragment会跟随销毁,在HolderFragment的onDestroy方法中调用mViewModelStore的clear方法。

ViewModel为什么可以实现旋转屏幕不销毁
setRetainInstance(boolean) 是Fragment中的一个方法。将这个方法设置为true就可以使当前Fragment在Activity重建时存活下来, 如果不设置或者设置为 false, 当前 Fragment 会在 Activity 重建时同样发生重建, 以至于被新建的对象所替代。
在setRetainInstance(boolean)为true的 Fragment (就是HolderFragment)中放一个专门用于存储ViewModel的Map, 这样Map中所有的ViewModel都会幸免于Activity的配置改变导致的重建,让需要创建ViewModel的Activity, Fragment都绑定一个这样的Fragment(就是HolderFragment), 将ViewModel存放到这个 Fragment 的 Map 中, ViewModel 组件就这样实现了。

参考

【大揭秘】Android架构组件ViewModel来龙去脉

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值