Jetpack ViewModel源码分析

前言

Jetpack ViewModel相信大家都很熟悉了,ViewModel是一个保存Activity、Fragment数据的类,它不随着Activity的配置改变而销毁,例如常见的屏幕旋转、系统语言切换、深、浅色模式切换等

ViewModel创建时,会绑定一个Activity或Fragment,所以可以实现单Activity多Fragment共享数据,使用ViewModel一般会配套使用LiveData

简单使用

以登录页面为例,只有一个用户名和密码的输入框,用户名和密码数据存放在ViewModel的LiveData中

  • 定义LoginViewModel
/**
 * 登录ViewModel
 */
public class LoginViewModel extends ViewModel {
    /**
     * 用户名
     */
    public final MutableLiveData mUserNameLiveData = new MutableLiveData<>();
    /**
     * 密码
     */
    public final MutableLiveData mPasswordLiveData = new MutableLiveData<>();
}
  • 获取LoginViewModel实例
LoginViewModel loginViewModel = ViewModelProviders.of(this).get(LoginViewModel.class);
  • 监听EditText的文字改变,在改变时,更新LiveData
vUsernameTextField.addTextChangedListener(new TextChangedListener() {
    @Override
    public void onTextChanged(CharSequence text, int start, int before, int count) {
        mLoginViewModel.mUserNameLiveData.setValue(text);
    }
    
    //...
});
vPasswordTextField.addTextChangedListener(new TextChangedListener() {
    @Override
    public void onTextChanged(CharSequence text, int start, int before, int count) {
        mLoginViewModel.mPasswordLiveData.setValue(text);
    }
    
    //...
});
  • 监听LiveData数据变化,做响应的业务逻辑
mLoginViewModel.mUserNameLiveData.observe(this, new Observer() {
    @Override
    public void onChanged(String newUserName) {
        //...
    }
});
mLoginViewModel.mPasswordLiveData.observe(this, new Observer() {
    @Override
    public void onChanged(String newPassword) {
        //...
    }
});

源码分析

从示例代码来看,关键点就在ViewModelProviders.of(activity)方法,以及传入activity或fragment后,再调用get(clazz)方法获取ViewModel的实例,所以切入点就在这2个API上

ViewModelProviders.of(activity),转调了of(activity,factory)方法,判断如果没有传入Factory实例,则使用默认的AndroidViewModelFactory

随后,创建了ViewModelProvider实例,同时调用Activity的getViewModelStore()方法获取ViewModelStore

我们来看下这个ViewModelStore是什么东西

@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity) {
    return of(activity, null);
}

@NonNull
@MainThread
public static ViewModelProvider of(@NonNull FragmentActivity activity,
        @Nullable Factory factory) {
    Application application = checkApplication(activity);
    //没有指定工厂,则使用默认的AndroidViewModelFactory
    if (factory == null) {
        factory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
    }
    //创建ViewModelProvider实例,并调用Activity的getViewModelStore()方法获取ViewModelStore
    return new ViewModelProvider(activity.getViewModelStore(), factory);
}

//检查Activity的Application是否为空
private static Application checkApplication(Activity activity) {
    Application application = activity.getApplication();
    if (application == null) {
        throw new IllegalStateException("Your activity/fragment is not yet attached to "
                + "Application. You can't request ViewModel before onCreate call.");
    }
    return application;
}

ViewModelStoreOwner

ViewModelStoreOwner是一个接口,ComponentActivity、AppCompatActivity、Fragment都实现了它

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

ViewModelStore

ViewModelStore,看名字是一个存储ViewModel的类,get()API就是调用的它,类结构来看,就是持有一个HashMap,通过一个key,来获取对应的value,就是ViewModel的实例,接下来看ViewModelProvider

public class ViewModelStore {
    private final HashMap 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);
    }

    Set keys() {
        return new HashSet<>(mMap.keySet());
    }

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

ViewModelProvider

get()方法,key为ViewModel类的类名,优先从mViewModelStore中获取,而mViewModelStore相当于一个Map缓存的功能,获取得到则返回,获取不到则通过传入的工厂进行创建

常用工厂有2种

  • NewInstanceFactory,反射调用无参构造实例化ViewModel
  • AndroidViewModelFactory,反射调用Application有参构造实例化ViewModel
public class ViewModelProvider {
    /**
     * 缓存Key的前缀
     */
    private static final String DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey";

    /**
     * ViewModel工厂接口
     */
    public interface Factory {
        /**
         * 创建指定Class的ViewModel
         */
         T create(Class modelClass);
    }

    static class OnRequeryFactory {
        void onRequery(ViewModel viewModel) {
        }
    }

    /**
     * 支持传入指定Key和Class,创建ViewModel
     */
    abstract static class KeyedFactory extends OnRequeryFactory implements Factory {
        /**
         * 可以指定Key和Class创建的create方法,旧的create(modelClass)将不再支持
         */
        public abstract  T create(String key,
                                                       Class modelClass);

        @Override
        public  T create(Class modelClass) {
            throw new UnsupportedOperationException("create(String, Class) must be called on "
                    + "implementaions of KeyedFactory");
        }
    }

    private final Factory mFactory;
    private final ViewModelStore mViewModelStore;

    /**
     * 构造方法
     *
     * @param owner ViewModelStore持有者,如果它实现了HasDefaultViewModelProviderFactory接口,则通过它来获取默认工厂
     */
    public ViewModelProvider(ViewModelStoreOwner owner) {
        this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
                ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
                : NewInstanceFactory.getInstance());
    }

    /**
     * 构造方法,传入ViewModelStore和ViewModel工厂Factory
     */
    public ViewModelProvider(ViewModelStoreOwner owner, Factory factory) {
        this(owner.getViewModelStore(), factory);
    }

    /**
     * 构造方法,传入ViewModelStore和ViewModel工厂Factory
     */
    public ViewModelProvider(ViewModelStore store, Factory factory) {
        mFactory = factory;
        mViewModelStore = store;
    }

    /**
     * 获取指定的ViewModel
     */
    public  T get(Class modelClass) {
        String canonicalName = modelClass.getCanonicalName();
        if (canonicalName == null) {
            throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
        }
        //默认缓存Key是前缀 + ClassName
        return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
    }

    /**
     * 获取指定的ViewModel
     *
     * @param key        缓存Key
     * @param modelClass ViewModel的Class
     */
    @SuppressWarnings("unchecked")
    public  T get(String key, Class modelClass) {
        //先从缓存中获取
        ViewModel viewModel = mViewModelStore.get(key);
        //检查取出的实例是否和Class匹配
        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;
    }

    /**
     * 简单工厂,会调用无参构造实例化ViewModel
     */
    public static class NewInstanceFactory implements Factory {
        /**
         * 单例
         */
        private static NewInstanceFactory sInstance;

        /**
         * 获取工厂实例
         */
        static NewInstanceFactory getInstance() {
            if (sInstance == null) {
                sInstance = new NewInstanceFactory();
            }
            return sInstance;
        }

        @SuppressWarnings("ClassNewInstance")
        @Override
        public  T create(Class 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);
            }
        }
    }

    /**
     * AndroidViewModel的工厂
     */
    public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {
        /**
         * 单例
         */
        private static AndroidViewModelFactory sInstance;

        /**
         * 获取工厂实例
         */
        public static AndroidViewModelFactory getInstance(Application application) {
            if (sInstance == null) {
                sInstance = new AndroidViewModelFactory(application);
            }
            return sInstance;
        }

        private final Application mApplication;

        public AndroidViewModelFactory(Application application) {
            mApplication = application;
        }

        @Override
        public  T create(Class modelClass) {
            //使用前,先判断传进来的Class,是否是AndroidViewModel或其子类
            if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
                //noinspection TryWithIdenticalCatches
                try {
                    //调用只有一次参数,并且参数类型时Application的构造方法
                    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);
        }
    }
}

ViewModel

经过ViewModelProvider的get()方法,就成功创建ViewModel的实例了,接下来看看ViewModel

主要有一个clear()清理方法,它将在Activity或Fragment的onDestory()中调用,用于清理ViewModel上保存的数据,数据保存到mBagOfTags变量,它是一个Map,所以有setTagIfAbsent()保存数据方法,getTag()获取数据方法

其中,如果保存的对象实现了Closeable接口,就会调用它的close()方法,例如IO流对象就实现了Closeable接口,也可以自定义对象实现该接口,统一在close()方法中,关闭资源等

public abstract class ViewModel {
    /**
     * 存储可Closeable的Map,存储的Closeable实例,会在onCleared()时调用它们的close()方法
     */
    private Map mBagOfTags = new HashMap<>();
    private volatile boolean mCleared = false;

    /**
     * ViewModel即将被销毁时回调
     */
    @SuppressWarnings("WeakerAccess")
    protected void onCleared() {
    }

    /**
     * 清理方法
     */
    final void clear() {
        mCleared = true;
        // Since clear() is final, this method is still called on mock objects
        // and in those cases, mBagOfTags is null. It'll always be empty though
        // because setTagIfAbsent and getTag are not final so we can skip
        // clearing it
        if (mBagOfTags != null) {
            synchronized (mBagOfTags) {
                for (Object value : mBagOfTags.values()) {
                    // see comment for the similar call in setTagIfAbsent
                    closeWithRuntimeException(value);
                }
            }
        }
        onCleared();
    }

    /**
     * 保存一个对象到ViewModel,同时指定它的Key,如果已经保存过了,则不会再保存,会返回保存的实例
     */
    @SuppressWarnings("unchecked")
     T setTagIfAbsent(String key, T newValue) {
        T previous;
        synchronized (mBagOfTags) {
            previous = (T) mBagOfTags.get(key);
            if (previous == null) {
                mBagOfTags.put(key, newValue);
            }
        }
        T result = previous == null ? newValue : previous;
        //如果已经销毁了,则关闭
        if (mCleared) {
            // It is possible that we'll call close() multiple times on the same object, but
            // Closeable interface requires close method to be idempotent:
            // "if the stream is already closed then invoking this method has no effect." (c)
            closeWithRuntimeException(result);
        }
        return result;
    }

    /**
     * 从ViewModel上,获取保存的对象
     */
    @SuppressWarnings({"TypeParameterUnusedInFormals", "unchecked"})
     T getTag(String key) {
        if (mBagOfTags == null) {
            return null;
        }
        synchronized (mBagOfTags) {
            return (T) mBagOfTags.get(key);
        }
    }

    /**
     * 关闭Closeable实例
     */
    private static void closeWithRuntimeException(Object obj) {
        if (obj instanceof Closeable) {
            try {
                ((Closeable) obj).close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

ViewModel的clear()方法调用时机

ComponentActivity的构造方法中,注册了一个Lifecycle监听,在onDestroy()回调时,判断如果没有发生配置改变而发生的重建,才清理ViewModelStore,所以Activity在重建时,不会清理ViewModel,数据是保留的,当正常按返回键销毁时,才会清理ViewModel

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.");
    }
    getLifecycle().addObserver(new LifecycleEventObserver() {
        @Override
        public void onStateChanged(@NonNull LifecycleOwner source,
                @NonNull Lifecycle.Event event) {
            //销毁时,没有发生配置改变而重建时,才清理ViewModelStore
            if (event == Lifecycle.Event.ON_DESTROY) {
                if (!isChangingConfigurations()) {
                    getViewModelStore().clear();
                }
            }
        }
    });
}

ViewModel的保存和恢复

在Activity因配置改变而销毁重建时,ComponentActivitymViewModelStore变量肯定会被置空,那ViewModel从哪里恢复呢?我们来看看getViewModelStore()方法

  • ViewModel恢复

mViewModelStore为null时,调用getLastNonConfigurationInstance()获取一个NonConfigurationInstances对象nc,拿取对象的viewModelStore属性来对mViewModelStore进行赋值

NonConfigurationInstances就是一个配置类,保存一个自定义对象customviewModelStore

@NonNull
@Override
public ViewModelStore getViewModelStore() {
    if (getApplication() == null) {
        throw new IllegalStateException("Your activity is not yet attached to the "
                + "Application instance. You can't request ViewModel before onCreate call.");
    }
    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;
}

//ComponentActivity的NonConfigurationInstances类
static final class NonConfigurationInstances {
    Object custom;
    ViewModelStore viewModelStore;
}

既然恢复点知道了,那么保存点在哪呢?

  • ViewModel的保存

保存点,就是retainNonConfigurationInstances()方法,该方法在ActivityThread类的performDestroyActivity()方法中调用,并把该方法的返回结果保存在ActivityClientRecord对象中

ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
        int configChanges, boolean getNonConfigInstance, String reason) {
    ActivityClientRecord r = mActivities.get(token);
    Class activityClass = null;
    if (r != null) {
        activityClass = r.activity.getClass();
        r.activity.mConfigChangeFlags |= configChanges;
        if (finishing) {
            r.activity.mFinished = true;
        }

        performPauseActivityIfNeeded(r, "destroy");

        if (!r.stopped) {
            callActivityOnStop(r, false /* saveState */, "destroy");
        }
        if (getNonConfigInstance) {
            try {
            //保存点,调用Activity的retainNonConfigurationInstances()方法获取 NonConfigurationInstances对象
                r.lastNonConfigurationInstances
                        = r.activity.retainNonConfigurationInstances();
            } catch (Exception e) {
            }
        }
    return r;
}

值得注意的是,Activity上也有一个NonConfigurationInstances类,它和子类ComponentActivity上的NonConfigurationInstances类不是同一个,关系是父类Activity的NonConfigurationInstances类的activity属性,保存了ComponentActivityNonConfigurationInstances类对象

//Activity类上的NonConfigurationInstances配置类
static final class NonConfigurationInstances {
    Object activity;
    HashMap children;
    FragmentManagerNonConfig fragments;
    ArrayMap loaders;
    VoiceInteractor voiceInteractor;
}

//Activity类上的retainNonConfigurationInstances()方法
NonConfigurationInstances retainNonConfigurationInstances() {
    //调用onRetainNonConfigurationInstance(),获取需要保存的自定义对象
    Object activity = onRetainNonConfigurationInstance();
    HashMap children = onRetainNonConfigurationChildInstances();
    FragmentManagerNonConfig fragments = mFragments.retainNestedNonConfig();


    mFragments.doLoaderStart();
    mFragments.doLoaderStop(true);
    ArrayMap loaders = mFragments.retainLoaderNonConfig();

    if (activity == null && children == null && fragments == null && loaders == null
            && mVoiceInteractor == null) {
        return null;
    }

    //创建NonConfigurationInstances配置类
    NonConfigurationInstances nci = new NonConfigurationInstances();
    nci.activity = activity;
    nci.children = children;
    nci.fragments = fragments;
    nci.loaders = loaders;
    if (mVoiceInteractor != null) {
        mVoiceInteractor.retainInstance();
        nci.voiceInteractor = mVoiceInteractor;
    }
    return nci;
}
  • onRetainNonConfigurationInstance(),Activity的空方法,被子类ComponentActivity复写
public Object onRetainNonConfigurationInstance() {
    return null;
}
  • ComponentActivity,子类复写该方法,保存自己的数据到父类的NonConfigurationInstances类中

其中,回调了一个onRetainCustomNonConfigurationInstance()方法,这个方法是提供给子类保存自定义对象的,所以如果我们有需求在配置重建时,保存一个对象,则可以复写该方法进行返回

@Override
@Nullable
public final Object onRetainNonConfigurationInstance() {
    //提供自定义对象给子类复写,保存自定义对象
    Object custom = onRetainCustomNonConfigurationInstance();

    ViewModelStore viewModelStore = mViewModelStore;
    if (viewModelStore == null) {
        //如果viewModelStore为null,获取最后一次保存的配置,如果获取到配置,则从配置中获取viewModelStore实例
        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        if (nc != null) {
            viewModelStore = nc.viewModelStore;
        }
    }

    //从配置中获取不到,并且没有自定义对象保存,则返回null
    if (viewModelStore == null && custom == null) {
        return null;
    }

    //需要保存,则创建NonConfigurationInstances实例,保存自定义对象和viewModelStore
    NonConfigurationInstances nci = new NonConfigurationInstances();
    nci.custom = custom;
    nci.viewModelStore = viewModelStore;
    return nci;
}
  • getLastNonConfigurationInstance(),获取保存的NonConfigurationInstances对象
@Nullable
public Object getLastNonConfigurationInstance() {
    return mLastNonConfigurationInstances != null
            ? mLastNonConfigurationInstances.activity : null;
}
  • Activity的attach()方法

我们知道,Activity的attach()方法,由ActivityThread会调用performLaunchActivity()方法

final void attach(Context context, ActivityThread aThread,
            Instrumentation instr, IBinder token, int ident,
            Application application, Intent intent, ActivityInfo info,
            CharSequence title, Activity parent, String id,
            NonConfigurationInstances lastNonConfigurationInstances,
            Configuration config, String referrer, IVoiceInteractor voiceInteractor,
            Window window, ActivityConfigCallback activityConfigCallback, IBinder assistToken) {
                //给配置类进行赋值
            mLastNonConfigurationInstances = lastNonConfigurationInstances; 
}

总结

ViewModel的保存和恢复流程如下

  • 保存:Activity因配置发生改变,ActivityThread会调用performDestroyActivity()方法,该方法调用了retainNonConfigurationInstances()方法,方法返回一个NonConfigurationInstances对象,该对象保存了ViewModel实例,然后NonConfigurationInstances对象被保存在了ActivityClientRecord

  • 恢复:Activity重建后,ActivityThread会调用performLaunchActivity()方法,该方法会调用Activity的attach()方法,该方法又会从ActivityClientRecord中把NonConfigurationInstances对象给Activity赋值

你可能感兴趣的:(Jetpack ViewModel源码分析)