Dagger单例每次创建新实例问题

7
我有一个如下的模块。
@Module
public class AppModule {
    private final Application app;

    public AppModule(Application app) {
        this.app = app;
    }

    @Provides
    @Architecture.ApplicationContext
    Context provideContext() {
        return app;
    }

    @Provides //scope is not necessary for parameters stored within the module
    public Context context() {
        return provideContext();
    }

    @Singleton
    @Provides
    Application provideApp() {
        return app;
    }

    @Singleton
    @Provides
    SoundsRepository provideSoundsRepository(Context context, SoundsDAO soundsDAO) {
        return new SoundsRepository(context, soundsDAO);
    }
}

像这样的一个组件。
@Singleton
@Component(modules = AppModule.class)
public interface AppComponent {

    void inject(Global global);

    void inject(MainActivity mainActivity);


    @Architecture.ApplicationContext
    Context getContext();

    Application getApplication();

    void inject(PostView postView);

    void inject(MediaPlayerService mediaPlayerService);
}

在活动、片段或服务中,我这样做

@Inject
    SoundsRepository soundsRepository;

@Override
protected void onCreate(...) {
    //....
    ((Global) getApplication()).getComponent().inject(this);
}

在SoundsRepository中

@Singleton
public class SoundsRepository {
    @Inject
    public SoundsRepository(Context context, SoundsDAO soundsDAO) {
        this.context = context;
        this.soundsDAO = soundsDAO;
        System.out.println(TAG + "INIT");
    }
    // ....

}

所以,现在每当我开始访问一个需要注入SoundsRepository的活动或服务时,我都会得到一个新的实例,我的意思是,“SoundsRepository”的构造函数再次启动。

我做错了什么?

编辑:在应用程序类中注入

public class Global extends MultiDexApplication {

    protected AppComponent appComponent;
    private boolean calledAlready = false;

    @Override
    public void onCreate() {
        super.onCreate();
        //if (LeakCanary.isInAnalyzerProcess(this)) return;
        //LeakCanary.install(this);
        initFirebasePersistance();
        appComponent = DaggerAppComponent.builder().appModule(new AppModule(this)).build();
        appComponent.inject(this);
        FrescoUtil.init(getApplicationContext());
    }


    public AppComponent getComponent() {
        return appComponent;
    }
}

1
请问您能否添加一下您是如何创建应用程序组件的呢?也就是说,您是如何创建此处返回的组件:((Global) getApplication()).getComponent()?还有,您是在什么时候销毁它呢? - Fred
3
该死...一切看起来都很好。我还需要再多一分钟 :| - Fred
2
我不知道。一切似乎都没问题。你是在应用程序创建时创建组件,并将其保留到应用程序实际销毁。这意味着所有作用域为单例的内容应该在每个应用程序运行内部保持单例。也许要仔细检查一下,确保你没有看到来自先前应用程序运行的日志。此外,在提供程序方法上放置一个日志或其他东西。你可能会在dagger之外的某个地方意外调用“new SoundsRepository()”。 - Fred
3
尝试从构造函数中删除注入的注释,因为显然您没有使用构造函数注入,并查看是否可以解决问题,这可能是问题的原因。另外,您应考虑切换到适当的构造函数注入,并从模块中删除提供方法,将作用域添加到类顶部。 - David Medenjak
尝试将单例作用域添加到以下方法中:@Provides @Architecture.ApplicationContext Context provideContext() { return app; } @Provides // 对于存储在模块内的参数,范围是不必要的 public Context context() { return provideContext(); } - Eugene Popovich
显示剩余15条评论
1个回答

5
  1. In your module you have a method that provides an instance of SoundsRepository - good
  2. In your AppComponent you are missing a:

    SoundsRepository soundsRepository();
    
  3. In your Global which extends Application/MultidexApplication you create your DaggerAppComponent - good

  4. In your other activities/fragments/services just call:

    Global application = (Global) getApplication();
    SoundsRepository sr = application.getComponent().soundsRepository()
    

Android保证您的应用程序(全局)类只有一个实例,供所有其他活动/服务使用(有点像单例)。

因此,请将组件放在该应用程序类中,每当您需要使用类时,请调用: (YourApplication) getApplication().getComponent().yourSingleInstanceSomething();

我为您创建并测试了样例代码:https://github.com/zakrzak/StackDaggerTest

Dagger的@Singleton只是一个作用域,并不能保证返回一个类的单一实例。

据我理解,如果您:

void inject(PostView postView);

您可以使用@Provided注释告诉Dagger将AppModule中用@Provided注释的所有内容在您请求时立即访问并提供给您的PostView。请按照以下方式操作:
@Inject
SoundsRepository soundsRepository;

然后Dagger只调用@provided方法,在您的情况下返回一个新的SoundRepository实例:
@Singleton
@Provides
SoundsRepository provideSoundsRepository(Context ........) {
    return new SoundsRepository(...);
}

这是导致你问题的原因。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接