ViewModel 源碼解析


通過源碼解析掌握

  • ViewModel的創建過程
  • ViewModel的存在哪里
  • ViewModel的生命周期
  • 為什么Activity旋轉屏幕后ViewModel可以恢復數據

ViewModel的創建

通過之前對ViewModel的使用,了解ViewModel的創建是通過 ==ViewModelProvider== 來創建的

MyViewModel myViewModel = new ViewModelProvider(this).get(MyViewModel.class);
 //或者直接使用工具類創建
 
 //ViewModelProviders是一個工具類,對ViewModelProvider進行了封裝
 MyViewModel myViewModel = ViewModelProviders.of(this).get(MyViewModel.class);
 

傳遞的是class ,說明是通過反射來創建的,那么就從ViewModelProvider入手

[ViewModelProvider.java]

public class ViewModelProvider {

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

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

    static class OnRequeryFactory {
        void onRequery(@NonNull ViewModel viewModel) {
        }
    }

    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");
        }
    }

    private final Factory mFactory;
    private final ViewModelStore mViewModelStore;

    //ViewModelStoreOwner就是當前Activity,
    public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
        this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
                ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
                : NewInstanceFactory.getInstance());
    }


    public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
        this(owner.getViewModelStore(), factory);
    }

    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");
        }
        return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
    }

    
    @SuppressWarnings("unchecked")
    @NonNull
    @MainThread
    public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
        ViewModel viewModel = mViewModelStore.get(key);

        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.
            }
        }
        if (mFactory instanceof KeyedFactory) {
            viewModel = ((KeyedFactory) mFactory).create(key, modelClass);
        } else {
            viewModel = mFactory.create(modelClass);
        }
        mViewModelStore.put(key, viewModel);
        return (T) viewModel;
    }
    ...

ViewModel的提供者,ViewModelProvider類有兩個屬性

//負責創建ViewModel的工廠
 private final Factory mFactory;
 //負責存儲ViewModel的存儲器
 private final ViewModelStore mViewModelStore;

從構造函數來看,有三個構造函數

 public ViewModelProvider(@NonNull ViewModelStoreOwner owner) {
        this(owner.getViewModelStore(), owner instanceof HasDefaultViewModelProviderFactory
                ? ((HasDefaultViewModelProviderFactory) owner).getDefaultViewModelProviderFactory()
                : NewInstanceFactory.getInstance());
    }

 public ViewModelProvider(@NonNull ViewModelStoreOwner owner, @NonNull Factory factory) {
        this(owner.getViewModelStore(), factory);
    }

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

創建一個ViewModelProvider 實例對象,獲取創建ViewModel的Factory和ViewModelStore的實例對象,ViewModelStoreOwner表示自己存儲ViewModel功能的組件,Activity和Fragment都實現了該接口

public interface ViewModelStoreOwner {
    /**
     * Returns owned {@link ViewModelStore}
     *
     * @return a {@code ViewModelStore}
     */
    @NonNull
    ViewModelStore getViewModelStore();
}

該接口就是獲取ViewModelStore

接下來是調用 get(@NonNull Class<T> modelClass) 方法獲取ViewModel實例對象

  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");
        }
        return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
    }

public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
       //從ViewModelStore中獲取,如果有則返回,如果沒有則通過Factory創建一個實例對象
        ViewModel viewModel = mViewModelStore.get(key);

        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.
            }
        }
        //通過Factory創建ViewModel實例對象
        if (mFactory instanceof KeyedFactory) {
            viewModel = ((KeyedFactory) mFactory).create(key, modelClass);
        } else {
            viewModel = mFactory.create(modelClass);
        }
        mViewModelStore.put(key, viewModel);
        return (T) viewModel;
    }

這個方法主要功能:

  • 獲取類的標準類名,并拼接上默認的Key
  • 從ViewModelStore中查找是否有已創建的ViewModel
  • 如果ViewModelStore中沒有該ViewModel的實例對象,則通過Factory反射創建一個,并保存到ViewModelStore中

從K—V模式來開,ViewModelStore就是通過HashMap來保存ViewModel的
[ViewModelStore.java]

public class ViewModelStore {

    private final HashMap<String, ViewModel> mMap = new HashMap<>();

    final void put(String key, ViewModel viewModel) {
        ViewModel oldViewModel = mMap.put(key, viewModel);
        if (oldViewModel != null) {
            oldViewModel.onCleared();
        }
    }

    final ViewModel get(String key) {
        return mMap.get(key);
    }

    Set<String> keys() {
        return new HashSet<>(mMap.keySet());
    }

    /**
     *  Clears internal storage and notifies ViewModels that they are no longer used.
     */
    public final void clear() {
        for (ViewModel vm : mMap.values()) {
            vm.clear();
        }
        mMap.clear();
    }
}

這里很簡單了,就是HashMap,在Activity或者Fragment的銷毀的時候,將map 清空
具體實現在ComponentActivity類中
[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) {
                //不是屏幕橫豎屏切換,則清空Map
                    if (!isChangingConfigurations()) {
                        getViewModelStore().clear();
                    }
                }
            }
        });

      ...
    }

接下來看看Factory

/**
     * Simple factory, which calls empty constructor on the give class.
     */
    public static class NewInstanceFactory implements Factory {

        private static NewInstanceFactory sInstance;

        /**
         * Retrieve a singleton instance of NewInstanceFactory.
         *
         * @return A valid {@link 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) {
            //noinspection TryWithIdenticalCatches
            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);
            }
        }
    }

/**
     * {@link Factory} which may create {@link AndroidViewModel} and
     * {@link ViewModel}, which have an empty constructor.
     */
    public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {

        private static AndroidViewModelFactory sInstance;

        /**
         * Retrieve a singleton instance of AndroidViewModelFactory.
         *
         * @param application an application to pass in {@link AndroidViewModel}
         * @return A valid {@link AndroidViewModelFactory}
         */
        @NonNull
        public static AndroidViewModelFactory getInstance(@NonNull Application application) {
            if (sInstance == null) {
                sInstance = new AndroidViewModelFactory(application);
            }
            return sInstance;
        }

        private Application mApplication;

        /**
         * Creates a {@code AndroidViewModelFactory}
         *
         * @param application an application to pass in {@link AndroidViewModel}
         */
        public AndroidViewModelFactory(@NonNull Application application) {
            mApplication = application;
        }

        @NonNull
        @Override
        public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
        // 如果是AndroidViewModel,繼承了ViewModel并含有Application
            if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
                //noinspection TryWithIdenticalCatches
                try {
                    return modelClass.getConstructor(Application.class).newInstance(mApplication);
                } catch (NoSuchMethodException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                } catch (InstantiationException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                } catch (InvocationTargetException e) {
                    throw new RuntimeException("Cannot create an instance of " + modelClass, e);
                }
            }
            return super.create(modelClass);
        }
    }

實現了Factory的工廠類也很簡單,工廠是一個單例,沒有構造函數則通過NewInstanceFactory 反射創建
如果是AndroidViewModel則通過AndroidViewModelFactory創建

再來看一下旋轉屏幕后ViewModel是怎么恢復數據的,這塊代碼當然是在Activity里面了;這個方法就是當屏幕旋轉會調用的:

  @Override
    @Nullable
    public final Object onRetainNonConfigurationInstance() {
        Object custom = onRetainCustomNonConfigurationInstance();

        ViewModelStore viewModelStore = mViewModelStore;
        // 若 viewModelStore 為空,則嘗試從 getLastNonConfigurationInstance() 中獲取,mViewModelStore本身就是Activity的成員變量
        if (viewModelStore == null) {
            // No one called getViewModelStore(), so see if there was an existing
            // ViewModelStore from our last NonConfigurationInstance
            //
            NonConfigurationInstances nc =
                    (NonConfigurationInstances) getLastNonConfigurationInstance();
            if (nc != null) {
                viewModelStore = nc.viewModelStore;
            }
        }
        // 依然為空,說明沒有需要緩存的,則返回 null
        if (viewModelStore == null && custom == null) {
            return null;
        }
       // 創建 NonConfigurationInstances 對象,并賦值 viewModelStore
        NonConfigurationInstances nci = new NonConfigurationInstances();
        nci.custom = custom;
        nci.viewModelStore = viewModelStore;
        return nci;
    }

看了上面代碼,也就是說Activity 在因配置更改而銷毀重建過程中會先調用 onRetainNonConfigurationInstance 保存 viewModelStore 實例。
在重建后可以通過 getLastNonConfigurationInstance 方法獲取之前的 viewModelStore 實例。
這里就類似Activity的onSaveInstanceState(Bundle)了。

總結


  • ViewModel 實例對象是又ViewModelProvider提供的
  • 創建ViewModelProvider實例對象需要一個ViewModelStore和Factory,ViewModelStore由ViewModlestoreOwner提供,Activity和Fragment實現該接口,Activity組件當生命周期事件為ON_DESTORY 并且不是橫豎屏切換的時候則清空Map
  • ViewModelProvider主要的工作就是從ViewModelStore中查是否該實例對象已保存在map中,如果有則直接返回,如果沒有則通過Factory反射創建一個ViewModel并保存在ViewModelStore中
  • ViewModelStore在Activity或者Fragment生命周期結束的時候清空掉Map中保存的ViewModel
  • 屏幕旋轉保存數據的實現就類似我們的onSaveInstanceState的實現。
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容