Подтвердить что ты не робот

Lazy Injection с кинжалом 2 на Android

Im new to Dagger 2. У меня есть этот сценарий, я не хочу вводить объект в свое приложение (в презентациях, в api)

У меня нет способа предоставить его изначально. Он не создается до завершения проверки подлинности на каком-то этапе моего приложения.

Из документации http://google.github.io/dagger/

Я вижу, что ленивая загрузка может быть способом решить эту проблему, например.

@Inject 
Lazy<Grinder> lazyGrinder;

а затем получите значение, подобное этому, используя:   lazyGrinder.get() измельчить();.

Мои вопросы:

  • Можно ли безопасно заменить объект после этого новым?
  • Есть ли другие рекомендуемые способы сделать это?

Спасибо

4b9b3361

Ответ 1

Это не подходит для Lazy. Lazy - отличный способ отложить дорогостоящую инициализацию объекта, но это подразумевает определенную семантику, которую вы не хотите или не хотите, особенно в отношении желаемого поведения "безопасной замены".

Проще говоря, Lazy - это оболочка провайдера, которая memoizes локально:

  • Если вы никогда не звоните get, Кинжал никогда не создает объект, о котором идет речь.
  • Первый вызов get создает и сохраняет экземпляр объекта.
  • Второй вызов get возвращает тот же экземпляр и так далее, независимо от того, был ли объект помечен как Singleton.

Это делает Lazy отличным выбором для дорогостоящего объекта, который в противном случае был бы полем (но никогда не может использоваться). Однако, если ссылка, скорее всего, изменится (как ваша воля), Lazy просто запутается: она сохранит значение при первом использовании и никогда не будет локально обновляться, поэтому несколько устаревших копий могут плавать в вашем приложении независимо от того, о том, что означает "правильное" значение в любой момент времени.


Чтобы воспользоваться использованием Grinder из вашего примера, лучшие решения включают:

  • Использование метода @Provides, который возвращает поле в модуле, которое может быть обновлено позже. Вам нужно будет ввести Provider<Grinder> для каждого экземпляра долгоживущего объекта, потому что введенные ссылки только на Grinder не будут обновляться. Это может быть лучшим выбором, если у вас много короткоживущих объектов.

    Ссылка неявно singleton, но не аннотируется как таковая, потому что вы сами контролируете экземпляр. Кинжал будет часто называть ваш метод getGrinder.

    @Module public class YourModule {
      private Grinder grinder;
    
      public void setGrinder(Grinder grinder) {
        this.grinder = grinder;
      }
    
      @Provides public Grinder getGrinder() {
        return grinder;
      }
    }
    
    /* elsewhere */
    YourModule module = new YourModule();
    YourComponent component = DaggerYourComponent.builder()
        .yourModule(module)
        .build();
    /* ... */
    module.setGrinder(latestAndGreatestGrinder);
    
  • Как упоминалось в комментариях к EpicPandaForce, создайте/соедините один объект GrinderHolder, GrinderController или AtomicReference, который предоставляет текущий экземпляр и позволяет обновлять. Таким образом, невозможно сразу вводить Grinder, но легко и понятно вводить объект, который извлекает текущую правильную шлифовальную машину. Если ваша реализация Singleton GrinderHolder не создает Grinder до тех пор, пока вы ее не попросите, вы фактически создали Lazy singleton самостоятельно.

Ответ 2

Если вы не можете предоставить объект во время создания Компонента, не добавляйте его на свой графа Component! Это требует путаницы зависимостей графов и несогласованности. Лучшее решение того, что вы рассматриваете, - это подход @Subcomponent, который позволяет вам создать новый компонент, который наследует зависимости от родителя, но также добавляет новый. Вот пример:

@Component
interface RegularComponent {
  @AppInstanceId String appInstanceId(); // unique per app install; not related to logging in
  AuthenticatedComponent newAuthenticatedComponent();
}

@Subcomponent
interface AuthenticatedComponent {
  Set<Friend> friends();
  @AccountId String accountId();
}

Здесь @AccountId в подкомпоненте может использовать appInstanceId для предоставления идентификатора учетной записи (если это необходимо), поскольку подкомпонент разделяет зависимости с его родительским компонентом.

Если вам нужно предоставить состояние вашим модулям для подкомпонента (с помощью идентификатора accountId, auth и т.д.), не стесняйтесь передавать его в качестве параметра в @Module и хранить его в поле private final. Вы можете узнать больше о том, как поставлять модули подкомпонентов в документации.