代理的目的在 Dagger 2 生成的代码中提供

2022-09-04 22:59:41

我有这个匕首模块。我想了解生成的代码,以便验证我的 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()

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


答案 1

首先:Dagger 会提前生成此代码,以便在模块化构建中,您可以获得更好的构建性能。正因为如此,我们不知道您需要哪个(或两者兼而有之,或者两者都不是),因此我们生成两者以防万一,并假设Proguard将能够剥离任何未使用的内容。

那么,两者实际上在做什么呢?

当请求此工厂表示的绑定为 时,将调用第一个(方法)。这可以直接发生,也可以在绑定限定范围内,或者其他一些方案。get()Provider<T>

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

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

问题是,提供的方法可能无法从与您的组件相同的包中访问,因此我们生成此“代理”方法,该方法为Dagger提供了正确的可访问性。它还使该方法的所有参数都可访问,并在必要时将其删除。如果它们确实被删除了(可以像泛型类型擦除一样),我们需要在代理方法将强制转换插入到正确的类型中。Object

实现不需要这样,因为在那里,所有类型都应该可以通过调用它的代码访问。Provider.get()

所以总结一下 - 我们想生成两个版本,希望你应该只使用一个,而Proguard应该清理另一个。

希望有所帮助!


答案 2

推荐