Dagger 2 生成代码中 proxyProvide 的用途

Purpose of proxyProvide in Dagger 2 generated code

我有这个 Dagger 模块。我想了解生成的代码,以便验证我的 Dagger 配置是否最佳。

@Module
public class TypefaceModule {

    @Provides @Singleton @Named("Roboto Light")
    static Typeface provideRobotoLight(AssetManager assets) {
        return Typeface.createFromAsset(assets, "fonts/Roboto-Light.ttf");
    }

}

这是生成的代码(Dagger 2.14.1):

public final class TypefaceModule_ProvideRobotoLightFactory implements Factory<Typeface> {
  private final Provider<AssetManager> assetsProvider;

  public TypefaceModule_ProvideRobotoLightFactory(Provider<AssetManager> assetsProvider) {
    this.assetsProvider = assetsProvider;
  }

  @Override
  public Typeface get() {
    return Preconditions.checkNotNull(
        TypefaceModule.provideRobotoLight(assetsProvider.get()),
        "Cannot return null from a non-@Nullable @Provides method");
  }

  public static TypefaceModule_ProvideRobotoLightFactory create(
      Provider<AssetManager> assetsProvider) {
    return new TypefaceModule_ProvideRobotoLightFactory(assetsProvider);
  }

  public static Typeface proxyProvideRobotoLight(AssetManager assets) {
    return Preconditions.checkNotNull(
        TypefaceModule.provideRobotoLight(assets),
        "Cannot return null from a non-@Nullable @Provides method");
  }
}

有两个函数做几乎相同的事情:实例方法get()和静态方法proxyProvideRobotoLight()

为什么 Dagger 生成了这段代码的两个版本,它们都静态调用了模块的 provide() 方法?一个不能叫另一个吗?

(顺便说一下,我确实意识到我不再需要在我的应用资产中捆绑字体。这不是这里的问题。)

首先:Dagger 生成此代码 ahead-of-time 以便在模块化构建中获得更好的构建性能。因此,我们不知道 which (或两者,或两者都不需要),所以我们生成两者以防万一,并假设 Proguard 将能够剥离任何东西未使用。

那么两者到底在做什么呢?

第一个(get() 方法)在请求此工厂表示的绑定作为 Provider<T> 时调用。这可以直接发生,或者如果绑定是作用域的,或者其他一些场景。

第二种情况就是我们所说的内联。假设您在模块中有一个 @Provides 方法,并且您的 @Component 上有一个 returns 该类型的方法。最理想的生成代码如下:

@Override
public YourBinding y() {
  return YourModule.yourProvidesMethod();
}

事实是,provides 方法可能无法从与您的组件相同的包中访问,因此我们生成了这个 "proxy" 方法,它为 Dagger 提供了正确的可访问性。它还使该方法的所有参数都可访问,必要时将它们擦除为 Object。如果它们确实被擦除(将其视为通用类型擦除),我们需要将强制转换插入正确的类型 inside 代理方法。

Provider.get() 实现不需要它,因为调用它的代码应该可以访问所有类型。

总而言之 - 我们想要生成两个版本,希望您只使用一个版本,Proguard 应该清理另一个版本。

希望对您有所帮助!