Jetpack系列之ViewModel

Jetpack ViewModel

Posted by xyh on September 3, 2018

本文记录Android JetpackArchitecture部分的ViewModel以及工作原理。

Android Jetpack系列之ViewModel

Android Jetpack是一系列助力更容易打造卓越 Android 应用的工具和组件。这些组件能帮助您遵循最佳实践、免除编写繁复的样板代码并简化复杂任务,从而使您可以专注于最核心的代码逻辑。

Jetpack 中的架构指南由 Android 开发中四个关键领域中的一系列代码库和工具提供支持。它们分别是基础(Foundation)、架构(Architecture)、行为(Behavior)和 UI。每个 Jetpack 组件均可单独采用,但它们依然可以流畅地协作。其中 androidx.* 库与 Framework API解耦,这能够提供向后兼容的同时,也能更频繁地更新。

本文记录Android Jetpack架构组件(Architecture)中的ViewModel

ViewModel概述

ViewModel用来管理UI交互的数据,它保存的数据不会因为Activity配置改变而重新生成,比如屏幕旋转会重新触发onCreate(),但是ViewModel保存的数据不会丢失。

ActivityFragment的生命周期是由Framework管理,Framework会在不在用户控制的情况下对ActivityFragment进行销毁和重建。 如果ActivityFragment销毁或者重建之后,存储在当中的数据将会丢失,简单的数据可以通过onSaveInstanceState()onCreate()来恢复,但是大数据,比如位图,或者一个列表却不适用,现在这些数据可以保存到ViewModel中。

下面是屏幕旋转之后的对比

效果图

实现ViewModel

实现ViewModel只需要继承ViewModel即可,如:

1
2
3
4
5
6
7
8
9
10
11
class TextViewModel : ViewModel() {
    var text: String? = null
        get() {
            if (field == null) {
                field = asyncText()
            }
            return field
        }

    private fun asyncText(): String = "This is a Text"
}

然后再通过ViewModelProviders来获取:

1
2
3
4
5
6
7
8
9
10
11
12
class ViewModelActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_view_model)
        val textViewModel = ViewModelProviders.of(this)
                .get(TextViewModel::class.java)

        val modelTv = findViewById<TextView>(R.id.tv_model)
        modelTv.text = textViewModel.text
    }
}

如果Activity重新创建,获取到的textViewModel是同一个实例,当Activity finished之后会调用ViewModelonCleared,用于回收资源,下文追踪源码分析。

注意:ViewModel不能有对View的引用,或者其他对Activity Context有引用的类。

如果需要用到Application Context可以选择继承AndroidViewModel

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class AndroidViewModel extends ViewModel {
    @SuppressLint("StaticFieldLeak")
    private Application mApplication;

    public AndroidViewModel(@NonNull Application application) {
        mApplication = application;
    }

    /**
     * Return the application.
     */
    @SuppressWarnings("TypeParameterUnusedInFormals")
    @NonNull
    public <T extends Application> T getApplication() {
        //noinspection unchecked
        return (T) mApplication;
    }
}

ViewModel的生命周期

ViewModel的生命周期

通常情况下会在ActivityonCreate()方法获取ViewModel,此后无论onCreate()调用多少次,获取到的ViewModel都是同一个实例。

ViewModel源码分析

1
2
3
4
5
6
7
8
9
10
11
public abstract class ViewModel {
    /**
     * This method will be called when this ViewModel is no longer used and will be destroyed.
     * <p>
     * It is useful when ViewModel observes some data and you need to clear this subscription to
     * prevent a leak of this ViewModel.
     */
    @SuppressWarnings("WeakerAccess")
    protected void onCleared() {
    }
}

ViewModel是一个抽象类,中间只有一个可选择实现的方法onCleared(),该方法会在重复缓存当前ViewModelViewModelStore中或者HolderFragmentonDestory()被调用,用于回收资源。

ViewModelProviders.of(xxx).get(xxx)源码分析

对于上文中出现的代码:

1
val textViewModel = ViewModelProviders.of(this).get(TextViewModel::class.java)

ViewModelProviders.of(this)的操作: 一共有4个重载方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull Fragment fragment) {
        ViewModelProvider.AndroidViewModelFactory factory =
                ViewModelProvider.AndroidViewModelFactory.getInstance(
                        checkApplication(checkActivity(fragment)));
        return new ViewModelProvider(ViewModelStores.of(fragment), factory);
    }
    
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
        ViewModelProvider.AndroidViewModelFactory factory =
                ViewModelProvider.AndroidViewModelFactory.getInstance(
                        checkApplication(activity));
        return new ViewModelProvider(ViewModelStores.of(activity), factory);
    }
    
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull Fragment fragment, @NonNull Factory factory) {
        checkApplication(checkActivity(fragment));
        return new ViewModelProvider(ViewModelStores.of(fragment), factory);
    }
    
@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity,
            @NonNull Factory factory) {
        checkApplication(activity);
        return new ViewModelProvider(ViewModelStores.of(activity), factory);
    }

该方法必须在主线程中调用,前两个方法不需要提供Factory,会实现默认的factory。

1
ViewModelProvider.AndroidViewModelFactory factory = ViewModelProvider.AndroidViewModelFactory.getInstance(checkApplication(activity));

该方法会通过AndroidViewModelFactory#getInstance()返回一个AndroidViewModelFactory的单例,何为AndroidViewModelFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
 public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {

        private static AndroidViewModelFactory sInstance;

        /**
         * Retrieve a singleton instance of AndroidViewModelFactory.
         *
         * @param application an application to pass in {@link AndroidViewModel}
         * @return A valid {@link AndroidViewModelFactory}
         */
        public static AndroidViewModelFactory getInstance(@NonNull Application application) {
            if (sInstance == null) {
                sInstance = new AndroidViewModelFactory(application);
            }
            return sInstance;
        }

        private Application mApplication;

        /**
         * Creates a {@code AndroidViewModelFactory}
         *
         * @param application an application to pass in {@link AndroidViewModel}
         */
        public AndroidViewModelFactory(@NonNull Application application) {
            mApplication = application;
        }

        @NonNull
        @Override
        public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
            if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
                //noinspection TryWithIdenticalCatches
                try {
                    return modelClass.getConstructor(Application.class).newInstance(mApplication);
                } catch (NoSuchMethodException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                } catch (InstantiationException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                } catch (InvocationTargetException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                }
            }
            return super.create(modelClass);
        }
    }

AndroidViewModelFactory继承自NewInstanceFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
 public static class NewInstanceFactory implements Factory {

        @SuppressWarnings("ClassNewInstance")
        @NonNull
        @Override
        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);
            }
        }
    }

该类实现了Factory接口,该接口只有一个方法create()用于创建新的实例。 回到方法

1
ViewModelProvider.AndroidViewModelFactory factory = ViewModelProvider.AndroidViewModelFactory.getInstance(checkApplication(activity));

该方法通过AndroidViewModelFactory.getInstance(checkApplication(activity))返回AndroidViewModelFactory的单例。其中checkApplication(activity)用于返回Activity/Fragment绑定的Application,如果没有绑定Application则会抛出异常。

再回到最初的of方法。

1
2
3
4
5
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
        ViewModelProvider.AndroidViewModelFactory factory = ViewModelProvider.AndroidViewModelFactory.getInstance(checkApplication(activity));
        return new ViewModelProvider(ViewModelStores.of(activity), factory);
    }
1
return new ViewModelProvider(ViewModelStores.of(activity), factory);

该句代码中的ViewModelStores.of(activity)会返回一个ViewModelStore该类用于存储ViewModelViewModelStores.of(activity)有两个重载方法。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@NonNull
@MainThread
public static ViewModelStore of(@NonNull FragmentActivity activity) {
        if (activity instanceof ViewModelStoreOwner) {
            return ((ViewModelStoreOwner) activity).getViewModelStore();
        }
        return holderFragmentFor(activity).getViewModelStore();
    }


@NonNull
@MainThread
public static ViewModelStore of(@NonNull Fragment fragment) {
        if (fragment instanceof ViewModelStoreOwner) {
            return ((ViewModelStoreOwner) fragment).getViewModelStore();
        }
        return holderFragmentFor(fragment).getViewModelStore();
    }

这两个构造函数除了入参不一样,其他基本是一样的,先判断Activity/Fragment是否实现了ViewModelStoreOwner接口,实现该接口要求实现getViewModelStore()方法并且返回一个ViewStore。如果没有实现该接口则会调用holderFragmentFor(activity/fragment).getViewModelStore()返回ViewModelStore()

holderFragmentFor(activity/fragment).getViewModelStore()方法位于HolderFragment中。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static HolderFragment holderFragmentFor(FragmentActivity activity) {
        return sHolderFragmentManager.holderFragmentFor(activity);
    }

    /**
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    public static HolderFragment holderFragmentFor(Fragment fragment) {
        return sHolderFragmentManager.holderFragmentFor(fragment);
    }

两个方法会返回HolderFragmentsHolderFragmentManagerHolderFragmentManager用于管理HolderFragment,其中的holderFragmentFor(Activity)方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
HolderFragment holderFragmentFor(FragmentActivity activity) {
            FragmentManager fm = activity.getSupportFragmentManager();
            //通过HOLDER_TAG获取已经添加过的HolderFragment
            HolderFragment holder = findHolderFragment(fm);
            if (holder != null) {
                return holder;
            }
            //mNotCommittedActivityHolders是一个Map,用于存储HolderFragment,key为Activity
            holder = mNotCommittedActivityHolders.get(activity);
            if (holder != null) {
                return holder;
            }
            //用于判断是否注册ActivityLifeCycle回调,没有则注册,用于Activity销毁的时候移除对应的Activity以及触发对应ViewModel的onCleared()
            if (!mActivityCallbacksIsAdded) {
                mActivityCallbacksIsAdded = true;
                activity.getApplication().registerActivityLifecycleCallbacks(mActivityCallbacks);
            }
            //创建新的HolderFragment并且为之设置TAG为HOLDER_TAG
            holder = createHolderFragment(fm);
            //将创建的HolderFragment放进mNotCommittedActivityHolders用于下次直接get()
            mNotCommittedActivityHolders.put(activity, holder);
            return holder;
        }

再看holderFragmentFor(fragment).getViewModelStore()就很清晰了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
    private ViewModelStore mViewModelStore = new ViewModelStore();
    
    public HolderFragment() {
        //当前Fragment绑定的Activity被recreate时,Fragment的onDestroy()和onCreate()不会调用
        setRetainInstance(true);
    }
    @Override
    public void onDestroy() {
        super.onDestroy();
        mViewModelStore.clear();
    }

    @NonNull
    @Override
    public ViewModelStore getViewModelStore() {
        return mViewModelStore;
    }

其实就是直接new ViewModelStore()了,何为ViewModelStore

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
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);
    }

    /**
     *  Clears internal storage and notifies ViewModels that they are no longer used.
     */
    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.onCleared();
        }
        mMap.clear();
    }
}

这个就很简单了。 获取到了ViewModelStore,再回到最初的ViewModelProviders.of()方法。

1
2
3
4
5
6
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
        ViewModelProvider.AndroidViewModelFactory factory =
                ViewModelProvider.AndroidViewModelFactory.getInstance(
                        checkApplication(activity));
        return new ViewModelProvider(ViewModelStores.of(activity), factory);
    }

下面这句返回一个ViewModelProvider,该类没有父类,追踪源码可知。

1
2
3
4
 public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
        mFactory = factory;
        this.mViewModelStore = store;
    }

只是设置了mFactoryViewModelStore,上文分析可知这两个参数的由来。

再回到获取ViewModel方法中的ViewModelProviders.of(this).get(TextViewModel::class.java) 分析get(),上文可知of返回的是ViewModelProvider,所以直接打开ViewModelProvider#get()方法。

1
2
3
4
5
6
7
8
    @NonNull
    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);
    }

其中canonicalName作为类的唯一标识。DEFAULT_KEY为android.arch.lifecycle.ViewModelProvider.DefaultKey。点开重载方法get(DEFAULT_KEY + ":" + canonicalName, modelClass);

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
@NonNull
@MainThread
public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
        //通过ViewModelStore来获取已存在的ViewModel
        ViewModel viewModel = mViewModelStore.get(key);
        //如果modelClass是上面viewModel的实例则直接返回
        if (modelClass.isInstance(viewModel)) {
            //noinspection unchecked
            return (T) viewModel;
        } else {
            //noinspection StatementWithEmptyBody
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }
        //通过Factory创建一个ViewModel,前文中的AndroidModelFacotry中的create()方法
        viewModel = mFactory.create(modelClass);
        //将当前ViewModel存储到ViewModelStore中
        mViewModelStore.put(key, viewModel);
        //noinspection unchecked
        return (T) viewModel;
    }

至此,ViewModelProviders.of(xx).get(xxx)分析完毕。