Viewmodel的原理

2020-05-07  本文已影响0人  烧伤的火柴

介绍

google的Jetpack推出的Viewmodel会绑定组件的生命周期,当Activity finish的时候,Viewmodel会执行onCleared()方法释放资源,避免内存泄漏。

使用

1.定义Viewmodel

class ShareViewModel: ViewModel() {
    val mutableLiveData:MutableLiveData<String> = MutableLiveData()
}

2.使用

val viewModel = ViewModelProvider(activity as ViewModelStoreOwner)[ShareViewModel::class.java]

        viewModel.mutableLiveData.observe(activity as LifecycleOwner, Observer {
            textView.text = it
        })

源码分析

ViewModelProvider构造

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

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

andoidx.activity:activity:1.0.0@aar中的ComponentActivity实现了ViewModelStoreOwner接口
andoidx.activity:activity:1.1.0@aar中的ComponentActivity实现了ViewModelStoreOwner接口和HasDefaultViewModelProviderFactory接口
我们分析一个1.0.0的ComponentActivity,那么mFactory 就是NewInstanceFactory实例
我们看一下ComponentActivity的getViewModelStore

   public ViewModelStore getViewModelStore() {
     ...
            if (mViewModelStore == null) {
                mViewModelStore = new ViewModelStore();
            }
        }
        return mViewModelStore;
    }

所以ComponentActivity的mViewModelStore 是ViewModelStore的实例

get方法得到Viewmodel

  public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
        String canonicalName = modelClass.getCanonicalName();
        if (canonicalName == null) {
            throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
        }
        return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
    }

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);
        } else {
            viewModel = (mFactory).create(modelClass);
        }
        mViewModelStore.put(key, viewModel);
        return (T) viewModel;
    }

第一步是从mViewModelStore的缓存中根据key查询ViewModel,如果缓存中存在 就直接返回,否则就根据mFactory create一个ViewModel然后存储到mViewModelStore中。
根据前边的分析mFactory 是NewInstanceFactory。

public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
            //noinspection TryWithIdenticalCatches
            try {
                return modelClass.newInstance();
            } catch (InstantiationException e) {
                throw new RuntimeException("Cannot create an instance of " + modelClass, e);
            } catch (IllegalAccessException e) {
                throw new RuntimeException("Cannot create an instance of " + modelClass, e);
            }
        }

这里我们发现Viewmodel是根据Class 反射创建出来的实例。

我们有时候看到一个Activity中多个Fragment使用Viewmodel共享数据,他们都是通过使用的用一个activity创建的ViewModelProvider,那么ViewModelProvider中的mViewModelStore是同一个,即共用一个缓存。

上一篇下一篇

猜你喜欢

热点阅读