代码之家  ›  专栏  ›  技术社区  ›  ant2009

如何在运行时将参数从活动或片段传递到匕首模块

  •  5
  • ant2009  · 技术社区  · 7 年前

    我的软件规格如下:

    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)
            }
        }
    }
    

    然而, MAPBOX地理编码器 在编译时在匕首模块中生成。所以我必须指定地址的字符串和 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)
    

    对于我对活动的注入,我使用以下方法:

    AndroidInjection.inject(this)
    

    这个问题有什么解决办法吗?

    4 回复  |  直到 7 年前
        1
  •  6
  •   Gaket    7 年前

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

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

    不幸的是,匕首2没有这个功能。然而,杰克·沃顿正在研究 separate library 可以附在匕首上。此外,你可以在他关于2018年伦敦德立顿的演讲中找到更多细节,他为这个问题专门做了一个完整的演讲部分: https://jakewharton.com/helping-dagger-help-you/

        2
  •  3
  •   CitrusO2    7 年前

    与已经给出的答案相比,另一种方法是通过一个叫做geomodelFactory的匕首依赖注入获得一个“工厂”,它可以为您创建geomodel的新实例。

    您可以将地址和类型传递给创建实例的工厂。为了进行优化,您可以存储已请求的所有不同地址/类型的引用(如果不删除旧的地址/类型,则会导致内存泄漏,如果存在大量不同的地址/类型),或者仅存储最新的实例和代码的其他部分,只需请求工厂为您提供h最后创建的几何模型。

        3
  •  1
  •   jaychang0917    7 年前

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

    所以在我看来,你应该创造一个 MAPBOX地理编码器 里面 getCoordinates() .

        4
  •  1
  •   urgentx Galeb Nassri    7 年前

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

    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) {...}
    

    但是,如果您在组件中创建许多不同的对象,那么这个方法可能是浪费的。