Android Jetpack系列之ViewModel的基本逻辑

2022-05-09  本文已影响0人  Android程序员老鸦

如果把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)
            }
        }
    ...略
}
上一篇 下一篇

猜你喜欢

热点阅读