ViewModel分析

MainViewModel mainViewModel = new ViewModelProvider(this).get(MainViewModel.class);

MainViewModel mainViewModel = new ViewModelProvider(getActivity()).get(MainViewModel.class);

上面两行代码中,第一行的“this” 关键字,既可以指代Activity本身,也可以指代Fragment本身。上第二行的“getActivity()”,则只能是指代Fragment的宿主Activity。

因此,Fragment之间的通信,我们可以通过这个上面第二行的方式,通过要通信的几个Fragment及宿主Activity共同创建一个ViewModel对象,在ViewModel对象中实现跨Fragment+Activity通信。

创建一个ViewModel,为什么在Activity/Fragment意外销毁(如旋转屏幕,黑白夜模式切换,语音言换)后,重启,ViewModel还存在,且与之前一样,没发生变化?

    public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
        // 在 Activity/Fragment中,实现的都是 ViewModelStoreOwner 接口,因此,在Activity/Fragment创建 ViewModel 对象时,
        // 下面 this()方法的第二个参数 对应的三目运算,通常会执行 后面的部分:NewInstanceFactory.getInstance()。
        this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
                ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
                : NewInstanceFactory.getInstance());
    }

最后调用到这里:

    public ViewModelProvider(@NonNull ViewModelStore store, @NonNull Factory factory) {
        mFactory = factory;
        mViewModelStore = store;
    }    

其中 mFactory 和 mViewModelStore定义如下:

private final Factory mFactory;
private final ViewModelStore mViewModelStore;

Factory是一个接口,轻定义如下:

    public interface Factory {
        @NonNull
        <T extends ViewModel> T create(@NonNull Class<T> modelClass);
    }    

ViewModelStore 定义如下:    

public class ViewModelStore {
    private final HashMap<String, ViewModel> mMap = new HashMap<>();
    // 执行put方法时,会判断 传入的“key”是否存在对应的 ViewModel 对象,如果存在,则执行 onCleared()方法。
    // 当然 ViewModel 的 onCleared()方法是一个空实现,具体的逻辑需要开发者自己去实现。
    final void put(String key, ViewModel viewModel) {
        ViewModel oldViewModel = mMap.put(key, viewModel);
        if (oldViewModel != null) {
            oldViewModel.onCleared();
        }
    }
    // 根据 传进来的key,获取对应的 ViewModel 对象。当 Activity/Fragment意外销毁时,ViewModelStore对象还是存在的,并没有随之销毁。
    // 因此 Activity/Fragment 重建后,会调用该 get()方法重新获取到 ViewModel 对象。
    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();
        }
        mMap.clear();
    }
}    

onCleared()方法实现如下:    

    protected void onCleared() {

    }    

ViewModel的 clear()方法实现如下:

    @MainThread
    final void clear() {
        mCleared = true;
        if (mBagOfTags != null) {
            synchronized (mBagOfTags) {
                for (Object value : mBagOfTags.values()) {
                    closeWithRuntimeException(value);
                }
            }
        }
        onCleared();
    }   

首先,我们要主要到该方法的注解:@MainThread,表明该方法只能是在主线程里面执行。

其次,mBagOfTags 定义如下:

    @Nullable
    private final Map<String, Object> mBagOfTags = new HashMap<>();

因此,mBagOfTags一定不为空,上面clear()方法的if(){...}判断会执行。 closeWithRuntimeException()方法实现如下:      

    private static void closeWithRuntimeException(Object obj) {
        if (obj instanceof Closeable) {
            try {
                ((Closeable) obj).close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }

ViewModelStore的 clear()方法在 Activity的 onDestroy()方法中调用:

ComponentActivity.java中的调用如下:

    public ComponentActivity() {
        getLifecycle().addObserver(new LifecycleEventObserver() {
            @Override
            public void onStateChanged(@NonNull LifecycleOwner source,
                    @NonNull Lifecycle.Event event) {
                if (event == Lifecycle.Event.ON_DESTROY) {
                    // Clear out the available context
                    mContextAwareHelper.clearAvailableContext();
                    // And clear the ViewModelStore
                    if (!isChangingConfigurations()) {
                        getViewModelStore().clear();
                    }
                }
            }
        });
    }

ViewModelStore的 clear()方法在Fragment中,并不是由Fragment本身调用的,而是由 FragmentManagerViewModel.java调用的:    

    void clearNonConfigState(@NonNull Fragment f) {
        if (FragmentManager.isLoggingEnabled(Log.DEBUG)) {
            Log.d(TAG, "Clearing non-config state for " + f);
        }
        // Clear and remove the Fragment's child non config state
        FragmentManagerViewModel childNonConfig = mChildNonConfigs.get(f.mWho);
        if (childNonConfig != null) {
            childNonConfig.onCleared();
            mChildNonConfigs.remove(f.mWho);
        }
        // Clear and remove the Fragment's ViewModelStore
        ViewModelStore viewModelStore = mViewModelStores.get(f.mWho);
        if (viewModelStore != null) {
            viewModelStore.clear();
            mViewModelStores.remove(f.mWho);
        }
    }

或者在Jetpack组件中的 navigation 组件的 NavControllerViewModel.java 调用(NavControllerViewModel继承了ViewModel):   

 private final HashMap<UUID, ViewModelStore> mViewModelStores = new HashMap<>();
     void clear(@NonNull UUID backStackEntryUUID) {
        // Clear and remove the NavGraph's ViewModelStore
        ViewModelStore viewModelStore = mViewModelStores.remove(backStackEntryUUID);
        if (viewModelStore != null) {
            viewModelStore.clear();
        }
    }


    @Override
    protected void onCleared() {
        for (ViewModelStore store: mViewModelStores.values()) {
            store.clear();
        }
        mViewModelStores.clear();
    }

mViewModelStores变量保存ViewModelStore对象的put()方法:

    @NonNull
    ViewModelStore getViewModelStore(@NonNull UUID backStackEntryUUID) {
        ViewModelStore viewModelStore = mViewModelStores.get(backStackEntryUUID);
        if (viewModelStore == null) {
            viewModelStore = new ViewModelStore();
            mViewModelStores.put(backStackEntryUUID, viewModelStore);
        }
        return viewModelStore;
    }

该方法既执行了 mViewModelStores 的get()方法,也执行了 mViewModelStores 的put()方法。 ViewModelStore分析完,我们在回到 Factory 接口,在这里,他一共有两个 实现类:

抽象类 KeyedFactory 如下:    

    abstract static class KeyedFactory extends OnRequeryFactory implements Factory {
        @NonNull
        public abstract <T extends ViewModel> T create(@NonNull String key,
                @NonNull Class<T> modelClass);

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

实体类 NewInstanceFactory 如下:    

    public static class NewInstanceFactory implements Factory {
        private static NewInstanceFactory sInstance;
        // 该方法在 ViewModelProvider 的构造方法中被引用到,创建一个 NewInstanceFactory 对象
        @NonNull
        static NewInstanceFactory getInstance() {
            if (sInstance == null) {
                sInstance = new NewInstanceFactory();
            }
            return sInstance;
        }

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

这两个 Factory 的子类,关键的都是 各自的create()方法,后面我还还会提到。

上面是 我们在创建 MainViewModel 对象时,第一步操作“new ViewModelProvider(this)”所看到的。

然后是 new ViewModelProvider(this).get(MainViewModel.class)后面的get()方法,他的实现如下:

    @NonNull
    @MainThread
    public <T extends ViewModel> T get(@NonNull Class<T> modelClass) {
        // Class.getCanonicalName()返回的是 该类的 package包名 + 类名。不是全限定名。
        String canonicalName = modelClass.getCanonicalName();
        if (canonicalName == null) {
            throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
        }
        return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
    }

静态变量 DEFAULT_KEY定义如下:    

private static final String DEFAULT_KEY = "androidx.lifecycle.ViewModelProvider.DefaultKey";

因此,某个指定的 ViewModel所对应的key值“DEFAULT_KEY + ":" + canonicalName”,永远是不变的,相当于是final类型的。

然后get()方法调用到:    

    @NonNull
    @MainThread
    public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
        // 从上面分析过的 mViewModelStore 对象中 的 mMap 变量中获取 key 值对应的 ViewModel对象
        ViewModel viewModel = mViewModelStore.get(key);
        // 如果我们传进来的 ViewModel 类与这里获取到的 ViewModel对象的类是同一个,就表明 我们所要创建 ViewModel的对象已经存在了会直接返回;
        // 因此,当我们反复的调用 ViewModelProvider 去创建 ViewModel的对象 时,系统只会创建一次,之后世界从 mMap 中去获取,容纳后return返回。
        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.
            }
        }
        // 如果我们在初始化 ViewModelProvider 时,传进来的 Factory 对象是 KeyedFactory 类型的,
        // 那么久调用 KeyedFactory的 create()方法去创建一个 ViewModel 对象,并保存到 mMap中。
        if (mFactory instanceof KeyedFactory) {
            viewModel = ((KeyedFactory) mFactory).create(key, modelClass);
        // 如果我们在初始化 ViewModelProvider 时,传进来的 Factory 对象是 NewInstanceFactory 类型的,
        // 就调用 NewInstanceFactory 的 create()方法去创建一个 ViewModel 对象,并保存到 mMap中。
        } else {
            viewModel = mFactory.create(modelClass);
        }
        // 最后是调用 put()方法,将创建的 ViewModel 对象保存到 mViewModelStore 对象中 的 mMap 变量中
        mViewModelStore.put(key, viewModel);
        return (T) viewModel; // 返回创建的 ViewModel 对象。
    }

NewInstanceFactory的create()方法如下:           

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

在比较靠前的地方,我提到过,ViewModelProvider的构造方法里面的三目运算,执行的是后面的一个:

 NewInstanceFactory.getInstance()

因此,上面的get()方法中,mFactory 是 NewInstanceFactory 类型的,不是 KeyedFactory 类型的,因此,get()方法的if判断:

        if (mFactory instanceof KeyedFactory) {
            viewModel = ((KeyedFactory) mFactory).create(key, modelClass);
        } else {
            viewModel = mFactory.create(modelClass);
        }

会执行 else { ...... } 分支,在 NewInstanceFactory 的 create()方法 中,通过反射的形式,创建ViewModel对象。

然后执行:

mViewModelStore.put(key, viewModel);

将创建的 ViewModel对象 保存到 ViewModelStore 里面的 mMap中。

就这样,即便当Activity/Fragment因意外而销毁时,ViewModelStore中保存的对应的 Activity/Fragment的ViewModel对象还在,因此,Activity/Fragment重建时,执行onCreate()方法时,就能直接获取到 ViewModel对象,并从中读取到数据,恢复状态。

  • 8
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值