简体   繁体   中英

Provide Activity instance with Hilt

How can I translate something like this:

@Module
abstract class BaseActivityModule<A : AppCompatActivity> {
    @Binds
    abstract fun provideActivity(activity: A): AppCompatActivity

    companion object {
        @Provides
        @ActivityContext
        fun provideContext(activity: AppCompatActivity): Context = activity
    }
}

@Module
abstract class SomeActivityModule : BaseActivityModule<SomeActivity>()

So it can be used latter like:

@ActivityScope
class UtilsClass @Inject constructor(
    private val activity: AppCompatActivity,
    ...
){...}

I've migrated a playground project from dagger to hilt and it went super smooth, but I've stumbled across this use-case. I've changed the code so I wont be needing that instance any more but the curiosity remains.

Is it even possible now that we don't need this kind of setup:

@ActivityScope
@ContributesAndroidInjector(modules = [SomeActivityModule::class])
abstract fun someActivity(): SomeActivity

Yes, you can cast @ActivityContext to that of your activity, read on for more clarification.
@ActivityContext can be used to scope the bindings that require activity context. But similar to dagger scoping scheme, you can only scope in classes that are @ActivityScoped , ie if you try @ActivityContext in a class and scope it with any other scope wider than @ActivityScoped , you will face compile time error

@dagger.hilt.android.qualifiers.ActivityContext android.content.Context cannot be provided without an @Provides-annotated method

Moreover, new bindings objects will instantiated every time any new activity is created.
refer https://developer.android.com/training/dependency-injection/hilt-android#component-scopes

i didn't try this code yet, if its not working please CMiMW,
according to documentation here , you can use predefined qualifers for Application Context and activity context.

your code may look like this

@ActivityScoped
class UtilsClass @Inject constructor(
@ActivityContext private val activity: Context,
... 
){
 ...
 val myActivity = if(context is MyActivity) context as MyActivity else throw ......  // check if its provided context was desired activity
 ...

}

Yes, We don't need this kind of setup. We just have to provide @AndroidEntryPoint on our activities and Hilt will handle the dependency injections on its own. Also with Hilt, There is no need to write Factory and InjectorComponents.

Just cast/get activity from context. But you can also specify class according to the docs

tailrec fun Context?.activity(): Activity? = this as? Activity
    ?: (this as? ContextWrapper)?.baseContext?.activity()

class MyClass @Inject constructor(@ActivityContext context: Context) {

    init {
        val activity = context.activity() as Activity
    }

    //...
}

I was facing situation while working on project, thought I would share if this helps someone.

The activity Context binding is available using @ActivityContext

class PaymentService @Inject constructor(
    @ActivityContext context: Context
) { ... }

and Activity binding is available without qualifiers.

class PaymentService @Inject constructor(
    activity: FragmentActivity
) { ... }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM