简体   繁体   中英

Is there any way to access contributing modules instances from application component dagger2

I have created a small sample to test dagger2 implementation. I have created a utility class in which an Activity's instance is to be injected. Is there any way to get this utility class instance in Activity itself using dagger2

CoreApplication.kt

class CoreApplication : Application(), HasActivityInjector {
    @Inject
    internal lateinit var dispatchingActivityInjector: DispatchingAndroidInjector<Activity>

    override fun activityInjector(): AndroidInjector<Activity> {
        return dispatchingActivityInjector    }

    val component: AppComponent by lazy {
        DaggerAppComponent
                .builder()
                .application(this)
                .sharedPreference(AppConstants.FILE_NAME_SHARED_PREFERENCES)
                .build()
    }
    override fun onCreate() {
        super.onCreate()
        component.inject(this)
        component.sharedPref().saveString("hello", "world")
        Log.i("test", component.sharedPref().getString("hello"))

    }
}

AppComponent.kt

@Singleton
@Component(modules = arrayOf(AndroidInjectionModule::class, ActivityBuilder::class, AppModuleBinds::class, AppModuleProvides::class))
interface AppComponent {

    @Component.Builder
    interface Builder {

        @BindsInstance
        fun application(application: Application): Builder

        @BindsInstance
        fun sharedPreference(@Named(Constant.Name.SHARED_PREFERENCES) sharedPreferenceName: String): Builder

        fun build(): AppComponent

    }

    fun inject(application: CoreApplication)

    fun sharedPref() : SharedPreferenceUtils

}

ActivityBuilder.kt

@Module
abstract class ActivityBuilder{
    @PerActivity
    @ContributesAndroidInjector(modules = arrayOf(HomeModuleBinds::class))
    abstract fun bindMainActivity(): MainActivity

    @PerActivity
    abstract fun dialogUtils() : DialogUtils

}

HomeModuleBinds.kt

@Module
    abstract class HomeModuleBinds {
        @Binds
        @PerActivity
        abstract fun activityContext(activity: Activity): Context

        @Binds
        @PerActivity
        abstract fun activity(activity: Activity): Activity
    }

DialogUtils.kt

@PerActivity
class DialogUtils @Inject constructor(var activity: Activity) {
    fun showDialog(error: String) = {
        val alertDialogBuilder = AlertDialog.Builder(activity)
        alertDialogBuilder.setTitle(error).create().show()

    }
}

Is there any way I can use DialogUtils instance in MainActivity Using dagger2 dependency cycle?

class MainActivity : AppCompatActivity() {

    @Inject
    @Singleton
    lateinit var sharedPref : SharedPreferenceUtils

    @Inject
    @PerActivity
    lateinit var dialogUtils: DialogUtils

    override fun onCreate(savedInstanceState: Bundle?) {
        AndroidInjection.inject(this)
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)
        sharedPref.saveString("test", "val")
        Log.i("test", sharedPref.getString("test"))



        //dialogUtils.showDialog("hello")
    }
}

For example using inject for DaggerUtils on MainActivity is causing cyclic dependency error

Don't inject the Activity into the Utility class.

Then in your Activity call:

dialogUtils.showDialog( "hello", MyACtivity.this)

In dialogUtils:

fun showDialog(error: String, context: Context) = {
        val alertDialogBuilder = AlertDialog.Builder(context)
        alertDialogBuilder.setTitle(error).create().show()

    }

Is there any way I can use DialogUtils instance in MainActivity Using dagger2 dependency cycle?

Yes, there is. To do that, you'll have to do the following changes in your Dagger setup:

1. ActivityBuilder.kt

Delete the following lines:

@PerActivity
abstract fun dialogUtils() : DialogUtils

Why? You don't need it. You already have DialogUtils injectable, since you annotated the class itself with @PerActivity and the constructor with @Inject . Dagger will automagically do the required binding wherever DialogUtils is needed. You write provide/bind methods only when you're injecting an abstract type. In this case, DialogUtils is not implementing an abstract type that you inject in the Activity . You inject the actual implementation directly so you don't need to setup any bindings.

2. HomeModuleBinds.kt

Change the Activity binding to more the specific Activity you want to bind to Activity , in this case it's MainActivity . Dagger will then understand that it needs to bind it to Activity when DialogUtils asks for it. You will need to do that for each Activity you want to use DialogUtils in the Activity 's own module - the one you pass as an argument to the @ContributeAndroidInjector(modules = [...]) , in this case it is HomeModuleBinds.kt .

@Binds
@PerActivity
abstract fun bindMainActivity(mainActivity: MainActivity): Activity

3. DialogUtils

The way you have method showDialog(String) defined currently, it returns a lambda! Remove the equals = .

fun showDialog(error: String) {
    val alertDialogBuilder = AlertDialog.Builder(activity)
    alertDialogBuilder.setTitle(error).create().show()

}

4. MainActivity.kt

Remove the scope annotations from the injected fields.

@Inject
@Singleton // <-- Remove this
lateinit var sharedPref : SharedPreferenceUtils

@Inject
@PerActivity // <-- Remove this
lateinit var dialogUtils: DialogUtils

You can only annotate Components, Provide/Bind methods and classes with scope annotations!

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