在Android @Singleton注解类匕首2没有被注入注解、匕首、Android、Singleton

2023-09-05 00:26:53 作者:琉璃の浅唇

我目前想匕首2集成到一个Android应用程序。我的项目设置如下:

I am currently trying to integrate Dagger 2 into an Android application. My project setup is as follows:

库 在应用程序(取决于库)

在我的图书馆项目中,我定义的类,我将在后面注入到需要它的(活动和普通班)在库以及应用程序项目的其他类。

In my library project I defined a class that I'll later inject into other classes that need it (Activities and regular classes) in the library as well as the app project.

@Singleton
public class MyManager{
  @Inject
  public MyManager(){
    //Do some initializing
  }
}

现在 - 例如在我的片段或活动或普通班我会如下注入上述辛格尔顿:

Now - for instance in my Fragments or Activities or regular classes I'd inject the above Singleton as follows:

public class SomeClass{

  @Inject
  MyManager myManager;
}

我这样想着,因为在实践中myManager总是空。而显然它的构造函数永远不会被调用要么,所以我想我一定是失去了一些东西配置明智?或者,也许我误解的文档,它并不意味着这样的工作方式呢? MyManager类的目的是成为一个应用广泛的辅助功能的组件,积累的实体 - 这就是为什么我去了@Singleton

Or so I thought, because in practice myManager is always null. And apparently it's constructor is never called either, so I guess I must be missing something configuration-wise? Or maybe I misunderstood the documentation and it's not meant to work this way at all? The purpose of MyManager class is to be an application-wide accessible component-accumulating entity - that's why I went for the @Singleton.

更新

要避免混淆:我的评论,我认为我提到的有分量的地方 - 这是指元件在基于组件的设计的意识,无关与匕首。该匕首型code我首先是上市公司 - 有没有别的相关的匕首在我的code。

To avoid confusion: I mentioned my having components somewhere in a comment I think - this refers to components in the sense of "component based design" and has nothing to do with dagger. The dagger-based code I have is all listed above - there is nothing else related to dagger in my code.

当我开始添加@Component我有一些编译器的问题,因为我的dagger2是未正确设置 - 查看关于如何设置dagger2正确这个真正有用的线索:http://stackoverflow.com/a/29943394/1041533

When I started adding @Component I had some compiler issues, because my dagger2 was not setup properly - check out this really helpful thread on how to setup dagger2 correctly: http://stackoverflow.com/a/29943394/1041533

更新2

下面是我更新code,根据G.隆巴德的建议 - 我改变了code如下 - 原来辛格尔顿在库项目:

Here is my updated code, based on G. Lombard's suggestions - I changed the code as follows - the original Singleton is in the library project:

@Singleton
public class MyManager{
  @Inject
  public MyManager(){
    //Do some initializing
  }
}

另外,在库项目的引导类:

Also in the library project is the bootstrap class:

@Singleton
@Component
public interface Bootstrap {
    void initialize(Activity activity);
}

然后我用上面的自举类在我的活动(在我的具体应用,不会在库项目!我不过也有类/活动在将访问引导库注入MyManager):

Then I use the above Bootstrap class in my activity (in my concrete app, NOT in the library project! I do however also have Classes/Activities in the library that'll access Bootstrap to inject MyManager):

public class MyActivity extends Activity{

    @Inject
    MyManager manager;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        //DONT DO THIS !!! AS EXPLAINED BY EpicPandaForce
        DaggerBootstrap.create().initialize(this);
    }
}

但是,即使这一行:

But even after this line:

        DaggerBootstrap.create().initialize(this);

该管理器实例仍是空,即不注射。

the manager instance is still null, i.e. not injected.

我刚刚发现这一点:http://stackoverflow.com/a/29326023/1041533

这意味着,如果我没有看错,意味着我需要指定引导类的每一个类,将使用@Inject有东西注入。可悲的是 - 这是不是一种选择,因为我有超过40个教学班和活动,我不得不这样做。

Which if I don't misread, implies I need to specify every single class in the Bootstrap class that will use @Inject to have stuff injected. Sadly - this is not an option, as I have more than 40 classes and activities for which I'd have to do that.

我的意思引导接口显然必须是这个样子:

Meaning my Bootstrap interface apparently would have to look something like this:

@Singleton
@Component
public interface Bootstrap {
    void initialize(ActivityA activity);
    void initialize(ActivityB activity);
    void initialize(ActivityC activity);
    void initialize(ActivityD activity);
    void initialize(ActivityE activity);
    void initialize(ActivityF activity);
    //and so on and so forth...
}

如果上面是真实的,那会不会是值得我用例。加:似乎没有编译时检查,如果我忘了指定我的40个类别之一吗?它只是不会工作 - 即崩溃的应用程序在运行时

If the above is true, that would not be worth it for my use case. Plus: Seems there is no compile-time check, if I forgot to specify one of my 40+ classes here? It just wont work - i.e. crash the app at runtime.

推荐答案

你犯了一个错误在你使用

You're making a mistake in that you are using

DaggerBootstrap.create().initialize(this);

在你的活动,因为范围不跨多个组件实例共享。使用自定义的应用程序类,我的建议是

in your Activity, as scopes are not shared across multiple component instances. What I recommend is using a custom application class

public class CustomApplication extends Application {
    @Override
    public void onCreate() {
         super.onCreate();
         Bootstrap.setup();
    }
}

@Component
@Singleton
public interface _Bootstrap {
    void initialize(ActivityA activityA);
    //void initiali...
}

public enum Bootstrap {
    INSTANCE;

    private _Bootstrap bootstrap;

    void setup() {
        bootstrap = Dagger_Bootstrap.create();
    }

    public _Bootstrap getBootstrap() {
        return bootstrap;
    }
}

然后,你可以把它作为

Then you could call it as

Bootstrap.INSTANCE.getBootstrap().initialize(this);

这样一来,你在你的类共享的组件。我个人命名为引导注射器 _Bootstrap ApplicationComponent ,所以它看起来是这样的:

This way, you share the component across your classes. I personally named Bootstrap as injector, and _Bootstrap as ApplicationComponent, so it looks like this:

Injector.INSTANCE.getApplicationComponent().inject(this);

不过,这只是我的典型设置。名字其实并不重要。

But that's just my typical setup. Names don't really matter.

编辑:为了你的最后一个问题,您可以通过subscop​​ing和组件的依赖关系解决这个

To your last question, you can solve this by subscoping and component dependencies.

您库中的项目应该能看到的只是类库,是否正确?在这种情况下,你要做的就是

Your library project should be able to see only the library classes, correct? In that case, all you do is

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface LibraryScope {
}

@Component(modules={LibraryModule.class})
@LibraryScope
public interface LibraryComponent {
    LibraryClass libraryClass(); //provision method for `MyManager`
}

@Module
public class LibraryModule {
    @LibraryScope
    @Provides
    public LibraryClass libraryClass() { //in your example, LibraryClass is `MyManager`
        return new LibraryClass(); //this is instantiation of `MyManager`
    }
}

public enum LibraryBootstrap {
    INSTANCE;

    private LibraryComponent libraryComponent;

    static {
        INSTANCE.libraryComponent = DaggerLibraryComponent.create();
    }

    public LibraryComponent getLibraryComponent() {
        return libraryComponent;
    }
}

@Scope
@Retention(RetentionPolicy.RUNTIME)
public @interface ApplicationScope {
}

@Component(dependencies={LibraryComponent.class}, modules={AdditionalAppModule.class})
@ApplicationScope
public interface ApplicationComponent extends LibraryComponent {
    AdditionalAppClass additionalAppClass();

    void inject(InjectableAppClass1 injectableAppClass1);
    void inject(InjectableAppClass2 injectableAppClass2);
    void inject(InjectableAppClass3 injectableAppClass3);
}

@Module
public class AdditionalAppModule {
    @ApplicationScope
    @Provides
    public AdditionalAppClass additionalAppClass() { //something your app shares as a dependency, and not the library
        return new AdditionalAppClass();
    }
}

public enum ApplicationBootstrap {
    INSTANCE;

    private ApplicationComponent applicationComponent;

    void setup() {
        this.applicationComponent = DaggerApplicationComponent.builder()
                                        .libraryComponent(LibraryBootstrap.INSTANCE.getLibraryComponent())
                                        .build();
    }

    public ApplicationComponent getApplicationComponent() {
        return applicationComponent;
    }
}

然后

@Inject
LibraryClass libraryClass; //MyManager myManager;

...
    ApplicationBootstrap.INSTANCE.getApplicationComponent().inject(this);