Android Jetpack 组件之 ViewModel 详解

Android 框架可以管理 UI 控制器(ActivityFragment)的生命周期。Android 框架可能会决定销毁或重新创建 UI 控制器,以响应完全不受控制的某些用户操作或设备事件。

如果系统销毁或重新创建 UI 控制器,则存储在其中的任何临时性 UI 相关数据都会丢失。例如,应用的某个 Activity 中可能包含用户列表,因配置更改而重新创建 Activity 后,新 Activity 必须重新提取用户列表。对于简单的数据,Activity 可以使用 onSaveInstanceState() 方法从 onCreate() 方法中的 Bundle 恢复其数据,但此方法仅适合可以序列化再反序列化的少量数据,而不适合数量可能较大的数据,如用户列表或位图。

ViewModel 类被设计用于以感知生命周期的方式来管理和存储 UI 界面相关的数据,例如当屏幕发生旋转、App 权限被动态修改、系统语言发生改变(Configuration changes)的时候,Activity 重建的时候,ViewModel 可以保留 UI 界面的数据。

优点

ViewModel 具有以下优点:

  • 存储和管理数据
  • 避免内存泄漏
  • 解耦
  • 共享数据

依赖

要将 ViewModel 库引入到 Android 项目中,请将以下依赖项添加到应用或模块的 build.gradle 文件中:

dependencies {
    def lifecycle_version = "2.2.0"

    // ViewModel
    implementation "androidx.lifecycle:lifecycle-viewmodel:$lifecycle_version"
    // KTX for ViewModel
    implementation "androidx.lifecycle:lifecycle-viewmodel-ktx:$lifecycle_version"
    // Saved state module for ViewModel
    implementation "androidx.lifecycle:lifecycle-viewmodel-savedstate:$lifecycle_version"
}

使用

架构组件为界面控制器提供了 ViewModel 辅助类,该类负责为 UI 界面准备数据。在配置更改期间会自动保留 ViewModel 对象,以便它们存储的数据立即可供下一个 Activity 或 Fragment 实例使用。

如果需要在应用中显示用户列表,请确保将获取和保留该用户列表的责任分配给 ViewModel,而不是 ActivityFragment,示例代码如下所示:

public class UserViewModel extends ViewModel {

    private MutableLiveData<List<User>> users;

    public LiveData<List<User>> getUsers() {
        if (users == null) {
            users = new MutableLiveData<List<User>>();
            loadUsers();
        }
        return users;
    }

    private void loadUsers() {
        // Do an asynchronous operation to fetch users.
    }

}

然后,可以从 AppCompatActivity 访问 ViewModel 中的数据,如下所示:

public class UserActivity extends AppCompatActivity {

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        // Create a ViewModel the first time the system calls an activity's onCreate() method.
        // Re-created activities receive the same UserViewModel instance created by the first activity.
        UserViewModel model = new ViewModelProvider(this).get(UserViewModel.class);
        model.getUsers().observe(this, new Observer<List<User>>() {
            @Override
            public void onChanged(List<User> userList) {
                // update UI
            }
        });
    }

}

如果重新创建了该 Activity,它接收的 ViewModel 实例与第一个 Activity 创建的实例相同。当所有者 Activity 销毁时,框架会调用 ViewModel 对象的 onCleared() 方法以便于释放资源。

注意:ViewModel 绝不能引用 ViewLifecycle 或可能持有对 Activity 上下文的引用的任何类。

ViewModel 对象可以包含 LifecycleObserver,如 LiveData 对象。如果 ViewModel 需要持有 Application 上下文(可以查找系统服务),则可以继承 AndroidViewModel 类并设置用于接收 Application 的构造函数。

生命周期

ViewModel 对象存在的时间范围是获取 ViewModel 时传递给 ViewModelProviderLifecycleViewModel 将一直留在内存中,直到限定其存在时间范围的 Lifecycle 永久消失(Activity 被销毁或 Fragment 被移除)。ViewModel 的生命周期如下图所示:
ViewModel的生命周期

通常在系统首次调用 Activity 对象的 onCreate() 方法时创建 ViewModel。系统可能会在 Activity 的整个生命周期内多次调用 onCreate() 方法(如在旋转设备屏幕时)。ViewModel 存在的时间范围是从首次创建 ViewModel 直到 Activity 被销毁。

源码分析

ViewModelProviders

可以通过 ViewModelProviders.of().get(modelClass) 创建 ViewModelViewModelProviders 的源码如下:

public class ViewModelProviders {

    /**
     * 通过正在活动的Fragment对象创建ViewModelProvider对象
     */
    @Deprecated
    @NonNull
    @MainThread
    public static ViewModelProvider of(@NonNull Fragment fragment) {
        return new ViewModelProvider(fragment);
    }

    /**
     * 通过正在活动的Activity对象创建ViewModelProvider对象
     */
    @Deprecated
    @NonNull
    @MainThread
    public static ViewModelProvider of(@NonNull FragmentActivity activity) {
        return new ViewModelProvider(activity);
    }

    /**
     * 通过正在活动的Fragment对象和指定Factory创建ViewModelProvider对象
     */
    @Deprecated
    @NonNull
    @MainThread
    public static ViewModelProvider of(@NonNull Fragment fragment, @Nullable Factory factory) {
        if (factory == null) {
            factory = fragment.getDefaultViewModelProviderFactory();
        }
        return new ViewModelProvider(fragment.getViewModelStore(), factory);
    }

    /**
     * 通过正在活动的Activity对象和指定Factory创建ViewModelProvider对象
     */
    @Deprecated
    @NonNull
    @MainThread
    public static ViewModelProvider of(@NonNull FragmentActivity activity,
                                       @Nullable Factory factory) {
        if (factory == null) {
            factory = activity.getDefaultViewModelProviderFactory();
        }
        return new ViewModelProvider(activity.getViewModelStore(), factory);
    }

}

ViewModelProviders 内部将 FragmentActivity 转化为 ViewModelStore,实际还是通过 ViewModelProvider 类创建 ViewModel,并且 ViewModelProviders 类已被标记为过时。

ViewModelProvider

可以通过 new ViewModelProvider(owner).get(modelClass) 创建 ViewModelViewModelProvider 的源码如下:

public class ViewModelProvider {

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

    /** 实现负责实例化ViewModel的工厂 */
    public interface Factory {
        /**
         * 创建ViewModel实例
         */
        @NonNull
        <T extends ViewModel> T create(@NonNull Class<T> modelClass);
    }

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

    /** 根据Key获取ViewModel实例的Factory实现类 */
    abstract static class KeyedFactory extends OnRequeryFactory implements Factory {
        /**
         * 创建ViewModel实例
         */
        @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;                 // 实现负责实例化ViewModel的工厂
    private final ViewModelStore mViewModelStore;   // 用于存储ViewModel的类

    /**
     * 构造方法
     */
    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或创建新的ViewModel
     */
    @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");
        }
        // 创建、存储ViewModel使用的key
        return get(DEFAULT_KEY + ":" + canonicalName, modelClass);
    }

    /**
     * 返回与该ViewModelProvider关联的现有ViewModel或创建新的ViewModel
     */
    @SuppressWarnings("unchecked")
    @NonNull
    @MainThread
    public <T extends ViewModel> T get(@NonNull String key, @NonNull Class<T> modelClass) {
        // 从ViewModelStore中通过key获取ViewModel对象
        ViewModel viewModel = mViewModelStore.get(key);
        // 通过key获取的ViewModel对象与想要的Class相同直接返回
        if (modelClass.isInstance(viewModel)) {
            return (T) viewModel;
        } else {
            //noinspection StatementWithEmptyBody
            if (viewModel != null) {
                // TODO: log a warning.
            }
        }
        // 通过ViewModelFactory创建ViewModel类
        if (mFactory instanceof KeyedFactory) {
            viewModel = ((KeyedFactory) (mFactory)).create(key, modelClass);
        } else {
            viewModel = (mFactory).create(modelClass);
        }
        // 将创建的ViewModel对象添加到ViewModelStore中
        mViewModelStore.put(key, viewModel);
        return (T) viewModel;
    }

    /** 简单工厂(调用给定Class的空构造函数) */
    public static class NewInstanceFactory implements Factory {

        private static NewInstanceFactory sInstance;

        /**
         * 获取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 {
                // 调用给定Class的空构造函数创建ViewModel实例
                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);
            }
        }
    }

}

ViewModelStore

ViewModelStore 类用于存储创建的 ViewModel,避免 ViewModel 被重复创建。ViewModelStore 的源码如下:

public class ViewModelStore {

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

    /**
     * 根据key存储ViewModel对象
     */
    final void put(String key, ViewModel viewModel) {
        ViewModel oldViewModel = mMap.put(key, viewModel);
        if (oldViewModel != null) {
            oldViewModel.onCleared();
        }
    }

    /**
     * 根据key获取存储的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();
    }

}

ViewModelStore 内部其实就是一个存储 ViewModelHashMap,并且提供 clear() 方法清空所有内容。

SavedStateViewModelFactory

FragmentComponentActivity 都实现了 HasDefaultViewModelProviderFactoryViewModelStoreOwner 接口,因此 ViewModelStore 类中创建 ViewModelFactory 都是通过 FragmentComponentActivitygetDefaultViewModelProviderFactory() 方法得到的。getDefaultViewModelProviderFactory() 方法的源码如下:

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) {
        mDefaultFactory = new SavedStateViewModelFactory(
                getApplication(),
                this,
                getIntent() != null ? getIntent().getExtras() : null);
    }
    return mDefaultFactory;
}

通过分析源码可以发现,最终的创建 ViewModelFactory 就是 SavedStateViewModelFactory 类,SavedStateViewModelFactory 继承了 ViewModelProvider 中的 KeyedFactory 抽象类。SavedStateViewModelFactory 的源码如下:

public final class SavedStateViewModelFactory extends ViewModelProvider.KeyedFactory {

    private final Application mApplication;
    private final ViewModelProvider.AndroidViewModelFactory mFactory; // 创建ViewModel的工厂
    private final Bundle mDefaultArgs;                     // 来自Fragment/Activity对象
    private final Lifecycle mLifecycle;                    // 来自Fragment/Activity对象
    private final SavedStateRegistry mSavedStateRegistry;  // 来自Fragment/Activity对象

    /**
     * 构造方法
     */
    public SavedStateViewModelFactory(@NonNull Application application,
                                      @NonNull SavedStateRegistryOwner owner,
                                      @Nullable Bundle defaultArgs) {
        mSavedStateRegistry = owner.getSavedStateRegistry();
        mLifecycle = owner.getLifecycle();
        mDefaultArgs = defaultArgs;
        mApplication = application;
        mFactory = ViewModelProvider.AndroidViewModelFactory.getInstance(application);
    }

    /**
     * 创建ViewModel
     */
    @NonNull
    @Override
    public <T extends ViewModel> T create(Class<T> modelClass) {
        // 用作创建ViewModel的key
        String canonicalName = modelClass.getCanonicalName();
        if (canonicalName == null) {
            throw new IllegalArgumentException("Local and anonymous classes can not be ViewModels");
        }
        return create(canonicalName, modelClass);
    }

    /**
     * 创建ViewModel
     */
    @NonNull
    @Override
    public <T extends ViewModel> T create(@NonNull String key, @NonNull Class<T> modelClass) {
        // 判断是否为AndroidViewModel的实现类
        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) {
            // 这里调用的是 AndroidViewModelFactory 的 create 方法
            return mFactory.create(modelClass);
        }
        // SavedStateHandleController实现LifecycleEventObserver接口
        SavedStateHandleController controller = SavedStateHandleController.create(
                mSavedStateRegistry, mLifecycle, key, mDefaultArgs);
        try {
            // 创建ViewModel对象
            T viewmodel;
            if (isAndroidViewModel) {
                viewmodel = constructor.newInstance(mApplication, controller.getHandle());
            } else {
                viewmodel = constructor.newInstance(controller.getHandle());
            }
            // 保存controller到ViewModel实例中
            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());
        }
    }


    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()) {
            Class<?>[] parameterTypes = constructor.getParameterTypes();
            if (Arrays.equals(signature, parameterTypes)) {
                return (Constructor<T>) constructor;
            }
        }
        return null;
    }

}

SavedStateHandleController

SavedStateViewModelFactory 在创建 ViewModel 时用到了 SavedStateViewModelFactory 类,SavedStateViewModelFactory 实际上是用于保存页面数据及根据生命周期事件来对自己进行管理。SavedStateViewModelFactorycreate() 方法源码如下:

static SavedStateHandleController create(SavedStateRegistry registry, Lifecycle lifecycle,
                                             String key, Bundle defaultArgs) {
    // 消耗先前由SavedStateProvider提供的保存状态,该状态是通过key存储的Bundle对象
    Bundle restoredState = registry.consumeRestoredStateForKey(key);
    // 将之前的保存状态和现在进行合并,放到SavedStateHandle中
    SavedStateHandle handle = SavedStateHandle.createHandle(restoredState, defaultArgs);
    // 创建持有key和handle的SavedStateHandleController对象
    SavedStateHandleController controller = new SavedStateHandleController(key, handle);
    // 添加监听和注册SavedStateProvider到SavedStateRegistry里
    controller.attachToLifecycle(registry, lifecycle);
    tryToAddRecreator(registry, lifecycle);
    return controller;
}

AndroidViewModelFactory

AndroidViewModelFactory 继承了 NewInstanceFactory,用于创建 AndroidViewModel 子类的实例,满足那些需要持有 Context 实例的 ViewModel 能快速实现。

AndroidViewModelFactory 采用单例模式,通过反射调用带 Application 参数的构造器方法创建 ViewModel 实例,如果创建失败则调用默认构造器创建。AndroidViewModelFactory 的源码如下:

/** 用于创建AndroidViewModel和ViewModel的工厂 */
public static class AndroidViewModelFactory extends ViewModelProvider.NewInstanceFactory {

    private static AndroidViewModelFactory sInstance;

    /**
     * 获取AndroidViewModelFactory实例(单例模式)
     */
    @NonNull
    public static AndroidViewModelFactory getInstance(@NonNull Application application) {
        if (sInstance == null) {
            sInstance = new AndroidViewModelFactory(application);
        }
        return sInstance;
    }

    private Application mApplication;

    /**
     * 创建AndroidViewModelFactory
     */
    public AndroidViewModelFactory(@NonNull Application application) {
        mApplication = application;
    }

    @NonNull
    @Override
    public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
        // 判断modelClass对象表示的类是否为AndroidViewModel的子类
        if (AndroidViewModel.class.isAssignableFrom(modelClass)) {
            try {
                // 通过反射调用带Application参数的构造器方法创建AndroidViewModel实例
                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);
            }
        }
        // 调用父类的create()方法创建ViewModel实例(内部实际上是调用默认构造器创建)
        return super.create(modelClass);
    }

}

参考

ViewModel Overview


评论
 上一篇
Android Jetpack 组件之 WorkManager 详解 Android Jetpack 组件之 WorkManager 详解
WorkManager 组件是由 Google 提供的用来管理后台工作任务。Android 已经有很多管理后台任务的类了,比如 JobScheduler、AlarmManger,再比如 AsyncTask、ThreadPool。WorkMa
2019-12-07
下一篇 
Android Jetpack 组件之 LiveData 详解 Android Jetpack 组件之 LiveData 详解
LiveData 是一个可观察的数据持有者类,与常规 Observable 不同,LiveData 是生命周期感知的,LiveData 也是 Android Jetpack 组件的一部分。 简介LiveData 是一个可观察的数据持有者类,
2019-11-17
  目录