问题
I would like to try Hilt DI in the android library.
It is a dependency on another project, with its own submodule. The very first problem I've encountered is the requirement of marking Application
with @HiltAndroidApp
. Now I do not have anything that extends Application
in my library ofc but would like to utilize Hilt and its predefined components.
Is it possible or should I go with Dagger only in such a case? I've found a solution for Dagger, where library dependency injection is made totally independently (the client is unaware of the library's DI): Dagger solution, would love to hear any opinion on that, maybe someone already put a great effort into that issue and can share his insights.
回答1:
If you're trying to include Hilt in an android library, then you should expect the android app (client of your library) to mark its Application
with @HiltAndroidApp
.
You should include your whole setup (entry points, modules, dependencies, ... whatever you want to have in your library) in the library module, and make the requirement for the client of the library to use the @HiltAndroidApp
to use your library correctly.
回答2:
You don't need to include @HiltAndroidApp
in library module to inject the dependencies in library modules to app module or any dynamic feature modules.
This sample has only core library module, app, and dynamic feature modules. Dynamic feature module implementation is optional.
Result of injecting from core library module to App's Activity and Fragment is as
Project dependency Structure
feature_hilt_camera feature_hilt_photos (Dynamic Feature Modules)
| | |
| ----App----
| |
core(android-library)
In core library module
have a dagger module as
@InstallIn(ApplicationComponent::class)
@Module
class CoreModule {
@Singleton
@Provides
fun provideCoreDependency(application: Application) = CoreDependency(application)
@Provides
fun provideCoreActivityDependency(context: Application) = CoreActivityDependency(context)
@Provides
fun provideCoreCameraDependency(): CoreCameraDependency = CoreCameraDependency()
@Provides
fun provideCorePhotoDependency(): CorePhotoDependency = CorePhotoDependency()
@Provides
fun provideAnotherDependency() = AnotherDependency()
}
And inject to Activity as
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
/**
* Injected from [CoreModule] with @Singleton scope
*/
@Inject
lateinit var coreDependency: CoreDependency
/**
* Injected from [CoreModule] with no scope
*/
@Inject
lateinit var coreActivityDependency: CoreActivityDependency
/**
* Injected from [MainActivityModule] with no scope
*/
@Inject
lateinit var toastMaker: ToastMaker
/**
*
* Injected from [MainActivityModule] with @ActivityScoped
* * To inject this there should be @Binds that gets Context from an Application
*/
@Inject
lateinit var mainActivityObject: MainActivityObject
/**
* Injected via constructor injection with no scope
*/
@Inject
lateinit var sensorController: SensorController
/**
* Injected via constructor injection with @Singleton scope
*
* ### Unlike Tutorial 9-2 This can be injected because MainActivity's component does not
* depend on any component with another scope
*/
@Inject
lateinit var singletonObject: SingletonObject
@Inject
lateinit var anotherDependency: AnotherDependency
@SuppressLint("SetTextI18n")
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
findViewById<TextView>(R.id.tvInfo).text =
"CoreModule @Singleton coreDependency: ${coreDependency.hashCode()}\n" +
"CoreModule no scope coreActivityDependency: ${coreActivityDependency.hashCode()}\n" +
"CoreModule no scope anotherDependency: ${anotherDependency.hashCode()}\n" +
"MainActivityModule @ActivityScoped mainActivityObject: ${mainActivityObject.hashCode()}\n" +
"MainActivityModule no scope toastMaker: ${toastMaker.hashCode()}\n" +
"Constructor no scope sensorController: ${sensorController.hashCode()}\n"
"Constructor @Singleton singletonObject: ${singletonObject.hashCode()}"
}
}
and it's same for HomeFragment
which is in app module
@AndroidEntryPoint
class HomeFragment : Fragment() {
/**
* Injected from [CoreModule] with @Singleton scope
*/
@Inject
lateinit var coreDependency: CoreDependency
/**
* Injected from [CoreModule] with no scope
*/
@Inject
lateinit var coreActivityDependency: CoreActivityDependency
@Inject
lateinit var homeFragmentObject: HomeFragmentObject
/**
* This dependency cannot be injected since this fragment's component does not depend on CoreComponent
* unlike Tutorial 9-2 counterpart
*/
@Inject
lateinit var mainActivityObject: MainActivityObject
@Inject
lateinit var fragmentObject: FragmentObject
}
If you also wish to inject to dynamic feature modules you need a provision module in your library module as
/**
* This component is required for adding component to DFM dependencies
*/
@EntryPoint
@InstallIn(ApplicationComponent::class)
interface CoreModuleDependencies {
/*
🔥 Provision methods to provide dependencies to components that depend on this component
*/
fun coreDependency(): CoreDependency
fun coreActivityDependency(): CoreActivityDependency
fun coreCameraDependency(): CoreCameraDependency
fun corePhotoDependency(): CorePhotoDependency
}
and dynamic feature module you will use this interface as dependent component
In camera dynamic feature module have a component like this
@Component(
dependencies = [CoreModuleDependencies::class],
modules = [CameraModule::class]
)
interface CameraComponent {
fun inject(cameraFragment1: CameraFragment1)
fun inject(cameraFragment2: CameraFragment2)
fun inject(cameraActivity: CameraActivity)
@Component.Factory
interface Factory {
fun create(coreComponentDependencies: CoreModuleDependencies,
@BindsInstance application: Application): CameraComponent
}
}
and inject it to your dynamic feature fragment with
private fun initCoreDependentInjection() {
val coreModuleDependencies = EntryPointAccessors.fromApplication(
requireActivity().applicationContext,
CoreModuleDependencies::class.java
)
DaggerCameraComponent.factory().create(
coreModuleDependencies,
requireActivity().application
)
.inject(this)
}
Full sample that in image is here, and you check out implementation for both libraries and dynamic feature modules in this sample project.
来源:https://stackoverflow.com/questions/63246625/hilt-using-in-android-library