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反射实现。判断配置发生变化,如:旋转屏幕,等到真正销毁才清空。

相关推荐
千里马学框架2 天前
一起学 Android 14:ShellTransition 屏幕旋转过程深度剖析
android·智能手机·性能优化·framework·性能·屏幕旋转·rotation
美狐美颜SDK开放平台2 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
AFinalStone2 天前
Android7 SystemUI源码解析(七)Keyguard锁屏模块深度解析
android·systemui
致远ccc2 天前
Google Play 上架前如何测试 App?多国家 Android 环境测试
android·app测试·googleplay·多国家应用测试
ttyyttemo2 天前
Kotlin 协程中的 Job 结构化并发与取消
android
sun0077002 天前
tbox 4g/5g切换,导致wan ip 改变,导致车机旧网络不可用。需要重启车机才行
android
其实防守也摸鱼2 天前
内网穿透与反向代理:原理、工具与实战指南
android·大数据·运维·安全·网络安全·自动化·渗透
AFinalStone2 天前
Android7 SystemUI 源码解析(四)NavigationBar 导航栏与 SystemBars
android·systemui
JMchen2 天前
属性动画原理与高级动画实现
android·kotlin·canvas
AFinalStone2 天前
Android7 SystemUI 源码解析(二)启动流程深度解析
android·systemui