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

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官方推荐的依赖注入框架​