匕首2单身人士不工作

jom*_*mni 12 java android dependency-injection dagger-2

使用Dagger 2,我试图在单个范围内的多个位置注入单个对象.但是,似乎我的解决方案每次都会创建一个新实例.

在这个测试项目中,我有一个MainActivity初始化DaggerModule.DaggerModule提供Box和Cat对象,Box以Cat为参数.我也在我的MainActivity中接受了Cat.最后,我检查了注入的两个Cat变量的引用(分别在Box和MainActivity中),但它们不是同一个实例.

如果我在MainActivity中调用了两次provideCat(),则会提供相同的实例.

主要活动:

public class MainActivity extends ActionBarActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        DaggerModule daggerModule = new DaggerModule();
        DaggerComponent daggerComponent = Dagger_DaggerComponent.builder()
                .daggerModule(daggerModule).build();

        // Same Cat instance returned.
        Cat cat1 = daggerComponent.provideCat();
        Cat cat2 = daggerComponent.provideCat();
        Log.d("=== cat1: ", cat1.toString());
        Log.d("=== cat2: ", cat2.toString());

        // Different Cat instance returned. Why?
        Box box = daggerComponent.provideBox();
        Log.d("=== box cat: ", box.getCat().toString());
    }
}
Run Code Online (Sandbox Code Playgroud)
@Module
public class DaggerModule {

    @Provides
    @Singleton
    public Cat provideCat() {
        return new Cat();
    }

    @Provides
    @Singleton
    public Box provideBox() {
        return new Box(provideCat());
    }

}
Run Code Online (Sandbox Code Playgroud)
@Singleton
@Component(modules = { DaggerModule.class })
public interface DaggerComponent {

    Cat provideCat();

    Box provideBox();

}
Run Code Online (Sandbox Code Playgroud)
public class Cat {

    @Inject
    public Cat() {
    }

}
Run Code Online (Sandbox Code Playgroud)
public class Box {

    private Cat mCat;

    @Inject
    public Box(Cat cat) {
        mCat = cat;
    }

    public Cat getCat() {
        return mCat;
    }

}
Run Code Online (Sandbox Code Playgroud)

提前致谢!

编辑: 如果provideBox接受Cat参数并使用它创建Box,而不是直接从provideBox中调用provideCat,则它可以工作.

    // Doesn't work, new Cat instance created.
    @Provides
    @Singleton
    public Box provideBox() {
        return new Box(provideCat());
    }
Run Code Online (Sandbox Code Playgroud)

VS

    // Works, same singleton injected.
    @Provides
    @Singleton
    public Box provideBox(Cat cat) {
        return new Box(cat);
    }
Run Code Online (Sandbox Code Playgroud)

在MainActivity中调用provideCat和在DaggerModule中的provideBox中执行它有什么区别?是不是Dagger编译器不像处理外部类那样处理DaggerModule,如果我在那里调用provideCat,注释就不会被应用?

jom*_*mni 7

我想从provideBox中调用provideCat的原因是我对Component接口的误解.我误解了Component实际上没有实现Component接口,因此Module的方法的参数不必在Component的相应方法中声明.如果是这样的话,它会强迫我在MainActivity的provideBox方法调用中创建Cat实例,我想避免这种情况(因此直接在Module的provideBox方法中调用provideCat).事实上,在Component方法中声明参数甚至使得Dagger编译器无法编译.

但由于Component方法不接受参数,因此解决方案只是在需要时在Module方法中将实例作为参数注入(而不是从Module本身中调用相应的provide方法),并且只需要调用Component的无参数方法来自MainActivity如下:

主要活动:

Cat cat = daggerComponent.provideCat();
Box box = daggerComponent.provideBox();
Run Code Online (Sandbox Code Playgroud)

零件:

Cat provideCat();
Box provideBox(); <- no arguments
Run Code Online (Sandbox Code Playgroud)

模块:

@Module
public class DaggerModule {

    @Provides
    @Singleton
    public Cat provideCat() {
        return new Cat();
    }

    @Provides
    @Singleton
    public Box provideBox(Cat cat) { <- arguments
        return new Box(cat);
    }

}
Run Code Online (Sandbox Code Playgroud)

MainActivity和Box的Cat单例实例现在是相同的,我不必从MainActivity声明它们,但是Dagger处理了所有这些.成功!但是,仍然不确定为什么提供方法在从外部类调用时的工作方式与在模块本身内调用时的方式不同.

  • 另外,对于`@Inject`ed类型,你可以直接使用`@ Singleton`注释类(在本例中为`Cat`和`Box`),并完全避免使用`@ Provide`方法. (6认同)
  • 行为不同的原因是实例管理由组件实现而不是模块处理.当您直接调用该方法时,它只会像任何其他Java方法一样调用它,但是当您让组件将依赖关系连接在一起时,它将使用`dagger.internal.ScopedProvider`来确保只有一个实例. (2认同)