Android Jetpack 架构组件(三) ViewModel

google官网 ViewModel 概览  

 

 ViewModel有两个作用:

1. 保存数据, 屏幕旋转或者其他config change引起的activity销毁。

2. fragments之间的数据共享,以及加上Live Data后可以直接通信。
 

ViewModel的生命周期

由下图可以看到,ViewModel的生命周期,不随屏幕旋转而消失。知道用户主动调用finish()以后,才在onDestory()以后消失。 而对于 Fragment,是在 Fragment dettached()。

引起ViewModel消失的情况如下:

1.按返回按钮
2. 从“最近使用的应用”屏幕中滑动关闭 Activity。
3. 从 Activity 向上导航。
4. 从“设置”屏幕中终止应用。
5.  Activity.finish()。

6. 切换到后台。在这种情况下,系统会尽最大努力将应用进程留在内存中。但是,当用户转而去与其他应用进行互动时,系统可能会销毁该应用进程。在这种情况下,Activity 实例连同其中存储的任何状态都会一起被销毁。当用户重新启动应用时,Activity 会出乎意料地处于干净状态。

 

 保存数据

旋转或切换到多窗口模式时, 以前是用savedInstanceState来保存和恢复UI数据的。

从ViewModel的生命周期可以看出,现在可以用ViewModel轻松实现。

在 Fragment 之间共享数据

在每一个Fragments中都可以用如下代码找到同一个view model对象。

 SharedViewModel model = new ViewModelProvider(requireActivity()).get(SharedViewModel.class);

简单源码分析

ViewModel            private final Map<String, Object> mBagOfTags = new HashMap<>();

ViewModelStore       private final HashMap<String, ViewModel> mMap = new HashMap<>();

ViewModelProvider    通过传递class, 反射生成返回用户的viewmodel对象, 并且让Activity存储起来。

ViewModelOwner       ViewModelStore getViewModelStore(); Activity实现。所以Activity持有ViewModelStore,以及一个或多个ViewModel。

ViewModel 对象存在的时间比视图或 LifecycleOwners 的特定实例存在的时间更长。所以绝不能引用View、Lifecycle 或可能存储对 Activity 上下文的引用的任何类。
ViewModel 将一直留在内存中,直到限定其存在时间范围的 Lifecycle 永久消失:对于 Activity,是在 Activity 完成时;而对于 Fragment,是在 Fragment 分离时。
   
ViewModelProvider.NewInstanceFactory 创建viewmodel对象
 ViewModelProvider.AndroidViewModelFactory 创建包含application 的viewmodel对象  

 

为何在屏幕旋转时不被回收,看以下代码中if (event == Lifecycle.Event.ON_DESTROY)的情况。

    public ComponentActivity() {
        Lifecycle lifecycle = getLifecycle();
        //noinspection ConstantConditions
        if (lifecycle == null) {
            throw new IllegalStateException("getLifecycle() returned null in ComponentActivity's "
                    + "constructor. Please make sure you are lazily constructing your Lifecycle "
                    + "in the first call to getLifecycle() rather than relying on field "
                    + "initialization.");
        }
        if (Build.VERSION.SDK_INT >= 19) {
            getLifecycle().addObserver(new LifecycleEventObserver() {
                @Override
                public void onStateChanged(@NonNull LifecycleOwner source,
                        @NonNull Lifecycle.Event event) {
                    if (event == Lifecycle.Event.ON_STOP) {
                        Window window = getWindow();
                        final View decor = window != null ? window.peekDecorView() : null;
                        if (decor != null) {
                            decor.cancelPendingInputEvents();
                        }
                    }
                }
            });
        }
        getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                if (event == Lifecycle.Event.ON_DESTROY) {
                    if (!isChangingConfigurations()) {
                        getViewModelStore().clear();
                    }
                }
            }
        });

        if (19 <= SDK_INT && SDK_INT <= 23) {
            getLifecycle().addObserver(new ImmLeaksCleaner(this));
        }
    }

 

请注意 if (!isChangingConfigurations()) , 也就是说view model不会被清理。并且系统会自动将 ViewModel 与发生配置更改后产生的新 Activity 实例相关联。

                if (event == Lifecycle.Event.ON_DESTROY) {
                    if (!isChangingConfigurations()) {
                        getViewModelStore().clear();
                    }
                }

使用要注意的问题:

你自定义的viewModel必须要下面的方式生产对象,否则没有效果

public class MainActivity extends AppCompatActivity {
    private ActivityMainBinding binding;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        
        binding = ActivityMainBinding.inflate(getLayoutInflater());
        setContentView(binding.getRoot());
        ViewModelProvider provider = new ViewModelProvider(this, new ViewModelProvider.NewInstanceFactory());
        MainActivityViewModel viewModel = provider.get(MainActivityViewModel.class);

        binding.setViewModel(viewModel);

    }
}

因为Activity有一个保存view model对象的操作。

这是你在MainAcitivity调用的ViewModelProvider构造函数。owner就是MainActivity对象。因为super类ComponentActivity实现了ViewModelStoreOwner。


  public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
        mFactory = factory;
        mViewModelStore = store;
    }

public interface ViewModelStoreOwner {
    /**
     * Returns owned {@link ViewModelStore}
     *
     * @return a {@code ViewModelStore}
     */
    @NonNull
    ViewModelStore getViewModelStore();
}

 

具体保存操作请看代码注释:

    @NonNull
    @MainThread
    public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
        ViewModel viewModel = mViewModelStore.get(key);

        if (modelClass.isInstance(viewModel)) {
            if (mFactory instanceof OnRequeryFactory) {
                ((OnRequeryFactory) mFactory).onRequery(viewModel);
            }
            return (T) viewModel;
        } else {
            //noinspection StatementWithEmptyBody
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }
        if (mFactory instanceof KeyedFactory) {
            viewModel = ((KeyedFactory) mFactory).create(key, modelClass); //用反射实例化你的ViewModel
        } else {
            viewModel = mFactory.create(modelClass);
        }
        mViewModelStore.put(key, viewModel); //在这里加入你的View Model
        return (T) viewModel;
    }

 

ViewModel就是这么简单,但是和Data Binding+LiveData结合后,保存数据,fragment之间通信就是很简单了。

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值