Dagger Hilt - ViewModel的依赖注入及实现原理

    技术2025-07-07  20

    Dagger Hilt

    Hilt是谷歌最新发布的DI库,降低了Android中Dagger的使用成本,支持各种常见Android组件的注入,也包括我们常用的ViewModel。

    Dagger Hilt - Android官方推荐的依赖注入框架 一文中介绍了ViewModel的注入方法,使用起来非常简单:

    class ActivityViewModel @ViewModelInject constructor( private val repository: Repository, @Assisted private val savedState: SavedStateHandle ) : ViewModel() { } @AndroidEntryPoint class MainActivity : AppCompatActivity(R.layout.activity_main) { private val viewModel by viewModels<ActivityViewModel>() override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) } }

    ViewModle创建需要借助ViewModel.Factory、而非构造函数直接创建。上面整个注入过程并没有自定义任何factory,仅仅@ViewModelInject一个注解就搞定了,这是怎么实现的呢?

    viewModels{…}

    viewModels{...}是一个继承Lazy<>的ktx扩展,可以通过by关键字方便地创建ViewModel,以前我在airbnb的Mvrx中见到过类似用法,看来是被Jetpack借鉴了。

    官方自然不只是简单的借(chao)鉴(xi),里面自有其玄机

    @MainThread inline fun <reified VM : ViewModel> ComponentActivity.viewModels( noinline factoryProducer: (() -> Factory)? = null ): Lazy<VM> { val factoryPromise = factoryProducer ?: { // ComponentActivity#getDefaultViewModelProviderFactory() defaultViewModelProviderFactory } return ViewModelLazy(VM::class, { viewModelStore }, factoryPromise) }

    通过源码知道,ViewModel.Factory默认使用了defaultViewModelProviderFactory。所以只要重写这个defaultViewModelProviderFactory,就可以hook自定义实现进去

    重写getDefaultViewModelProviderFactory

    通过前一篇文章我们知道,Hilt会在编译期修改被注入对象的父类,

    @AndroidEntryPoint class MainActivity : AppCompatActivity(R.layout.activity_main) {

    MainActivity原本继承自AppCompatActivity,但经Hilt处理后父类变为了Hilt_MainActivity

    @Generated("dagger.hilt.android.processor.internal.androidentrypoint.ActivityGenerator") public abstract class Hilt_MainActivity extends AppCompatActivity implements GeneratedComponentManager<Object> { private volatile ActivityComponentManager componentManager; ... @Override public ViewModelProvider.Factory getDefaultViewModelProviderFactory() { ViewModelProvider.Factory factory = DefaultViewModelFactories.getActivityFactory(this); if (factory != null) { return factory; } return super.getDefaultViewModelProviderFactory(); } }

    HIlt_MainActivity中通过DefaultViewModelFactories.getActivityFactory(this)返回ViewModel.Factory。

    public final class DefaultViewModelFactories { @Nullable public static ViewModelProvider.Factory getActivityFactory(ComponentActivity activity) { return getFactoryFromSet( EntryPoints.get(activity, ActivityEntryPoint.class).getActivityViewModelFactory()); } //... }

    一句话概括:Hilt通过Dagger生成的Component获取ViewModelFactory

    EntryPoints.get(activity, ActivityEntryPoint.class)创建并获取ActivityComponent,getActivityViewModelFactory()通过Component内的Module获取Factory

    创建ActivityComponent

    public final class EntryPoints { @Nonnull public static <T> T get(Object component, Class<T> entryPoint) { if (component instanceof GeneratedComponent) { return entryPoint.cast(component); } else if (component instanceof GeneratedComponentManager) { return entryPoint.cast(((GeneratedComponentManager<?>) component).generatedComponent()); } } } @Generated("dagger.hilt.android.processor.internal.androidentrypoint.ActivityGenerator") public abstract class Hilt_MainActivity extends AppCompatActivity implements GeneratedComponentManager<Object> { private volatile ActivityComponentManager componentManager; ... @Override public final Object generatedComponent() { return componentManager().generatedComponent(); } protected ActivityComponentManager createComponentManager() { return new ActivityComponentManager(this); } protected final ActivityComponentManager componentManager() { if (componentManager == null) { synchronized (componentManagerLock) { if (componentManager == null) { componentManager = createComponentManager(); } } } return componentManager; }

    如上,Hilt_MainActivity继承自GeneratedComponentManager,ActivityComponentManager获取generatedComponent

    public class ActivityComponentManager implements GeneratedComponentManager<Object> { //... protected Object createComponent() { return ((ActivityComponentBuilderEntryPoint) activityRetainedComponentManager.generatedComponent()) .activityComponentBuilder() .activity(activity) .build(); } }

    最终通过Hilt_MainActivity的ActivityComponentManager获创建ActivityComponent,ActivityComponentManager内部通过activityRetainedComponentManager(借助ViewModel)保证了ActivityComponent的复用。

    获取ViewModelFactory

    获取ActivityComponent后,通过内部的Model获取ViewModelFactory。 Hilt中提供了ActivityModule,可以InstallIn到ActivityComponent。ActivityModule中定义了Factory的Provider

    @RestrictTo(RestrictTo.Scope.LIBRARY_GROUP_PREFIX) public final class ViewModelFactoryModules { /** * Hilt Modules for providing the activity level ViewModelFactory */ @Module @InstallIn(ActivityComponent.class) public abstract static class ActivityModule { @NonNull @Multibinds abstract Map<String, ViewModelAssistedFactory<? extends ViewModel>> viewModelFactoriesMap(); @Provides @IntoSet @NonNull @DefaultActivityViewModelFactory static ViewModelProvider.Factory provideFactory( @NonNull Activity activity, @NonNull Application application, @NonNull Map<String, Provider<ViewModelAssistedFactory<? extends ViewModel>>> viewModelFactories) { // Hilt guarantees concrete activity is a subclass of ComponentActivity. SavedStateRegistryOwner owner = (ComponentActivity) activity; Bundle defaultArgs = activity.getIntent() != null ? activity.getIntent().getExtras() : null; SavedStateViewModelFactory delegate = new SavedStateViewModelFactory(application, owner, defaultArgs); return new HiltViewModelFactory(owner, defaultArgs, delegate, viewModelFactories)

    通过SavedStateViewModelFactory的defaultArgs,将ViewModel所需的参数进行注入

    总结

    Hilt在编译期改写Activity或者Fragment的父类,获取了自定义的ViewModel.Factory的方法,从而hook了ViewModle的创建过程,对ViewModel进行注入。整个实现过程借助@InstallIn以及@AndroidEntryPoint的注解,本身就是一个Hilt的最佳实践,值得学习和借鉴

    参考上一篇 Dagger Hilt - Android官方推荐的依赖注入框架

    Processed: 0.015, SQL: 9