美文网首页
Android Jetpack系列之ViewModel的基本逻辑

Android Jetpack系列之ViewModel的基本逻辑

作者: Android程序员老鸦 | 来源:发表于2022-05-09 00:07 被阅读0次

    如果把Activity比喻成一栋大房子,LiveData就好比一个个家丁,那ViewModel就是那个大管家,他管理着房子的大大小小的事务和每个家丁的日常工作。
    ViewModel的设计目的可以概况成以下几点:

    1.维护Activity的数据不随着Activity的各种生命异常而丢失,比如手机的横竖屏切换的时候;
    2.承担起Activity控制层的作用,让Activity的代码不至于太膨胀,便于维护;
    3.在作用域可控的情况下管理各种异步请求和数据的生命敏感事件。

    这就是谷歌给开发者的一套标准的开发app的指导方案,很权威,很nice,用完你会感叹相见恨晚。
    先来看看ViewModel的创建,继承ViewModel即可:

    class MainViewModel : ViewModel() {
        // 维护了一个liveData
        private val testLiveData = MutableLiveData(0)
        // get方法只返回liveData,这样就实现了liveData的读写分离,在viewModel里更改,activity里读取
        fun getTestLiveData(): LiveData<Int> {
            return testLiveData
        }
    }
    

    怎么实例化呢,官方不推荐直接new出来,而是这样:

    class MainActivity : AppCompatActivity() {
        private lateinit var mainViewModel: MainViewModel
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
            // 官方推荐的实例化方式
            mainViewModel = ViewModelProvider(this).get(MainViewModel::class.java)
       
        }
    }
    

    那就从ViewModelProvider开始入手,看看ViewModel是基于什么原理设计和维护的,先看看ViewModelProvider的构造方法和get方法:

    public class ViewModelProvider {
        // 维护了两个成员变量,实际上也都是他们俩在做事
        private final Factory mFactory; // 创建ViewModel实例的工厂
        private final ViewModelStore mViewModelStore; // 字面意思就是ViewModel存储类
        //
        public interface Factory {
            /**
             * Creates a new instance of the given {@code Class}.
             * <p>
             *
             * @param modelClass a {@code Class} whose instance is requested
             * @param <T>        The type parameter for the ViewModel.
             * @return a newly created ViewModel
             */
            @NonNull
            <T extends ViewModel> T create(@NonNull Class<T> modelClass);
        } 
        // ViewModelStoreOwner是个接口,字面意思是ViewModelStore拥有者,根据谷歌jetpack代码命名规律也能猜到它的作用是能提供
       //ViewModelStore ,我们在上面的示例传入了自身Activity this,说明父类实现了ViewModelStoreOwner接口。
        public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
            // ComponentActivity也实现了HasDefaultViewModelProviderFactory,下面我们把它相关方法也贴出来
            this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
                    ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
                    : NewInstanceFactory.getInstance());
        }
        // 最终给两个成员变量完成了赋值
        public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
            mFactory = factory;
            mViewModelStore = store;
        }
    
    
         @NonNull
        @MainThread
        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");
            }
            //  key加了DEFAULT_KEY 拼装起来
            return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
        }
    
    
        @NonNull
        @MainThread
        public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
            // 先从mViewModelStore里取,这里猜测应该是个缓存
            ViewModel viewModel = mViewModelStore.get(key);
            // 如果是ViewModel的子类对象并且mFactory是OnRequeryFactory子类对象
            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.
                }
            }
            // 用相应的工厂创建ViewModel实例
            if (mFactory instanceof KeyedFactory) {
                viewModel = ((KeyedFactory) mFactory).create(key, modelClass);
            } else {
                viewModel = mFactory.create(modelClass);
            }
            // 放入缓存
            mViewModelStore.put(key, viewModel);
            return (T) viewModel;
        }
      ...略
    }
    

    ViewModelProvider的两个成员变量mViewModelStore 和mFactory 分别来自ComponentActivity的getViewModelStore()和getDefaultViewModelProviderFactory() 方法:

    public class ComponentActivity extends androidx.core.app.ComponentActivity implements
            ...
            ViewModelStoreOwner,
            HasDefaultViewModelProviderFactory,
            SavedStateRegistryOwner {
    
        @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.");
            }
            // 这个方法就是创建了一个ViewModelStore赋值给了mViewModelStore
            ensureViewModelStore();
            return mViewModelStore;
        }
    
        @NonNull
        @Override
        public final SavedStateRegistry getSavedStateRegistry() {
            return mSavedStateRegistryController.getSavedStateRegistry();
        }
    
        @NonNull
        @Override
        public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
            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 (mDefaultFactory == null) {
                // 创建的是SavedStateViewModelFactory,看命名是保存状态的vm工厂,注意这个构造函数穿了些啥
                mDefaultFactory = new SavedStateViewModelFactory(
                        getApplication(),
                        this,
                        getIntent() != null ? getIntent().getExtras() : null);
            }
            return mDefaultFactory;
        }
    }
    
    // ViewModelStore 专门用来存储ViewModel
    public class ViewModelStore {
        // 熟悉的存储方式,map
        private final HashMap<String, ViewModel> mMap = new HashMap<>();
        // 存储
        final void put(String key, ViewModel viewModel) {
            ViewModel oldViewModel = mMap.put(key, viewModel);
            // 如果之前存储了相同的,执行一下onCleared方法
            if (oldViewModel != null) {
                oldViewModel.onCleared();
            }
        }
        // 取缓存
        final ViewModel get(String key) {
            return mMap.get(key);
        }
        
        Set<String> keys() {
            return new HashSet<>(mMap.keySet());
        }
    
        /**
         *  清除所有的viewModel
         */
        public final void clear() {
            for (ViewModel vm : mMap.values()) {
                vm.clear();
            }
            // 注意会执行viewModel的clear方法
            mMap.clear();
        }
    }
    
    注意:其实到这里你基本应该已经知道了ViewModel是怎么被创建和保存起来的了,以下内容只是探寻ViewModel究竟是怎么被实例化的,提前透露一下就是用类名通过newInstance()实例化的。
    现在做个小总结:ViewModel如果通过ViewModelProvider的get方法实例化的话,同一个Activity(ViewModelStoreOwner)里只会实例化一个实例然后缓存到ViewModelStore里,每次获取的时候是会先取缓存,所以保证了同一个ViewModel的唯一性!

    再来看SavedStateViewModelFactory:

    public final class SavedStateViewModelFactory extends ViewModelProvider.KeyedFactory {
        private final Application mApplication;
        private final ViewModelProvider.Factory mFactory; // 实际是这个工厂在创建vm实例
        private final Bundle mDefaultArgs;
        private final Lifecycle mLifecycle; // 维护了一个lifecycle
        private final SavedStateRegistry mSavedStateRegistry; // 所谓的保存状态应该跟这个有关
    
       
        public SavedStateViewModelFactory(@Nullable  Application application,
                @NonNull SavedStateRegistryOwner owner) {
            this(application, owner, null);
        }
        @SuppressLint("LambdaLast")
        public SavedStateViewModelFactory(@Nullable Application application,
                @NonNull SavedStateRegistryOwner owner,
                @Nullable Bundle defaultArgs) {
            mSavedStateRegistry = owner.getSavedStateRegistry();
            mLifecycle = owner.getLifecycle();
            mDefaultArgs = defaultArgs;
            mApplication = application;
            // 前面调用这个构造函数是传下来了application的,所以这里执行的是
            // ViewModelProvider.AndroidViewModelFactory.getInstance(application)
            mFactory = application != null
                    ? ViewModelProvider.AndroidViewModelFactory.getInstance(application)
                    : ViewModelProvider.NewInstanceFactory.getInstance();
        }
        // 这里是ViewModelProvider里创建viewModel调用的方法
        @NonNull
        @Override
        public <T extends ViewModel> T create(@NonNull String key, @NonNull Class<T> modelClass) {
            // 我们创建一般的ViewModel,不是继承自AndroidViewModel,所以是false
            boolean isAndroidViewModel = AndroidViewModel.class.isAssignableFrom(modelClass);
            Constructor<T> constructor;
            if (isAndroidViewModel && mApplication != null) {
                constructor = findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE);
            } else {
                // 所以会命中这里,去找匹配的构造函数,这个方法在下面
                constructor = findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE);
            }
            // doesn't need SavedStateHandle 
           //不需要SavedStateHandle ,至于需要的情况那是另外的应用场景,可以单独去了解
            if (constructor == null) {
                // 绕了半天,其实还是执行了这个创建方法,我们继续看AndroidViewModelFactory
                return mFactory.create(modelClass);
            }
            // 这里的逻辑是关于SavedStateHandle ,暂不细看
            SavedStateHandleController controller = SavedStateHandleController.create(
                    mSavedStateRegistry, mLifecycle, key, mDefaultArgs);
            try {
                T viewmodel;
                if (isAndroidViewModel && mApplication != null) {
                    viewmodel = constructor.newInstance(mApplication, controller.getHandle());
                } else {
                    viewmodel = constructor.newInstance(controller.getHandle());
                }
                viewmodel.setTagIfAbsent(TAG_SAVED_STATE_HANDLE_CONTROLLER, controller);
                return viewmodel;
            } catch (IllegalAccessException e) {
                throw new RuntimeException("Failed to access " + modelClass, e);
            } catch (InstantiationException e) {
                throw new RuntimeException("A " + modelClass + " cannot be instantiated.", e);
            } catch (InvocationTargetException e) {
                throw new RuntimeException("An exception happened in constructor of "
                        + modelClass, e.getCause());
            }
        }
    @NonNull
        @Override
        public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
            // ViewModelProvider calls correct create that support same modelClass with different keys
            // If a developer manually calls this method, there is no "key" in picture, so factory
            // simply uses classname internally as as key.
            String canonicalName = modelClass.getCanonicalName();
            if (canonicalName == null) {
                throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
            }
            return create(canonicalName, modelClass);
        }
    
        private static final Class<?>[] ANDROID_VIEWMODEL_SIGNATURE = new Class[]{Application.class,
                SavedStateHandle.class};
        private static final Class<?>[] VIEWMODEL_SIGNATURE = new Class[]{SavedStateHandle.class};
    
        @SuppressWarnings("unchecked")
        private static <T> Constructor<T> findMatchingConstructor(Class<T> modelClass,
                Class<?>[] signature) {
            for (Constructor<?> constructor : modelClass.getConstructors()) {
                 // 这里会去找入参是SavedStateHandle类型的构造函数,显然我们一般的
                //ViewModel是没有这个构造函数的,这里会返回null,我们继续回到上面
                Class<?>[] parameterTypes = constructor.getParameterTypes();
                if (Arrays.equals(signature, parameterTypes)) {
                    return (Constructor<T>) constructor;
                }
            }
            return null;
        }
    
        @Override
        void onRequery(@NonNull ViewModel viewModel) {
            attachHandleIfNeeded(viewModel, mSavedStateRegistry, mLifecycle);
        }
    }
    

    \color{red} {AndroidViewModelFactory:}

     public open class AndroidViewModelFactory( private val application: Application) : NewInstanceFactory() {
           // 通过上面的分析我们知道是调用了这个方法来创建ViewModel的
            override fun <T : ViewModel> create(modelClass: Class<T>): T {
                // 上面我们也分析过我们的viewModel不是AndroidViewModel的子类
                return if (AndroidViewModel::class.java.isAssignableFrom(modelClass)) {
                    try {
                        modelClass.getConstructor(Application::class.java).newInstance(application)
                    } catch (e: NoSuchMethodException) {
                        throw RuntimeException("Cannot create an instance of $modelClass", e)
                    } catch (e: IllegalAccessException) {
                        throw RuntimeException("Cannot create an instance of $modelClass", e)
                    } catch (e: InstantiationException) {
                        throw RuntimeException("Cannot create an instance of $modelClass", e)
                    } catch (e: InvocationTargetException) {
                        throw RuntimeException("Cannot create an instance of $modelClass", e)
                    }
                // 所以最终是调用了父类的create方法,下面接着看父类NewInstanceFactory
                } else super.create(modelClass)
            }
    
        }
    

    \color{red} {NewInstanceFactory:}

      public open class NewInstanceFactory : Factory {
            @Suppress("DocumentExceptions")
            override fun <T : ViewModel> create(modelClass: Class<T>): T {
                return try {
                    // 好嘛,最后就是简单的反射创建的
                    modelClass.newInstance()
                } catch (e: InstantiationException) {
                    throw RuntimeException("Cannot create an instance of $modelClass", e)
                } catch (e: IllegalAccessException) {
                    throw RuntimeException("Cannot create an instance of $modelClass", e)
                }
            }
        ...略
    }
    

    相关文章

      网友评论

          本文标题:Android Jetpack系列之ViewModel的基本逻辑

          本文链接:https://www.haomeiwen.com/subject/desmyrtx.html