前言
本章是基于Dagger2.38.1源码去理解hilt源码,在理解hilt源码之前一定要对dagger的用法有一定深入的了解。
hilt我个人的理解是专门为Android设计的一款简化的Dagger。
所以我们虽然使用了hilt,它最终还是会为我们转换成一个Dagger,然后在由Dagger源码处理。
下面我们来看看具体内容。
hilt demo
以github上的一个Demo作为讲解案例。
-
在MyApplication、MainActivity、UserListFragment和UserDetailsFragment中加入入口注解;
@HiltAndroidApp class MyApplication : Application() {...} @AndroidEntryPoint class MainActivity : AppCompatActivity(R.layout.activity_main) @AndroidEntryPoint class UserListFragment : Fragment() {...} @AndroidEntryPoint class UserDetailsFragment : Fragment() {...}
-
在UserListViewModel和UserDetailsViewModule上加入@HiltViewModel注解;
@HiltViewModel class UserListViewModel @Inject constructor( private val userListRepository: UserListRepository ) : ViewModel() {...} @HiltViewModel class UserDetailsViewModel @Inject constructor( private val userDetailsRepository: UserDetailsRepository ) : ViewModel() {...}
-
完成以上两个步骤就可以使用注解了;
-
(1) 例如上面的代码在UserListViewModel构造函数中使用userListRepository,依赖的是UserListRepository使用@Inject构造函数;
-
(2)UserListRepository使用@Inject构造函数的UserListService参数依赖于NetworkModule的provideApiService方法;等等,注解的使用和Dagger雷同。
-
(3)贴出DatabaseModule和NetworkModel代码:
@InstallIn(SingletonComponent::class) @Module object DatabaseModule { @Provides @Singleton fun provideAppDatabase(@ApplicationContext appContext: Context): UsersDatabase { return Room.databaseBuilder( appContext, UsersDatabase::class.java, "Users" ).fallbackToDestructiveMigration().build() } @Provides fun provideChannelDao(usersDatabase: UsersDatabase): UsersDao { return usersDatabase.usersDao } } @Module @InstallIn(SingletonComponent::class) object NetworkModule { @Singleton @Provides fun provideOkHttpClient() = if (BuildConfig.DEBUG) { val loggingInterceptor = HttpLoggingInterceptor() loggingInterceptor.setLevel(HttpLoggingInterceptor.Level.BODY) OkHttpClient.Builder() .addInterceptor(loggingInterceptor) .build() } else { OkHttpClient .Builder() .build() } @Singleton @Provides fun provideRetrofit(okHttpClient: OkHttpClient): Retrofit = Retrofit.Builder() .addConverterFactory(MoshiConverterFactory.create()) .baseUrl("https://api.github.com/") .client(okHttpClient) .build() @Provides @Singleton fun provideApiService(retrofit: Retrofit): UserListService = retrofit.create(UserListService::class.java) @Provides @Singleton fun provideUserDetailsService(retrofit: Retrofit): UserDetailsService = retrofit.create(UserDetailsService::class.java) }
hilt demo生成Dagger demo
生成注入方法
-
@HiltAndroidApp修饰的MyApplication生成注入方法:
@OriginatingElement( topLevelClass = MyApplication.class ) @GeneratedEntryPoint @InstallIn(SingletonComponent.class) public interface MyApplication_GeneratedInjector { void injectApplication(MyApplication myApplication); }
-
@AndroidEntryPoint修饰的MainActivity生成注入方法:
@OriginatingElement( topLevelClass = MainActivity.class ) @GeneratedEntryPoint @InstallIn(ActivityComponent.class) public interface MainActivity_GeneratedInjector { void injectMainActivity(MainActivity mainActivity); }
-
@AndroidEntryPoint修饰的UserListFragment生成注入方法:
@OriginatingElement( topLevelClass = UserListFragment.class ) @GeneratedEntryPoint @InstallIn(FragmentComponent.class) public interface UserListFragment_GeneratedInjector { void injectUserListFragment(UserListFragment userListFragment); }
-
@AndroidEntryPoint修饰的UserDetailsFragment生成注入方法:
@OriginatingElement( topLevelClass = UserDetailsFragment.class ) @GeneratedEntryPoint @InstallIn(FragmentComponent.class) public interface UserDetailsFragment_GeneratedInjector { void injectUserDetailsFragment(UserDetailsFragment userDetailsFragment); }
生成Component容器
-
SingleTonComponent节点:
@Component(modules = [ DatabaseModule.class, NetworkModule.class, ApplicationContextModule.class ]) @Singleton public static abstract class SingletonComponent implements Application_GeneratedInjector { //Application_GeneratedInjector类中的方法 //void injectApplication(Application application); ActivityRetainedComponent.Builder retainedComponentBuilder(); @Component.Builder public static interface Builder{ Builder applicationContextModule(ApplicationContextModule context); SingletonComponent build(); } }
-
ApplicationContextModule是hilt源码提供
@Module @InstallIn({SingletonComponent.class}) public final class ApplicationContextModule { private final Context applicationContext; public ApplicationContextModule(Context applicationContext) { this.applicationContext = applicationContext; } @Provides @ApplicationContext Context provideContext() { return this.applicationContext; } @Provides Application provideApplication() { return Contexts.getApplication(this.applicationContext); } }
-
ActivityRetainedComponent类:
@subComponent @ActivityRetainedScoped public static abstract class ActivityRetainedComponent{ ActivityComponent.Builder activityComponentBuilder(); @SubComponent.Builder static interface Builder{ ActivityRetainedComponent build(); } }
- 实际情况并不是简单的这样子处理,这里为了我们能够简单的理解去掉了生命周期等类;
-
ActivityComponent类(同样的代码掐头去尾):
@subComponent @ActivityScoped public static abstract class ActivityComponent implements MainActivity_GeneratedInjector { //MainActivity_GeneratedInjector中的方法 //void injectMainActivity(MainActivity mainActivity); ViewModelComponent.Builder getViewModelComponentBuilder(); FragmentComponent.Builder fragmentComponentBuilder(); @SubComponent.Builder static interface Builder{ Builder activity( @BindsInstance Activity activity); ActivityComponent build(); } }
-
FragmentComponent类:
@subComponent @FragmentScoped public static abstract class FragmentComponent implements UserDetailsFragment_GeneratedInjector, UserListFragment_GeneratedInjector { //UserDetailsFragment_GeneratedInjector //void injectUserDetailsFragment(UserDetailsFragment userDetailsFragment); //UserListFragment_GeneratedInjector //void injectUserListFragment(UserListFragment userListFragment); @SubComponent.Builder static interface Builder{ Builder fragment(@BindsInstance Fragment fragment); FragmentComponent build(); } }
-
ViewModelComponent暂时不贴,否则容易乱。
demo实现注入
-
@HiltAndroidApp修饰的MyApplication生成注入类;
//A generated base class to be extended by the @HiltAndroidApp annotated class. If using the Gradle plugin, this is swapped as the base class via bytecode transformation. @Generated("ApplicationGenerator") abstract class Hilt_MyApplication extends Application implements GeneratedComponentManagerHolder { private final ApplicationComponentManager componentManager = new ApplicationComponentManager( new ComponentSupplier() { @Override public Object get() { //_com_aregyan_github_MyApplication_HiltComponents内部类SingletonComponent生成的,该类后面生成。 return Dagger_com_aregyan_github_MyApplication_HiltComponents_SingletonComponent.builder() .applicationContextModule(new ApplicationContextModule(Hilt_Application.this)) .build(); } } ); @Override public final ApplicationComponentManager componentManager() { return componentManager; } @Override public final Object generatedComponent() { return this.componentManager().generatedComponent(); } @CallSuper @Override public void onCreate() { // This is a known unsafe cast, but is safe in the only correct use case: // $APP extends Hilt_$APP ((MyApplication_GeneratedInjector)generatedComponent()).injectApplication((MyApplication) this); super.onCreate(); } }
-
@AndroidEntryPoint修饰的MainActivity实现注入;
/** * A generated base class to be extended by the @dagger.hilt.android.AndroidEntryPoint annotated class. If using the Gradle plugin, this is swapped as the base class via bytecode transformation. */ public abstract class Hilt_MainActivity extends AppCompatActivity implements GeneratedComponentManagerHolder { private volatile ActivityComponentManager componentManager; private final Object componentManagerLock = new Object(); private boolean injected = false; Hilt_MainActivity() { super(); _initHiltInternal(); } Hilt_MainActivity(int contentLayoutId) { super(contentLayoutId); _initHiltInternal(); } private void _initHiltInternal() { addOnContextAvailableListener(new OnContextAvailableListener() { @Override public void onContextAvailable(Context context) { inject(); } }); } @Override public final Object generatedComponent() { return this.componentManager().generatedComponent(); } protected ActivityComponentManager createComponentManager() { return new ActivityComponentManager(this); } @Override public final ActivityComponentManager componentManager() { if (componentManager == null) { synchronized (componentManagerLock) { if (componentManager == null) { componentManager = createComponentManager(); } } } return componentManager; } protected void inject() { if (!injected) { injected = true; ((MainActivity_GeneratedInjector) this.generatedComponent()).injectMainActivity(UnsafeCasts.<MainActivity>unsafeCast(this)); } } @Override public ViewModelProvider.Factory getDefaultViewModelProviderFactory() { return DefaultViewModelFactories.getActivityFactory(this, super.getDefaultViewModelProviderFactory()); } }
-
贴出ActivityComponentManager代码如下:
public class ActivityComponentManager implements GeneratedComponentManager<Object> { /** * Entrypoint for {@link ActivityComponentBuilder}. */ @EntryPoint @InstallIn(ActivityRetainedComponent.class) public interface ActivityComponentBuilderEntryPoint { ActivityComponentBuilder activityComponentBuilder(); } private volatile Object component; private final Object componentLock = new Object(); protected final Activity activity; private final GeneratedComponentManager<ActivityRetainedComponent> activityRetainedComponentManager; public ActivityComponentManager(Activity activity) { this.activity = activity; this.activityRetainedComponentManager = new ActivityRetainedComponentManager((ComponentActivity) activity); } @Override public Object generatedComponent() { if (component == null) { synchronized (componentLock) { if (component == null) { component = createComponent(); } } } return component; } protected Object createComponent() { if (!(activity.getApplication() instanceof GeneratedComponentManager)) { if (Application.class.equals(activity.getApplication().getClass())) { throw new IllegalStateException( "Hilt Activity must be attached to an @HiltAndroidApp Application. " + "Did you forget to specify your Application's class name in your manifest's " + "<application />'s android:name attribute?"); } throw new IllegalStateException( "Hilt Activity must be attached to an @AndroidEntryPoint Application. Found: " + activity.getApplication().getClass()); } return EntryPoints.get( activityRetainedComponentManager, ActivityComponentBuilderEntryPoint.class) .activityComponentBuilder() .activity(activity) .build(); } }
-
@AndroidEntryPoint修饰的UserListFragment实现注入;
/** * A generated base class to be extended by the @dagger.hilt.android.AndroidEntryPoint annotated class. If using the Gradle plugin, this is swapped as the base class via bytecode transformation. */ public abstract class Hilt_UserListFragment extends Fragment implements GeneratedComponentManagerHolder { private ContextWrapper componentContext; private boolean disableGetContextFix; private volatile FragmentComponentManager componentManager; private final Object componentManagerLock = new Object(); private boolean injected = false; Hilt_UserListFragment() { super(); } Hilt_UserListFragment(int contentLayoutId) { super(contentLayoutId); } @Override @CallSuper public void onAttach(Context context) { super.onAttach(context); initializeComponentContext(); inject(); } @Override @SuppressWarnings("deprecation") @CallSuper @MainThread public void onAttach(Activity activity) { super.onAttach(activity); Preconditions.checkState(componentContext == null || FragmentComponentManager.findActivity(componentContext) == activity, "onAttach called multiple times with different Context! Hilt Fragments should not be retained."); initializeComponentContext(); inject(); } private void initializeComponentContext() { if (componentContext == null) { // Note: The LayoutInflater provided by this componentContext may be different from super Fragment's because we getting it from base context instead of cloning from the super Fragment's LayoutInflater. componentContext = FragmentComponentManager.createContextWrapper(super.getContext(), this); disableGetContextFix = FragmentGetContextFix.isFragmentGetContextFixDisabled(super.getContext()); } } @Override public Context getContext() { if (super.getContext() == null && !disableGetContextFix) { return null; } initializeComponentContext(); return componentContext; } @Override public LayoutInflater onGetLayoutInflater(Bundle savedInstanceState) { LayoutInflater inflater = super.onGetLayoutInflater(savedInstanceState); return LayoutInflater.from(FragmentComponentManager.createContextWrapper(inflater, this)); } @Override public final Object generatedComponent() { return this.componentManager().generatedComponent(); } protected FragmentComponentManager createComponentManager() { return new FragmentComponentManager(this); } @Override public final FragmentComponentManager componentManager() { if (componentManager == null) { synchronized (componentManagerLock) { if (componentManager == null) { componentManager = createComponentManager(); } } } return componentManager; } protected void inject() { if (!injected) { injected = true; ((UserListFragment_GeneratedInjector) this.generatedComponent()).injectUserListFragment(UnsafeCasts.<UserListFragment>unsafeCast(this)); } } @Override public ViewModelProvider.Factory getDefaultViewModelProviderFactory() { return DefaultViewModelFactories.getFragmentFactory(this, super.getDefaultViewModelProviderFactory()); } }
-
@AndroidEntryPoint修饰的UserDetailsFragment实现注入;
/** * A generated base class to be extended by the @dagger.hilt.android.AndroidEntryPoint annotated class. If using the Gradle plugin, this is swapped as the base class via bytecode transformation. */ public abstract class Hilt_UserDetailsFragment extends Fragment implements GeneratedComponentManagerHolder { private ContextWrapper componentContext; private boolean disableGetContextFix; private volatile FragmentComponentManager componentManager; private final Object componentManagerLock = new Object(); private boolean injected = false; Hilt_UserDetailsFragment() { super(); } Hilt_UserDetailsFragment(int contentLayoutId) { super(contentLayoutId); } @Override @CallSuper public void onAttach(Context context) { super.onAttach(context); initializeComponentContext(); inject(); } @Override @SuppressWarnings("deprecation") @CallSuper @MainThread public void onAttach(Activity activity) { super.onAttach(activity); Preconditions.checkState(componentContext == null || FragmentComponentManager.findActivity(componentContext) == activity, "onAttach called multiple times with different Context! Hilt Fragments should not be retained."); initializeComponentContext(); inject(); } private void initializeComponentContext() { if (componentContext == null) { // Note: The LayoutInflater provided by this componentContext may be different from super Fragment's because we getting it from base context instead of cloning from the super Fragment's LayoutInflater. componentContext = FragmentComponentManager.createContextWrapper(super.getContext(), this); disableGetContextFix = FragmentGetContextFix.isFragmentGetContextFixDisabled(super.getContext()); } } @Override public Context getContext() { if (super.getContext() == null && !disableGetContextFix) { return null; } initializeComponentContext(); return componentContext; } @Override public LayoutInflater onGetLayoutInflater(Bundle savedInstanceState) { LayoutInflater inflater = super.onGetLayoutInflater(savedInstanceState); return LayoutInflater.from(FragmentComponentManager.createContextWrapper(inflater, this)); } @Override public final Object generatedComponent() { return this.componentManager().generatedComponent(); } protected FragmentComponentManager createComponentManager() { return new FragmentComponentManager(this); } @Override public final FragmentComponentManager componentManager() { if (componentManager == null) { synchronized (componentManagerLock) { if (componentManager == null) { componentManager = createComponentManager(); } } } return componentManager; } protected void inject() { if (!injected) { injected = true; ((UserDetailsFragment_GeneratedInjector) this.generatedComponent()).injectUserDetailsFragment(UnsafeCasts.<UserDetailsFragment>unsafeCast(this)); } } @Override public ViewModelProvider.Factory getDefaultViewModelProviderFactory() { return DefaultViewModelFactories.getFragmentFactory(this, super.getDefaultViewModelProviderFactory()); } }
viewmodel
以上理解消化完毕我们再来看viewmodel。
这里注意,我们实现的ViewModel要么使用@Inject修饰构造函数,要么通过@Module修饰的接口或抽象类提供依赖。
ViewModel生成_HiltModules类
-
UserListViewModel生成UserListViewModel_HiltModules:
@OriginatingElement( topLevelClass = UserListViewModel.class ) public final class UserListViewModel_HiltModules { private UserListViewModel_HiltModules() { } @Module @InstallIn(ViewModelComponent.class) public abstract static class BindsModule { private BindsModule() { } @Binds @IntoMap @StringKey("com.aregyan.github.views.userList.UserListViewModel") @HiltViewModelMap public abstract ViewModel binds(UserListViewModel vm); } @Module @InstallIn(ActivityRetainedComponent.class) public static final class KeyModule { private KeyModule() { } @Provides @IntoSet @HiltViewModelMap.KeySet public static String provide() { return "com.aregyan.github.views.userList.UserListViewModel"; } } }
-
UserDetailsViewModel生成UserDetailsViewModel_HiltModules:
@OriginatingElement( topLevelClass = UserDetailsViewModel.class ) public final class UserDetailsViewModel_HiltModules { private UserDetailsViewModel_HiltModules() { } @Module @InstallIn(ViewModelComponent.class) public abstract static class BindsModule { private BindsModule() { } @Binds @IntoMap @StringKey("com.aregyan.github.views.userDetails.UserDetailsViewModel") @HiltViewModelMap public abstract ViewModel binds(UserDetailsViewModel vm); } @Module @InstallIn(ActivityRetainedComponent.class) public static final class KeyModule { private KeyModule() { } @Provides @IntoSet @HiltViewModelMap.KeySet public static String provide() { return "com.aregyan.github.views.userDetails.UserDetailsViewModel"; } } }
ViewModelComponent类
@subComponent(modules = [
UserDetailsViewModel_HiltModules.BindsModule.class,
UserListViewModel_HiltModules.BindsModule.class,
HiltViewModelFactory.ViewModelModule.class
])
@ViewModelScoped
public static abstract class ViewModelComponent
implements
{
//HiltViewModelFactory.ViewModelFactoriesEntryPoint
@HiltViewModelMap
Map<String, Provider<ViewModel>> getHiltViewModelMap()
@SubComponent.Builder
static interface Builder implements ViewModelComponentBuilder{
ViewModelComponentBuilder savedStateHandle(@BindsInstance SavedStateHandle handle);
ViewModelComponent build();
}
}
当前getHiltViewModelMap收集ViewModel类,K:viemodel名称,V:ViewModel子类;
(1)当前getHiltViewModelMap方法依赖于UserDetailsViewModel_HiltModules.BindsModule和UserListViewModel_HiltModules.BindsModule的binds方法,binds方法提供了ViewModel子类的实例化;
ViewModelProvider.Factory
在Hilt_MainActivity中提供了ViewModelProvider.Factory,用于提供ViewModel:
@Override
public ViewModelProvider.Factory getDefaultViewModelProviderFactory() {
return DefaultViewModelFactories.getActivityFactory(this, super.getDefaultViewModelProviderFactory());
}
最终会调用:
ViewModelComponent component = viewModelComponentBuilder.savedStateHandle(handle).build();
总结
为了方便理解,hilt生成代码的部分改动量非常大,实际要比这个复杂。如果有兴趣可以自己去学习hilt系列源码。
以上代码可以看出,hilt给android使用注解提供了大大的便利,很多都不需要我们手动去实现,非常的方便。
后面会针对hilt注解进行详细讲解:hilt转换dagger的中间过程,以及各个注解使用规则。