Android JetPack——ViewModel使用以及原理

概念

试图数据管理类,ViewModel负责准备和管理跟UI组件(Activity,Fragment)相关的数据类,同时还可以用来负责UI组件间的通信。

存在的意义

a.页面销毁重新创建后(如旋转屏幕,异常销毁等),原来的UI相关数据会丢失,理论上可以通过onSaveInstanceState()存储数据,组件重建之后通过onCreate(),从中读取Bundle恢复数据。但如果是大量数据,Intent源码限制1M大小,实际可用大概512k左右,超过时不能储存。

b.基于架构层次考虑,UI controllers其实只需要负责展示UI数据、响应用户交互和系统交互,但是现存MVP架构中presenter层过于庞大,Aciivity与Fragment也难以做到试图分类。

生命周期:

     左侧表示Activity的生命周期状态,右侧绿色部分表示ViewModel的生命周期范围。ViewModel只有onCleared()在结束时调用,Activity生命周期照旧。注意当旋转屏幕时,在不设置onConfig属性的情况下,Activity会被reCreate,但是VidewModel还是之前的对象,没有重新创建。

ViewModel原理

1.创建

a.viewModel初始化通过ViewModelProvider获取ViewModel实例,先看ViewModel源码其构造方法:

public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
        this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
                ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
                : NewInstanceFactory.getInstance());
}
    
public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
    this(owner.getViewModelStore(), factory);
}

ViewModelProvider的构造方法中可以看到最终是需要两个参数ViewModelStoreOwner以及Factory。这两个参数中ViewModelStoreOwner是用来存储ViewModel对象的,Factory是用来创建ViewModel对象。

b.ViewModelProvider的get()方法获取ViewModel实例

public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
        ViewModel viewModel = mViewModelStore.get(key); // 1.是否有缓存ViewModel实例缓存

        ...
        if (mFactory instanceof KeyedFactory) {
            viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
        } else {
            viewModel = (mFactory).create(modelClass);
        }
        mViewModelStore.put(key, viewModel);
        return (T) viewModel;
    }

通过Factory创建ViewModel后,讲viewModel放置在mViewModelStore缓存中

c.ViewModelStoreOwner,ViewModelStore

public interface ViewModelStoreOwner {
    /**
     * Returns owned {@link ViewModelStore}
     *
     * @return a {@code ViewModelStore}
     */
    @NonNull
    ViewModelStore getViewModelStore();
}
public class ViewModelStore {
    private final HashMap<String, ViewModel> mMap = new HashMap<>();
 
    final void put(String key, ViewModel viewModel) {
        ViewModel oldViewModel = mMap.get(key);
        if (oldViewModel != null) {
            oldViewModel.onCleared();
        }
        mMap.put(key, viewModel);
    }
 
    final ViewModel get(String key) {
        return mMap.get(key);
    }
 
    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.onCleared();
        }
        mMap.clear();
    }
}

源码中我们传入的组件ViewModelStoreOwner,通过getViewModelStore方法获取到的ViewModelStore对象,从源码中我们能够看到,在ViewModelStore内部是保存了一个HashMap,key就是ViewModel的全类名,所以在调用get方法时,从store拿到的ViewModel就是我们要创建的这个实例

2.销毁

a.ViewModel中有clear()方法和onCleared()都执行了clear方法,进行vm.clear与清除缓存HashMap缓存的 操作

public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.clear();
        }
        mMap.clear();
    }

b.继续跟踪代码能查看到Activity与Framgent执行getViewModelStore().clear()方法的时机

 public ComponentActivity() {
 	getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                if (event == Lifecycle.Event.ON_DESTROY) {
                    if (!isChangingConfigurations()) {
                        // 销毁ViewModel
                        getViewModelStore().clear();
                    }
                }
            }
        });
 }
void clearNonConfigState(@NonNull Fragment f) {
    ...
    // Clear and remove the Fragment's ViewModelStore
    ViewModelStore viewModelStore = mViewModelStores.get(f.mWho);
    if (viewModelStore != null) {
        // ViewModel销毁
        viewModelStore.clear();
        mViewModelStores.remove(f.mWho);
    }
}

这里有个点需要注意,ViewModel的销毁在onDestory()中,是晚于onDestoryView()的,所以要注意在使用ViewModel做操作时会不会触发组件更新。不然的话可能造成空指针异常。

3.ViewModel的缓存策略

在Activity重建时会执行destory生命周期事件,那么为什么ViewModel没有销毁呢?

public ViewModelStore getViewModelStore() {
    	...
        if (mViewModelStore == null) {
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                // Restore the ViewModelStore from NonConfigurationInstances
                mViewModelStore = nc.viewModelStore;
            }
            if (mViewModelStore == null) {
                mViewModelStore = new ViewModelStore();
            }
        }
        return mViewModelStore;
    }

getViewModelStore()方法时优先从getLastNonConfigurationInstance()方法获取,如果getLastNonConfigurationInstance()方法没有缓存,才会去新建对象。

NonConfigurationInstances 持有并储存viewModelStore对象,viewModelStore对象的HashMap中存储ViewModel对象。

4.Fragment之间共享ViewModel

inline fun <reified VM : ViewModel> Fragment.activityViewModels(
    noinline factoryProducer: (() -> Factory)? = null
) = createViewModelLazy(VM::class, { requireActivity().viewModelStore },
    factoryProducer ?: { requireActivity().defaultViewModelProviderFactory })

在activityViewModels()的实现中可以看到是requireActivity()获取的viewModelStore。以此来实现共享ViewModel。

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值