Android的ViewModel

前言

通过懒加载创建model

kotlin 复制代码
private val model by lazy {
    ViewModelProvider(this)[BaseViewModel::class.java]
}
class BaseViewModel : ViewModel() {

}

ViewmodelProvider实现:

kotlin 复制代码
public constructor(
    owner: ViewModelStoreOwner
) : this(owner.viewModelStore, defaultFactory(owner), defaultCreationExtras(owner))
// 创建Factory
internal fun defaultFactory(owner: ViewModelStoreOwner): Factory =
    if (owner is HasDefaultViewModelProviderFactory)
        owner.defaultViewModelProviderFactory else instance

用this的viewModelStore,创建Factory. this是传给ViewModelProvider的一个ViewModelStoreOwner接口的实现。

kotlin 复制代码
interface ViewModelStoreOwner {
    /**
     * The owned [ViewModelStore]
     */
    val viewModelStore: ViewModelStore
}

ComponentActivity/Fragment实现了ViewModelStoreOwner和HasDefaultViewModelProviderFactory。 ComponentActivity实现:

java 复制代码
@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.");
    }
    ensureViewModelStore();
    return mViewModelStore;
}

@SuppressWarnings("WeakerAccess") /* synthetic access */
void ensureViewModelStore() {
    if (mViewModelStore == null) {
        NonConfigurationInstances nc =
                (NonConfigurationInstances) getLastNonConfigurationInstance();
        if (nc != null) {
            // Restore the ViewModelStore from NonConfigurationInstances
            mViewModelStore = nc.viewModelStore;
        }
        if (mViewModelStore == null) {
            mViewModelStore = new ViewModelStore();
        }
    }
}

getLastNonConfigurationInstance没有就会new一个返回。 Fragment()实现:

implementation 'androidx.fragment:fragment-ktx:1.6.2'

java 复制代码
public ViewModelStore getViewModelStore() {
    if (mFragmentManager == null) {
        throw new IllegalStateException("Can't access ViewModels from detached fragment");
    }
    if (getMinimumMaxLifecycleState() == Lifecycle.State.INITIALIZED.ordinal()) {
        throw new IllegalStateException("Calling getViewModelStore() before a Fragment "
                + "reaches onCreate() when using setMaxLifecycle(INITIALIZED) is not "
                + "supported");
    }
    return mFragmentManager.getViewModelStore(this);
}

 void performAttach() {
   //省略部分代码
     mChildFragmentManager.attachController(mHost, createFragmentContainer(), this);
    }

FragmentManager:

java 复制代码
@NonNull
private FragmentManagerViewModel mNonConfig;
ViewModelStore getViewModelStore(@NonNull Fragment f) {
    return mNonConfig.getViewModelStore(f);
}


void attachController(@NonNull FragmentHostCallback<?> host,
            @NonNull FragmentContainer container, @Nullable final Fragment parent) {
 //省略部分代码
 
   if (parent != null) {
   // fragment如果嵌套了,则去找getChildNonConfig
            mNonConfig = parent.mFragmentManager.getChildNonConfig(parent);
        } else if (host instanceof ViewModelStoreOwner) {
        // 获取host的ViewModelStore,自己创建一个ViewModelProvider缓存FragmentManagerViewModel类进去
            ViewModelStore viewModelStore = ((ViewModelStoreOwner) host).getViewModelStore();
            mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore);
        } else {
        // 自己huost找不到,自己创建一个FragmentManagerViewModel,传入flase,表示不自动缓存
            mNonConfig = new FragmentManagerViewModel(false);
        }
    }
        
        mNonConfig.setIsStateSaved(isStateSaved());
// 设置setNonConfig()
        mFragmentStore.setNonConfig(mNonConfig);

FragmentManagerViewModel:

java 复制代码
private final HashMap<String, ViewModelStore> mViewModelStores = new HashMap<>();
@NonNull
ViewModelStore getViewModelStore(@NonNull Fragment f) {
    ViewModelStore viewModelStore = mViewModelStores.get(f.mWho);
    if (viewModelStore == null) {
        viewModelStore = new ViewModelStore();
        mViewModelStores.put(f.mWho, viewModelStore);
    }
    return viewModelStore;
}

@NonNull
    static FragmentManagerViewModel getInstance(ViewModelStore viewModelStore) {
        ViewModelProvider viewModelProvider = new ViewModelProvider(viewModelStore,
                FACTORY);
        return viewModelProvider.get(FragmentManagerViewModel.class);
    }

FragmentController

java 复制代码
public void attachHost(@Nullable Fragment parent) {
    mHost.mFragmentManager.attachController(
            mHost, mHost /*container*/, parent);
}

public static FragmentController createController(@NonNull FragmentHostCallback<?> callbacks) {
    return new FragmentController(checkNotNull(callbacks, "callbacks == null"));
}

FragmentActivity:

java 复制代码
final FragmentController mFragments = FragmentController.createController(new HostCallbacks());

 final FragmentController mFragments = FragmentController.createController(new HostCallbacks());

//内部类
 class HostCallbacks extends FragmentHostCallback<FragmentActivity>{
    // 省略部分代码
      @NonNull
        @Override
        public ViewModelStore getViewModelStore() {
            return FragmentActivity.this.getViewModelStore();
        }
 }

Fragment的ViewModel其实是委托给了FragmentManager。 Fragment李德mNonConfig.getViewModelStore(f),最后调用host.getViewModelStore()。host是FragmentActivity一个内部类。调用到FragmentActivity.this.getViewModelStore()。FragmentActivity继承了ComponentActivity。Fragment调用的是ComponentActivity的getViewModelStore()构建ViewModelProvider返回。如果不行,自己创建一个FragmentManagerViewModel(fasle)用于处理。 ViewModelStore:

kotlin 复制代码
open class ViewModelStore {

    private val map = mutableMapOf<String, ViewModel>()

    /**
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    fun put(key: String, viewModel: ViewModel) {
        val oldViewModel = map.put(key, viewModel)
        oldViewModel?.onCleared()
    }

    /**
     * Returns the `ViewModel` mapped to the given `key` or null if none exists.
     */
    /**
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    operator fun get(key: String): ViewModel? {
        return map[key]
    }

    /**
     * @hide
     */
    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP)
    fun keys(): Set<String> {
        return HashSet(map.keys)
    }

    /**
     * Clears internal storage and notifies `ViewModel`s that they are no longer used.
     */
    fun clear() {
        for (vm in map.values) {
            vm.clear()
        }
        map.clear()
    }
}

ViewModelStore是一个map,能存ViewModel和清除。 ViewModelProvider:

kotlin 复制代码
 @MainThread
    public open operator fun <T : ViewModel> get(modelClass: Class<T>): T {
        val canonicalName = modelClass.canonicalName
            ?: throw IllegalArgumentException("Local and anonymous classes can not be ViewModels")
        return get("$DEFAULT_KEY:$canonicalName", modelClass)
    }

    @Suppress("UNCHECKED_CAST")
    @MainThread
    public open operator fun <T : ViewModel> get(key: String, modelClass: Class<T>): T {
        val viewModel = store[key]
        if (modelClass.isInstance(viewModel)) {
            (factory as? OnRequeryFactory)?.onRequery(viewModel!!)
            return viewModel as T
        } else {
            @Suppress("ControlFlowWithEmptyBody")
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }
        val extras = MutableCreationExtras(defaultCreationExtras)
        extras[VIEW_MODEL_KEY] = key

        return try {
            factory.create(modelClass, extras)
        } catch (e: AbstractMethodError) {
            factory.create(modelClass)
        }.also { store.put(key, it) }
    }

拿传入的类名canonicalName前拼接DEAFULT_KEY,如果当前store有,且是当前类的实例,强转返回。没有就factory创建。最后调用also缓存进去。 ComonentActivity:

java 复制代码
@NonNull
@Override
public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
    if (mDefaultFactory == null) {
        mDefaultFactory = new SavedStateViewModelFactory(
                getApplication(),
                this,
                getIntent() != null ? getIntent().getExtras() : null);
    }
    return mDefaultFactory;
}

Fragment:

java 复制代码
@NonNull
@Override
public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
    if (mFragmentManager == null) {
        throw new IllegalStateException("Can't access ViewModels from detached fragment");
    }
    if (mDefaultFactory == null) {
        Application application = null;
        Context appContext = requireContext().getApplicationContext();
        while (appContext instanceof ContextWrapper) {
            if (appContext instanceof Application) {
                application = (Application) appContext;
                break;
            }
            appContext = ((ContextWrapper) appContext).getBaseContext();
        }
        if (application == null && FragmentManager.isLoggingEnabled(Log.DEBUG)) {
            Log.d(FragmentManager.TAG, "Could not find Application instance from "
                    + "Context " + requireContext().getApplicationContext() + ", you will "
                    + "need CreationExtras to use AndroidViewModel with the default "
                    + "ViewModelProvider.Factory");
        }
        mDefaultFactory = new SavedStateViewModelFactory(
                application,
                this,
                getArguments());
    }
    return mDefaultFactory;
}

上面都返回了SavedStateViewModelFactory。

java 复制代码
  @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);
    }


 public <T extends ViewModel> T create(@NonNull String key, @NonNull Class<T> modelClass) {
   //判断是否是isAndroidViewModel
        boolean isAndroidViewModel = AndroidViewModel.class.isAssignableFrom(modelClass);
        Constructor<T> constructor;
        if (isAndroidViewModel) {
            constructor = findMatchingConstructor(modelClass, ANDROID_VIEWMODEL_SIGNATURE);
        } else {
            constructor = findMatchingConstructor(modelClass, VIEWMODEL_SIGNATURE);
        }
        // doesn't need SavedStateHandle
        if (constructor == null) {
            return mFactory.create(modelClass);
        }

        SavedStateHandleController controller = SavedStateHandleController.create(
                mSavedStateRegistry, mLifecycle, key, mDefaultArgs);
        try {
            T viewmodel;
            if (isAndroidViewModel) {
                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());
        }
    }

判断是否是AndroidViewModel,newInstance(),反射。get()是从缓存拿,没有则反射一个新对象,also缓存进去。 Fragment正常情况下用FragmentActivity的ViewModelStore。FragmentActivity的父类ComponentActivity

java 复制代码
public ComponentActivity() {

  //省略部分代码
getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                // activity 销毁了
                if (event == Lifecycle.Event.ON_DESTROY) {
                    mContextAwareHelper.clearAvailableContext();
                    // 判断是否是屏幕旋转等情况下发生了
                    if (!isChangingConfigurations()) {
                        // 配置没发生变化,则正常清理
                        getViewModelStore().clear();
                    }
                }
            }
        });
}

在ON_DESTROY时候,判断!isChangingConfigurations(),配置没变化,就真正销毁,调用了getViewModelStore().clear();ViewModel不建议持有Context,因为onDestory后才执行清理ViewModel,所以旋转屏幕ViewModel不会丢数据,虽然走了onDestory内部判断了是否旋转屏幕的判断。

Fragment管理ViewModel

Fragment通过this拿ViewModel,两种情况。一种拿FragmentActivity的ViewModelStore。一种自己构建了FragmentManangerViewModel();这个mNonConfig塞进了mFragmentStore。

java 复制代码
 if (parent != null) {
            mNonConfig = parent.mFragmentManager.getChildNonConfig(parent);
        } else if (host instanceof ViewModelStoreOwner) {
            ViewModelStore viewModelStore = ((ViewModelStoreOwner) host).getViewModelStore();
            mNonConfig = FragmentManagerViewModel.getInstance(viewModelStore);
        } else {
            mNonConfig = new FragmentManagerViewModel(false);
        }
        // Ensure that the state is in sync with FragmentManager
        mNonConfig.setIsStateSaved(isStateSaved());
        mFragmentStore.setNonConfig(mNonConfig);

FragmentManager中:

java 复制代码
 private final FragmentStore mFragmentStore = new FragmentStore();
  FragmentManagerViewModel getNonConfig() {
        return mNonConfig;
    }

FragmentManager:

java 复制代码
private void clearBackStackStateViewModels() {
        boolean shouldClear;
        if (mHost instanceof ViewModelStoreOwner) {
            shouldClear = mFragmentStore.getNonConfig().isCleared();
        } else if (mHost.getContext() instanceof Activity) {
            Activity activity = (Activity) mHost.getContext();
            shouldClear = !activity.isChangingConfigurations();
        } else {
            shouldClear = true;
        }
        if (shouldClear) {
            for (BackStackState backStackState : mBackStackStates.values()) {
                for (String who : backStackState.mFragments) {
                   mFragmentStore.getNonConfig().clearNonConfigState(who, false);
                }
            }
        }
    }
     void dispatchDestroy() {
        mDestroyed = true;
        execPendingActions(true);
        endAnimatingAwayFragments();
        clearBackStackStateViewModels();
        //省略代码
        }

判断哪些Fragment需要清理。 FragmentController:

java 复制代码
public void dispatchDestroyView() {
        mHost.mFragmentManager.dispatchDestroyView();
    }

FragmentActivity:

java 复制代码
 @Override
    protected void onDestroy() {
        super.onDestroy();
        mFragments.dispatchDestroy();
       mFragmentLifecycleRegistry.handleLifecycleEvent(Lifecycle.Event.ON_DESTROY);
    }

FragmentActivity在onDestory调用FragmentController的mFragment.dispatchDestory()->FragmentManager.dispatchDestory->clearBackStackStateViewModels()。FragmentActivity销毁才销毁ViewModel。 FragmentStateManager重新构建时,也会销毁清理对应的ViewModel。

总结

ViewModel保存数据,页面变化能缓存。自动管理,页面销毁自动清理。Fragment和Activity可共用。Fragment可以拿到Activity的ViewModel(只看传入的类名,this)。 ComponentActivity监听onDestroy,清理。Fragment在FragmentActivity的onDestroy会清理。ViewModel就是一个map。通过内部factory反射实现。判断配置发生变化,如:旋转屏幕,等到真正销毁才清空。

相关推荐
小比卡丘1 小时前
C语言进阶版第17课—自定义类型:联合和枚举
android·java·c语言
前行的小黑炭2 小时前
一篇搞定Android 实现扫码支付:如何对接海外的第三方支付;项目中的真实经验分享;如何高效对接,高效开发
android
落落落sss3 小时前
MybatisPlus
android·java·开发语言·spring·tomcat·rabbitmq·mybatis
代码敲上天.4 小时前
数据库语句优化
android·数据库·adb
GEEKVIP6 小时前
手机使用技巧:8 个 Android 锁屏移除工具 [解锁 Android]
android·macos·ios·智能手机·电脑·手机·iphone
model20058 小时前
android + tflite 分类APP开发-2
android·分类·tflite
彭于晏6898 小时前
Android广播
android·java·开发语言
与衫9 小时前
掌握嵌套子查询:复杂 SQL 中 * 列的准确表列关系
android·javascript·sql
500了15 小时前
Kotlin基本知识
android·开发语言·kotlin
人工智能的苟富贵16 小时前
Android Debug Bridge(ADB)完全指南
android·adb