如何在运行时从活动或片段将参数传递给dagger模块

问题描述 投票:5回答:4

我的软件规格如下:

Android Studio 3.4
dagger-android 2.16

我有以下类传递将执行并返回响应的MapboxGeocoder

class GeocodingImp(private val mapboxGeocoder: MapboxGeocoder) : Geocoding {

    override fun getCoordinates(address: String, criteria: String): AddressCoordinate {
        val response = mapboxGeocoder.execute()

        return if(response.isSuccess && !response.body().features.isEmpty()) {
            AddressCoordinate(
                response.body().features[0].latitude,
                response.body().features[0].longitude)
        }
        else {
            AddressCoordinate(0.0, 0.0)
        }
    }
}

但是,MapboxGeocoder是在编译时在匕首模块中生成的。所以我必须指定地址和TYPE_ADDRESS的字符串。

@Reusable
@Named("address")
@Provides
fun provideAddress(): String = "the address to get coordinates from"

@Reusable
@Provides
@Named("geocoder_criteria")
fun provideGeocoderCriteria(): String = GeocoderCriteria.TYPE_ADDRESS

@Reusable
@Provides
fun provideMapboxGeocoder(@Named("address") address: String, @Named("geocoder_criteria") geocoderCriteria: String): MapboxGeocoder =
    MapboxGeocoder.Builder()
        .setAccessToken("api token")
        .setLocation(address)
        .setType(geocoderCriteria)
        .build()

@Reusable
@Provides
fun provideGeocoding(mapboxGeocoder: MapboxGeocoder): Geocoding =
    GeocodingImp(mapboxGeocoder)

我的component课程:

interface TMDispatchMobileUIComponent {
    @Component.Builder
    interface Builder {
        @BindsInstance
        fun application(application: TMDispatchMobileUIApplication): Builder

        fun build(): TMDispatchMobileUIComponent
    }

    fun inject(application: TMDispatchMobileUIApplication)
}

在主要活动中,我会像这样使用它,因为用户可以输入不同的地址或将标准更改为其他地址。但是在编译模块时,我无法在运行时将任何参数传递给它们:

presenter.getAddressCoordinates("this should be the actual address", GeocoderCriteria.TYPE_ADDRESS)

为了注入Activity,我使用以下内容:

AndroidInjection.inject(this)

有没有解决这个问题的方法?

android dagger-2 dagger.android
4个回答
6
投票

您可以使用“辅助注射”方法解决您遇到的问题。

这意味着您需要使用现有作用域提供的依赖项以及实例创建者(在本例中为主要活动)的某些依赖项来构建类。谷歌的Guice有一个很好的description of what it is and why it is needed

不幸的是,Dagger 2没有这个功能。然而,杰克沃顿正在制作一个可以附加到Dagger的separate library。此外,你可以在他关于Droidcon London 2018的演讲中找到更多细节,在那里他为这个问题专门讨论了一个问题:https://jakewharton.com/helping-dagger-help-you/


3
投票

与已经给出的答案相比,一种不同的方法是通过名为GeoModelFactory的匕首依赖注入获得“工厂”,它可以为您创建GeoModel的新实例。

您可以将地址和类型传递给创建实例的工厂。为了优化,您可以存储已经请求的所有不同地址/类型的引用(如果有很多不同的地址/类型,如果没有删除那么可能导致内存泄漏),或者如果仅存储它也可能就足够了最新的实例和代码的其他部分,只需要求工厂为您提供最后创建的GeoModel。


1
投票

MapboxGeocoder是在运行时动态构造的,在这种情况下,dagger没有多大帮助,因为它的目的是帮助你在编译时构建对象图,就像你手写代码一样。

所以在我看来,你应该在MapboxGeocoder中创建一个getCoordinates()


1
投票

如果愿意,可以在运行时重新创建整个组件,然后将参数作为构造函数参数传递给模块。就像是:

fun changeAddress(address: String) {
    val component = DaggerAppComponent.builder() //Assign this to wherever we want to keep a handle on the component
            .geoModule(GeoModule(address))
            .build()
    component.inject(this) //To reinject dependencies
}

你的模块看起来像:

@Module
class AppModule(private val address: String) {...}

但是,如果您在组件中创建了许多不同的对象,则此方法可能会浪费。

© www.soinside.com 2019 - 2024. All rights reserved.