Назначение proxyProvide в кинжале 2 сгенерированный код

У меня есть этот кинжальный модуль. Я хочу понять сгенерированный код, поэтому я могу проверить, что моя конфигурация кинжала оптимальна.

@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 [email protected] @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 [email protected] @Provides method");
  }
}

Существуют две функции, которые выполняют почти одно и то же: метод экземпляра get() и статический метод proxyProvideRobotoLight().

Почему Dagger сгенерировал две версии этого кода, которые статически называют метод provide() модуля provide()? Нельзя ли позвонить другому?

(Кстати, я понимаю, что мне больше не нужно связывать шрифты в моих активах приложения. Это не вопрос здесь.)

Ответ 1

Во-первых: кинжал генерирует этот код досрочно, поэтому в модульной сборке вы получаете лучшую производительность сборки. Из-за этого мы не знаем, какой (или и тот, и другой) вам понадобится, поэтому мы генерируем как на всякий случай, так и предположим, что Proguard сможет отключить все, что не используется.

Итак, что же происходит на самом деле?

Первый (метод get()) вызывается, когда привязка, которую этот factory представляет, запрашивается как Provider<T>. Это может произойти либо напрямую, либо если привязка привязана, или несколько других сценариев.

Второй случай - это то, что мы называем вложением. Предположим, что у вас есть метод @Provides в модуле, и у вас есть метод на @Component, который возвращает этот тип. Самый идеальный код для генерации - это что-то вроде:

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

Дело в том, что метод, предоставляющий метод, может быть недоступен из того же пакета, что и ваш компонент, поэтому мы генерируем этот метод "прокси", который дает Кинжал правильную доступность. Он также делает доступными все параметры для этого метода, стирая их до Object, если необходимо. И если они действительно стираются (подумайте об этом как стирание стираемого типа), нам нужно затем вставить приведения в правильные типы внутри прокси-метода.

Реализация Provider.get() не нуждается в этом, потому что там все типы должны быть доступны с помощью кода, который его вызывает.

Итак, чтобы подвести итог - мы хотим сгенерировать обе версии, надеюсь, вы должны использовать только один, и Proguard должен очистить другой.

Надеюсь, что это поможет!