首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >用Dagger实现单例生成器

用Dagger实现单例生成器
EN

Stack Overflow用户
提问于 2019-11-20 22:54:01
回答 2查看 308关注 0票数 0

我有一门课想通过匕首注射。它需要一个构建器,因为它的一些参数只有在运行时才知道。我也希望这门课能成为单身学生。

也就是说,我们的代码库的几个部分需要这个类的实例,但实际上只有一部分代码库知道如何设置它。

安装在应用程序的早期发生--在任何人实际尝试使用单例之前--但是在Dagger已经初始化了它的根组件之后。

代码的其他部分访问对象的正确方法是什么?

代码语言:javascript
复制
class S {
  private S(Foobar foobar) {
    // ...
  }

  @Singleton
  public static class Builder {
    Foobar foobar;
    @Inject
    public Builder() {}

    public Builder setFoobar(Foobar foobar) {
      this.foobar = foobar;
    }

    public S build() {
      return new S(foobar);
    }
  }
}

class Main {
  private Foobar foobar = new Foobar();
  private final S s;

  @Inject
  public Main(S.Builder sBuilder) {
    s = sBuilder.setFoobar(foobar).build();
  }
}

class Other {
  private final S s;

  @Inject
  public Other(/* What do I put here to get access to S? */) {
  }

编辑:为了清晰起见,让我声明,本例中的Foobar是在应用程序的早期创建的,但是在Dagger和应用程序的高级结构被实例化之后。这个特定的程序是一个安卓应用程序;在本例中,Foobar是一个膨胀的视图,而S是该视图的控制器。

只有一个Foobar和一个S。我们的代码的各个部分都希望能够与S通信,但实际上只有一部分代码能够创建它。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2019-11-25 19:16:38

基于我从@MyDogTom的answer中发出的提示,介绍我们的第一个子组件是解决方案。

直到构建了S之后才构建Foobar。然后初始化一个子组件,将S传递给它的生成器,并使用该子组件构造Other

代码语言:javascript
复制
@Subcomponent
public interface MySubComponent {
    @Subcomponent.Builder
    interface Builder {
        @BindsInstance Builder s(S s);
        StatusBarComponent build();
    }

    /**
     * Scope annotation for singleton items within the MySubComponent.
     */
    @Documented
    @Retention(RUNTIME)
    @Scope
    @interface MySubComponentScope {}

    @MySubComponentScope
    Ohter getOther();

}

// Attach MySubComponent to Dagger where appropriate, per their documentation.
// Then, in Main, do something like the following:


class Main {
  private final MySubComponent.Builder mySubComponentBuilder;
  private final S.Builder sBuilder;
  private Foobar foobar;

  @Inject
  public Main(MySubComponent.Builder mySubComponentBuilder, S.Builder sBuilder) {
    this.mySubComponentBuilder = mySubComponentBuilder;
    this.sBuilder = sBuilder;
  }

  // At some point, foobar gets created. Then we call the following method.
  private void afterInit();
    S s = sBuilder.setFoobar(foobar).build();

    Other other = mySubComponentBuilder.s(s).build().getOther();
  }
}

很明显,这是一个略显做作的例子,但演示了问题的解决方案。

票数 0
EN

Stack Overflow用户

发布于 2019-11-21 10:18:04

您可以将BindsInstance用于https://dagger.dev/api/2.10/dagger/BindsInstance.html

应用程序创建RootComponent。在创建过程中,它应该提供Foobar的实例。让我们看一下伪码

代码语言:javascript
复制
class S {
    private S(Foobar foobar) {
        // ...
    }

    public static class Builder {
        Foobar foobar;

        public Builder() {}

        public Builder setFoobar(Foobar foobar) {
            this.foobar = foobar;
        }

        public S build() {
            return new S(foobar);
        }
    }
}

@Module
public static class RootModule {

    @Provides
    @Singleton
    public static S provideS(Foobar foobar) {
        return new S.Builder().setFoobar(foobar).build();
    }
}

@Singleton
@Component(module = {RootModule.class})
public interface RootComponent {
    @Component.Factory
    interface Factory {
        public RootComponent create(@BindsInstance Foobar foobar)
    }
}

public class Application {
    private RootComponent createComponent() {
        return DaggerRootComponent.factory().create(new Foobar())
    }
}

更新

这个特定的程序是一个Android应用程序;Foobar在本例中是一个膨胀的视图,S是该视图的控制器。

我强烈建议您不要保留对View的引用。这可能会产生微妙的bug和内存泄漏。相反,我建议您引入某种事件总线,它将是Dagger图中的单例,并在S (视图控制器)和使用者之间共享。这个均匀总线将用于用户与S (视图控制器)之间的通信。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/58964669

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档