如何使用Dagger向构造函数注入提供自定义依赖项

时间:2018-10-17 15:20:35

标签: android dagger-2

我有我想注入的NetworkDataSource。我想使用构造函数注入,因为我是此类的所有者:

 public class NetworkDataSource {

    @Inject
    public NetworkDataSource(String url, String method) {
        this.url = url;
        this.method = method;
    }
 }

问题是,当触发Service时,会从BroadcastIntent中检索此构造函数的参数(即依赖项)。因此,我的问题是,如何将从Service检索到的这些参数提供给我的NetworkDataSource构造函数注入?

Service看起来像这样:

public class Service extends IntentService {

   // I would like to inject NetworkDataSource
   //@Inject
   //NetworkDataSource netWorkDataSource;

   public String url;
   public String method;

   @Override
   protected void onHandleIntent(Intent workIntent) {
     url = workIntent.getStringExtra("url");
     method = workIntent.getStringExtra("method");
   }

   ............
   ............

   networkDataSource.myMethod();
}

谢谢。

3 个答案:

答案 0 :(得分:2)

这是一个棘手的问题,因为您会认为Dagger主要解决了现在不再需要引入“ Factory”类来重新配置行为的问题。

但是,实际上,您仍然仍然需要使用“ Factory”类来创建具有动态构造函数参数的对象,这些对象是在运行时获取的。

所以:

 public class NetworkDataSource {

    @Inject
    public NetworkDataSource(String url, String method) {
        this.url = url;
        this.method = method;
    }
 }

将会

@Singleton
public class NetworkDataSourceFactory {
    private final OkHttpClient okHttpClient;
    private final Gson gson;

    @Inject
    public NetworkDataSourceFactory(OkHttpClient okHttpClient, Gson gson) {
        this.okHttpClient = okHttpClient;
        this.gson = gson;
    }

    public NetworkDataSource create(String url, String method) {
        return new NetworkDataSource(okHttpClient, gson, url, method);
    }
}

然后,您现在可以注入NetworkDataSourceFactory,并在收到参数时创建一个NetworkDataSource

@Inject NetworkDataSourceFactory factory;

....
    networkDataSource = factory.create(url, method);

假设您可以使用AutoFactory帮助创建工厂,但是我还没有使用过,我只知道它存在于这个特定用例中。

编辑:您也可以签出https://github.com/square/AssistedInject来解决此问题。

答案 1 :(得分:1)

让我们一步一步地做。 (所有代码都将位于kotlin中)

首先,您拥有

class NetworkDataSource(val url: String, val method: String)

,并且需要使用匕首 module 来创建

@Module
class NetworkModule {
    @Provides
    fun dataSource(@Named("url") url: String, 
                   @Named("method") method: String): NetworkDataSource {
        return NetworkDataSource(url, method)
    }
}

之后,您需要使用匕首 component

@Component(modules = [NetworkModule::class])
interface NetworkComponent {
    fun inject(service: Service)
    @Component.Builder
    interface Builder {
        @BindsInstance
        fun url(@Named("url") url: String): Builder
        @BindsInstance
        fun method(@Named("method") method: String): Builder
        fun build(): NetworkComponent
    }
}

现在您可以将其注入Service

class Service : IntentService {
    @Inject
    lateinit var netWorkDataSource: NetworkDataSource
    override protected fun onHandleIntent(workIntent: Intent) {
        val url = workIntent.getStringExtra("url")
        val method = workIntent.getStringExtra("method")
        DaggerNetworkComponent.builder()
            .url(url)
            .method(method)
            .build()
            .inject(this)
    }
}

就是这样。

答案 2 :(得分:0)

我认为这是不可能的,因为您只能在dagger 2中提供可用的数据源,所以我建议您在这种情况下不要使用依赖注入,因为在构建项目时您的数据不可用