簡體   English   中英

尋找 Dagger 輔助注入的示例

[英]Looking for an example for Dagger assisted injection

來自匕首討論@

我有一個 class,它從 object 圖中獲取一些依賴項,並在運行時從調用者獲取其他依賴項。

public class ImageDownloader {
  // Get these dependencies from the injector.
  private final HttpClient httpClient;
  private final ExecutorService executorService;

  // Get these from the caller.
  private final URL imageUrl;
  private final ImageCallback callback;

  ...
}

我想出了一個解決方案,我定義了一個工廠,

public class ImageDownloader {
  ...
  public static class Factory {
    private final HttpClient httpClient;
    private final ExecutorService executorService;

    @Inject
    public Factory(HttpClient httpClient, ExecutorService executorService) {
      this.httpclient = httpClient;
      this.executorService = executorService;
    }

    public ImageDownloader create(URL imageUrl, ImageCallback callback) {
      return new ImageDownloader(httpClient, executorService, iamgeUrl, callback);
    }
  }
  ...
}

現在,我沒有在客戶端的構造函數中注入ImageDownloader ,而是簡單地注入ImageDownloader.Factory並調用它的create()方法。

如您所見,這非常冗長。 它還有一堆重復和樣板。 使用@Inject注釋字段本身存在一些障礙,所以讓我們暫時忽略這種可能性。

Square 人員提出了一個有趣的解決方案,即使用提供程序。 定義一個Factory接口,

public class ImageDownloader {
  ...
  public interface Factory {
    ImageDownloader create(URL imageUrl, ImageCallback callback);
  }
}

然后在模塊中提供它,

public class ImageModule {
  ...
  @Provides 
  public ImageModule.Factory provideImageModuleFactory(
      final Provider<HttpClient> httpClientProvider, 
      final Provider<ExecutorService> executorServiceProvider) {
    return new ImageDownloader.Factory() {
      public ImageDownloader create(URL imageUrl, ImageCallback callback) {
        return new ImageDownloader(httpClientProvider.get(), executorServiceProvider.get(),
            imageUrl, callback);
      }
  }
  ...
}

(同樣來自 dagger-discuss@)。

我的ImageDownloader是一個 class,由 class 注入,由另一個 class 注入,而另一個 class 注入,...,在@Module中引用。 這一切都以某種方式*有效,並且所有類都在構建時找到。 現在,要添加模塊,我必須明確讓 object 圖知道它。

我一定遺漏了一些東西——注入一個新的 class 非常容易,但是添加一個新模塊非常乏味。

我的問題是:在實踐中如何進行輔助注射? 有人有例子嗎? 如果有的話,我應該如何使用ImageModule

* - “不知何故”確實暗示它對我來說有一定的魔力。

因此,谷歌的一些Dagger / Guice人員在一個包含AutoFactory(代碼生成的輔助注入),AutoValue(代碼生成的自定義值)的項目中創建了一個名為AutoFactory( http://github.com/google/auto )的東西。 types)和AutoService(自動生成java服務元數據文件)。

AutoFactory幾乎可以像您期望的那樣運行 - 它會生成您手工軋制的工廠。 這是一個非常早期的版本,我們計划了更多的靈活性,但它將生成一個工廠類,它將采用包含一些JSR-330可注入依賴項和一些調用堆棧參數的類型,並在創建實例時將它們合並在一起帶注釋的類型。

實質上,如果您正確注釋工廠創建的類型,它將自動生成您編寫的工廠。

例如,如果您創建了您的類:

@AutoFactory
public class ImageDownloader {
  // Get these dependencies from the injector.
  private final HttpClient httpClient;
  private final ExecutorService executorService;

  // Get these from the caller.
  private final URL imageUrl;
  private final ImageCallback callback;

  ImageDownloader(
      @Provided HttpClient httpClient,
      @Provided ExecutorService executorService,
      ImageCallback callback,
      URL imageUrl) {
    // assignments
  }
}

AutoFactory將生成:

@Generated("com.google.auto.factory.processor.AutoFactoryProcessor")
public final class ImageDownloaderFactory {
  private final Provider<ExampleClasses.HttpClient> httpClientProvider;
  private final Provider<java.util.concurrent.ExecutorService> executorServiceProvider;

  @Inject
  public ImageDownloaderFactory(
      Provider<ExampleClasses.HttpClient> httpClientProvider,
      Provider<java.util.concurrent.ExecutorService> executorServiceProvider) {
    this.httpClientProvider = httpClientProvider;
    this.executorServiceProvider = executorServiceProvider;
  }

  public ImageDownloader create(ImageCallback callback, URL imageUrl) {
    return new ImageDownloader(
        httpClientProvider.get(), 
        executorServiceProvider.get(), 
        callback, 
        imageUrl);
  }
}

(注意,我們在輸出源上有一堆清理工作,但上面基本上是生成的,但格式不是很好。)

然后,生成的類是一個JSR-330兼容的可注入類,你可以在你的依賴圖(Dagger或Guice)中注入它,它將為你創建這些對象,將調用堆棧狀態與提供的依賴關系混合在一起適當。

你可以注入上面的Just-In-Time,或者你可以在閑暇時通過@Provides方法提供它。

您甚至可以讓工廠實現工廠接口,然后簡單地將兩者綁定在一個匕首模塊中,如下所示:

@AutoFactory(implementing = MyFactoryInterface.class)
public class ImageDownloader {
  // ... otherwise as above...
}

@Module(...)
class MyModule {
  @Provides MyFactoryInterface factoryImpl(ImageDownloaderFactory impl) {
    return impl;
  }
}

正如@xsveda所說,對於輔助注射,你可能想要使用AssistedInject 我在這篇博文中寫過這篇文章 ,但我會在這里添加一個完整的例子來簡化事情。

你需要的第一件事是依賴:

compileOnly 'com.squareup.inject:assisted-inject-annotations-dagger2:0.5.0'
kapt 'com.squareup.inject:assisted-inject-processor-dagger2:0.5.0'

那么這是你的例子的樣子:

class ImageDownloader @AssistedInject constructor(
  private val httpClient: HttpClient,
  private val executorService: ExecutorService,
  @Assisted private val imageUrl: URL,
  @Assisted private val callback: ImageCallback
) {

  @AssistedInject.Factory
  interface Factory {
    fun create(imageUrl: URL, callback: ImageCallback): ImageDownloader
  }
}

首先,不是使用@Inject注釋構造函數,而是使用@AssistedInject對其進行@AssistedInject 然后我們注釋必須通過工廠的參數,這與AutoFactory所期望的相反。 最后,我們需要一個帶有@AssistedInject.Factory注釋的內部工廠接口,它有一個接收輔助參數的方法並返回我們感興趣的實例。

不幸的是,我們還有一個額外的步驟:

@AssistedModule
@Module(includes = [AssistedInject_AssistedInjectModule::class])
interface AssistedInjectModule

我們不一定需要專門的模塊,即使這是一個有效的選項。 但是我們也可以在已經安裝在組件中的另一個模塊中添加這些注釋。 這里的好處是我們只需要做一次,之后任何工廠都會自動成為圖形的一部分。

有了它,您基本上可以像平常一樣注入工廠並詢問您的對象。

您可以使用square / AssistedInject使用Dagger進行輔助注射

請在此處查看我的原始答案: https//stackoverflow.com/a/53719342/2862474

從 2021 年 1 月的Dagger 2.31開始,Dagger 現在原生支持輔助注入推薦使用 Square 和 Auto 選項 這些其他選項仍然有效,但與本機選項相比可能需要額外設置。

對於您的情況,您需要使用@AssistedFactory定義工廠接口,然后在構造函數中指定 arguments 來自它:

public class ImageDownloader {
  @AssistedFactory
  public interface Factory {
    ImageDownloader create(URL imageUrl, ImageCallback callback);
  }

  @AssistedInject
  public Factory(
      HttpClient httpClient,
      ExecutorService executorService,
      @Assisted URL imageUrl,
      @Assisted ImageCallback callback) {
    // ...
  }
}

您的模塊不需要參與,並注意與@AssistedInject相比缺少@Inject 正如上面鏈接的文檔一樣,當工廠提供兩個相同類型的 arguments 時,有一些選項。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM