![](/img/trans.png)
[英]Enable to setup android workmanager with dagger to inject repository in android worker
[英]Android Dagger 2.14 setup
我想弄清楚如何用dagger 2设置android项目,但我做错了什么。 Dagger 2和android依赖注入对我来说是相对较新的概念。
这是我的设置。
// App.java root of the application
public class App extends DaggerApplication {
@Override
protected AndroidInjector<? extends DaggerApplication> applicationInjector() {
AppComponent appComponent = DaggerAppComponent.create();
appComponent.inject(this);
return appComponent;
}
}
// AppComponent.java component
@Component(modules = {
AndroidSupportInjectionModule.class,
AppBuilder.class,
SplashModule.class,
AppModule.class})
public interface AppComponent extends AndroidInjector<App> {
}
// AppBuilder.java module which bootstraps activities
@Module
public abstract class AppBuilder {
@ContributesAndroidInjector
abstract SplashActivity splashActivityInjector();
}
我还有扩展DaggerAppCompatActivity和SplashModule的活动,它们在SplashActivity中处理依赖注入
现在这个设置正常,我可以在我的SplashActivity中注入MVP模式演示器,如下所示:
// inside SplashActivity
@Inject
SplashContract.Presenter mPresenter;
和演示者中的MVP视图
// SplashPresenter
@Inject
SplashContract.View view;
到现在为止还挺好。 但现在我想在演示者中进行额外的注射:
@Inject
AppDataManager appDataManager;
AppDataManager类需要构造应用程序上下文。 而且每个应用程序我只需要一个AppDataManager实例。 我不知道如何做到这一点,有很多例子,但他们使用不同的Dagger 2版本,因为我没有真正的经验,它会让人感到困惑。
我尝试设置额外的AppModule类,它应该处理AppDataManager,但它在运行时崩溃。
// AppModule.java
@Module
public class AppModule {
private Context mContext;
public AppModule(Context context) {
mContext = context;
}
@Provides
@Singleton
Context provideContext() {
return mContext;
}
@Provides
@Singleton
AppDataManager provideAppDataManager(Context context) {
return new AppDataManager(context);
}
}
我究竟做错了什么? (我怀疑我应该以不同的方式定义AppModule)。
编辑Logcat:
FATAL EXCEPTION: main
Process: com.domain.application, PID: 16075
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.domain.application/com.domain.application.ui.splash.SplashActivity}: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean com.domain.application.data.AppDataManager.isUserLoggedIn()' on a null object reference
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2984)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3045)
at android.app.ActivityThread.-wrap14(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1642)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6776)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)
Caused by: java.lang.NullPointerException: Attempt to invoke virtual method 'boolean com.domain.application.data.AppDataManager.isUserLoggedIn()' on a null object reference
at com.domain.application.ui.splash.SplashPresenter.openNextActivity(SplashPresenter.java:25)
at com.domain.application.ui.splash.SplashActivity.onCreate(SplashActivity.java:20)
at android.app.Activity.performCreate(Activity.java:6955)
at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1126)
at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2927)
at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3045)
at android.app.ActivityThread.-wrap14(ActivityThread.java)
at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1642)
at android.os.Handler.dispatchMessage(Handler.java:102)
at android.os.Looper.loop(Looper.java:154)
at android.app.ActivityThread.main(ActivityThread.java:6776)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1520)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1410)
您可以将AppComponent
定义如下:
@Singleton
@Component(modules = {AndroidSupportInjectionModule.class, AppBuilder.class, AppModule.class})
interface AppComponent : AndroidInjector<App>
让你的App
使用它:
public class App extends Application implements HasActivityInjector, HasSupportFragmentInjector {
@Inject
DispatchingAndroidInjector<Activity> dispatchingActivityInjector;
@Inject
DispatchingAndroidInjector<Fragment> dispatchingFragmentInjector;
@Override
public void onCreate() {
// Pay attention here: you have to initialize your `AppModule` with the context.
// Without it, Dagger won't be able to provide a `Context`.
// Since your AppDataManager needs a context to be provided, Dagger will also fail to provide it.
DaggerAppComponent.builder()
.appModule(AppModule(this)) // <-- don't forget this line
.build()
.inject(this);
}
@Override
public AndroidInjector<Activity> activityInjector() {
return dispatchingActivityInjector;
}
@Override
public AndroidInjector<Fragment> supportFragmentInjector() {
return dispatchingFragmentInjector;
}
}
你的AppBuilder
应该是这样的:
@Module
public abstract class AppBuilder {
@ContributesAndroidInjector(modules = {SplashModule.class})
abstract SplashActivity splashActivityInjector();
}
和你的AppModule
:
@Module
public class AppModule {
private Context mContext;
public AppModule(Context context) {
mContext = context;
}
@Provides
@Singleton
Context provideContext() {
return mContext;
}
@Provides
@Singleton
AppDataManager provideAppDataManager(Context context) {
return new AppDataManager(context);
}
}
你的SplashModule
:
@Module
abstract class SplashModule {
@Binds
abstract SplashContract.View provideView(SplashActivity activity)
@Binds
abstract SplashContract.Presenter providePresenter(SplashPresenter presenter)
}
在演示者中使用构造函数注入:
@Inject
public SplashPresenter(SplashContract.View view, AppDataManager manager) {
mView = view;
mManager = manager;
}
最后使用@Inject SplashContract.Presenter presenter
者在SplashActivity
注入您的演示@Inject SplashContract.Presenter presenter
。 为此,请确保您的SplashActivity
扩展了DaggerAppCompatActivity
。 此外, SplashActivity
必须实现SplashContract.View
以及SplashPresenter
必须实现SplashContract.Presenter
。
如果您的AppComponent
未声明为Singleton
,则每次注入AppDataManager
时都会有一个不同的实例。 使用@Singleton
标记它确保只要提供它的组件处于活动状态,就会收到相同的对象。 由于您的AppComponent
与您的Application
绑定,因此您的组件不会消亡,因此将提供相同的对象实例。
根据经验,只要有可能,就应该使用构造函数注入。 通过使用它,Dagger将注入创建对象所需的每个参数。 此外,使用@Inject
标记构造函数使其成为依赖图的一部分:现在可以在不必创建@Provides
方法的情况下注入它。
您必须手动初始化AppModule
,因为它使用非空构造函数。 此时,Dagger对如何提供Context
(用于创建AppModule
)没有任何线索。 如果AppComponent
上安装的模块使用默认的空构造函数,则不必自行初始化它。
@Binds
注释用于减少进一步的样板。 它必须应用于具有单个参数的抽象函数,该参数的类型可分配给返回类型。 在您的情况下,参数SplashScreenActivity
实现返回类型SplashContract.View
:每当您注入SplashContract.View
,Dagger将提供SplashScreenActivity
的接口实现。
首先,添加一个自定义Builder
接口和方法inject
,它将App
作为参数接收到AppComponent
:
@Component.Builder
interface Builder {
@BindsInstance
Builder application(App app);
AppComponent build();
}
void inject(App app);
此外,添加@Singleton
注解你AppComponent
接口。
然后构建您的应用程序 在App
类中,使用自定义构建器注入App
实例:
AppComponent appComponent = DaggerAppComponent
.builder()
.application(this)
.build();
appComponent.inject(this);
更新AppModule
以正确提供上下文:
@Provides
Context providesContext(App app) {
return app.getApplicationContext();
}
@Singleton @Provides
AppDataManager provideAppDataManager(Context context) {
return new AppDataManager(context);
}
最后,确保在super
调用之前在您的活动上调用AndroidInjection
的inject
方法:
AndroidInjection.inject(this)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.