ViewModel 源码分析

栏目: 编程工具 · 发布时间: 7年前

内容简介:从图可以看出来,ViewModel 与 LiveData 和 Paging 是谷歌新组件,同时它是 android.arch.lifecycle 包里面的类,可以支持 activity 和 fragment 共享数据(比如在 fragment 获取 activity 搜索框的内容)当然 activity 销毁了数据就不存在了;又或者是 fragment 与子 fragment 共享数据(比如 fragment 里面嵌套了 viewpager , viewpager 里又有 fragemnt)。创建一个类传
ViewModel 源码分析

从图可以看出来,ViewModel 与 LiveData 和 Paging 是谷歌新组件,同时它是 android.arch.lifecycle 包里面的类,可以支持 activity 和 fragment 共享数据(比如在 fragment 获取 activity 搜索框的内容)当然 activity 销毁了数据就不存在了;又或者是 fragment 与子 fragment 共享数据(比如 fragment 里面嵌套了 viewpager , viewpager 里又有 fragemnt)。

使用方法

//build.gralde
implementation 'android.arch.lifecycle:extensions:1.1.1'  //包括了 viewmodel 和 livedata
implementation 'android.arch.lifecycle:compiler:1.1.1'
implementation 'android.arch.lifecycle:common-java8:1.1.1'
复制代码

创建一个类传字符串,然后在 activity 实例化并且赋值。

//KeywordModel.kt
class KeywordModel : ViewModel() {

    var keyword: MutableLiveData<String>? = MutableLiveData()

    fun getKeyWord(): LiveData<String> {

        return keyword!!
    }

    fun setKeyWord(key: String) {
        keyword?.value = key
    }
}
//MainActivity.kt
val keywordModel=ViewModelProviders.of(this).get(KeywordModel::class.java)  //在activity实例化

keywordModel.setKeyWord("siri")  //赋值

复制代码

在fragment 获取值

//ExampleFragment.kt
val keywordModel = ViewModelProviders.of(activity as MainActivity).get(KeywordModel::class.java)

keywordModel.getKeyWord().observe(this, Observer<String> {
            mPresenter.requestArticleList(requireNotNull(it), true)
        })
复制代码

以上就完成了 ViewModel 的基本使用了。

源码分析

在分析源码之前,应该思考一下,如果这个功能由你来写,你会是怎么实现,用什么数据结构去存数据,然后根据这个功能,可以拓展出什么其他用途。

首先看创建方法。ViewModelProviders 的 of 方法可以传入 fragment 或者是 activity,就是说你可以在fragment 或者 activity 创建 viewmodel,而这个 viewmodel 只会依赖你的创建的 activity 或者是 fragment(都是同一个viewmodel)。我们先来分析 传入参数是 activity 的这种情况。

//ViewModelProviders.java
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
        return of(activity, null);
    }

public static ViewModelProvider of(@NonNull FragmentActivity activity,
            @Nullable Factory factory) {
        Application application = checkApplication(activity);
        if (factory == null) {
            factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
        }
        return new ViewModelProvider(ViewModelStores.of(activity), factory);
    }
复制代码

调用了两个参数的 of 方法,在 of 方法里面,通过 activity 来获取 applicaiton 从而来创建默认的 AndroidViewModelFactory 工厂。 这个工厂是 ViewModelProvider 的静态内部类。主作用是同是通过反射来获取 viewmodel

//AndroidViewModelFactory.java
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
            if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
                try {
                    return modelClass.getConstructor(Application.class).newInstance(mApplication);
                } catch (Exception e) {
                    throw new RuntimeException("", e);
                }
            }
            return super.create(modelClass);
        }
复制代码

还有另外一个参数 ViewModelStores.of(activity),判断了当前activity有没有实现 ViewModelStoreOwner 接口,而我们没实现,就下一步吧。调用了 HolderFragment 的 holderFragmentFor 来创建一个 holderFragment, 添加到 activity 上(当然这个fragment 没界面),而这个 fragment 上有 mViewModelStore 的实例。

//ViewModelStores.java
public static ViewModelStore of(@NonNull FragmentActivity activity) {
        if (activity instanceof ViewModelStoreOwner) {
            return ((ViewModelStoreOwner) activity).getViewModelStore();
        }
        return holderFragmentFor(activity).getViewModelStore();
    }
复制代码

而在 ViewModelStore 里面有 hashmap ,通过 key 获取存储 viewmodel 。所以 viewmodel 使用了hashmap来存储 viewmodel 啦。

//ViewModelStore.java
public class ViewModelStore {
    private final HashMap<String, ViewModel> mMap = new HashMap<>();

    final void put(String key, ViewModel viewModel) {
        ViewModel oldViewModel = mMap.put(key, viewModel);
        if (oldViewModel != null) {
            oldViewModel.onCleared();
        }
    }

    final ViewModel get(String key) {
        return mMap.get(key);
    }

    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.onCleared();
        }
        mMap.clear();
    }
}
复制代码

而看回 ViewModelProvider 这个类,通过get方法来获取viewmodel,从下面的的 get 方法可以看到 hashmap 的 key 是由DEFAULT_KEY 前缀和的 viewmodel 的 canonicalName 来组成。并且get的时候 会先从hashmah 中获取viewmodel ,不存在这个viewmodel,再从 mFactory 里面创建 viewmodel ,并存进 hashmap。

//ViewModelProvider.java
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)) {
            //noinspection unchecked
            return (T) viewModel;
        } else {
            //noinspection StatementWithEmptyBody
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }

        viewModel = mFactory.create(modelClass);
        mViewModelStore.put(key, viewModel);
        //noinspection unchecked
        return (T) viewModel;
    }

复制代码

同理

当viewmodelproviders.of 传入fragment时,也会走上面的流程,只不过生成holderfragment的时候用getChildFragmentManager()

//HolderFragment.java
HolderFragment holderFragmentFor(Fragment parentFragment) {
            FragmentManager fm = parentFragment.getChildFragmentManager();
            HolderFragment holder = findHolderFragment(fm);
            if (holder != null) {
                return holder;
            }
            holder = mNotCommittedFragmentHolders.get(parentFragment);
            if (holder != null) {
                return holder;
            }

            parentFragment.getFragmentManager()
                    .registerFragmentLifecycleCallbacks(mParentDestroyedCallback, false);
            holder = createHolderFragment(fm);
            mNotCommittedFragmentHolders.put(parentFragment, holder);
            return holder;
        }
复制代码

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

PHP and MySQL Web Development

PHP and MySQL Web Development

Luke Welling、Laura Thomson / Sams / July 25, 2007 / $49.99

Book Description PHP and MySQL Web Development teaches you to develop dynamic, secure, commerical Web sites. Using the same accessible, popular teaching style of the three previous editions, this b......一起来看看 《PHP and MySQL Web Development》 这本书的介绍吧!

URL 编码/解码
URL 编码/解码

URL 编码/解码

html转js在线工具
html转js在线工具

html转js在线工具

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试