【问题标题】:Dagger 2 singletons not working匕首 2 单例不工作
【发布时间】:2015-04-03 15:59:41
【问题描述】:

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

在这个测试项目中,我有一个初始化 DaggerModule 的 MainActivity。 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());
    }
}

@Module
public class DaggerModule {

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

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

}

@Singleton
@Component(modules = { DaggerModule.class })
public interface DaggerComponent {

    Cat provideCat();

    Box provideBox();

}

public class Cat {

    @Inject
    public Cat() {
    }

}

public class Box {

    private Cat mCat;

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

    public Cat getCat() {
        return mCat;
    }

}

提前致谢!

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

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

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

在 MainActivity 中调用 provideCat 和在 DaggerModule 中的 provideBox 中调用有什么区别?难道 Dagger 编译器没有像处理外部类那样处理 DaggerModule 并且如果我在那里调用 provideCat 注释不会被应用?

【问题讨论】:

    标签: java android dependency-injection dagger-2


    【解决方案1】:

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

    但是由于组件方法不接受参数,解决方案只是在需要的地方将实例作为参数注入到模块方法中(而不是从模块本身调用相应的提供方法),并且只需要调用MainActivity 中组件的无参方法如下:

    主活动:

    Cat cat = daggerComponent.provideCat();
    Box box = daggerComponent.provideBox();
    

    组件:

    Cat provideCat();
    Box provideBox(); <- no arguments
    

    模块:

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

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

    【讨论】:

    • 行为不同的原因是实例管理是由组件实现来处理的,而不是模块。当您直接调用该方法时,它只会像任何其他 Java 方法一样调用它,但是当您让组件将依赖项连接在一起时,它将使用dagger.internal.ScopedProvider 来确保只有一个实例。
    • 另外,对于 @Injected 的类型,您可以直接使用 @Singleton 注释类(在本例中为 CatBox)并完全避免使用 @Provides 方法.
    • 感谢您的信息和提示!
    • 有一个非常相似的问题。这为我节省了很多头撞。谢谢!
    • 是的。对于调用provder方法和Injector方法之间的区别以及为什么要使用这两种方法,我有点困惑。仍然不是 100%。
    猜你喜欢
    • 2015-01-17
    • 1970-01-01
    • 1970-01-01
    • 2020-10-02
    • 1970-01-01
    • 2019-11-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多