如果有多个模块并且它们都提供应用程序上下文,那么如何将conext注入某个类(例如活动)?
这里有两个模块,都提供应用程序上下文,并且componenet具有getConext()函数和其他一些已定义的
。DataModule
@Module
class DataModule(@ApplicationContext val mAppContext: Context) {
@Singleton
@Provides
@ApplicationContext
internal fun provideAppContext(): Context {
return mAppContext
}
... ...
// provide the DataManagerAdapterImpl
@Provides
@Singleton
internal fun provideDataManagerAdapter(dataManagerAdapter: DataManagerAdapterImpl): DataManagerAdapter {
return dataManagerAdapter
}
}
UIModule
@Module
class UIModule(@ApplicationContext private val applicationContext: Context) {
@Singleton
@Provides
@ApplicationContext
internal fun provideAppContext(): Context {
return applicationContext
}
... ...
}
组件网络:
@Singleton
@Component(modules = arrayOf(UIModule::class, DataModule::class))
interface UIComponent {
@ApplicationContext
fun getContext(): Context
fun dataManagerAdapter(): DataManagerAdapter
... ...
fun inject(dataManagerAdapter: DataManagerAdapter)
fun inject(loginActivity: LoginActivity)
}
喷油器助手:
class DiInjector constructor(@ApplicationContext appContext: Context) {
companion object {
private val sUIComponent: UIComponent by lazy {
DaggerUIComponent.builder()
.dataModule(DataModule(appContext))
.uIModule(UIModule(appContext))
.build()
}
......
getUIComponent() : UIComponent{
return sUIComponent
}
}
}
该类注入上下文:
abstract class DataManagerAdapter {
@Inject
lateinit var context: Context
... ...
}
及其派生类:
class DataManagerAdapterImpl @Inject
constructor() : DataManagerAdapter() {
init {
DiInjector.getUIComponent().inject(this) //<== will inject the context
}
......
}
以及注入DataManagerAdapterImpl的活动
class LoginActivity : AppCompatActivity() {
@Inject
lateinit var mDataManagerAdapter: DataManagerAdapter
public override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.layout_activity)
// this will get the UIComponent
DiInjector.getUIComponent().inject(this) //<== will inject the actual DataManagerAdapterImpl
......
}
... ...
}
如果DataModule和UIModule均提供了Context,则会出现以下错误,并且确实是Componenet的getConext()不知道从哪个模块获取DataModule或UIModule。
e: ../di/UIComponent.java:23: error: @com.data.scope.ApplicationContext android.content.Context is bound multiple times:
public abstract android.content.Context getContext();
^
@org.jetbrains.annotations.NotNull @com.data.scope.ApplicationContext @Provides @Singleton android.content.Context com.data.di.module.UIModule.provideAppContext$sample_debug()
@org.jetbrains.annotations.NotNull @com.data.scope.ApplicationContext @Provides @Singleton android.content.Context com.data.di.module.DataModule.provideAppContext$sample_debug()
如果在DataModule中注释掉上下文提供部分fun provideAppContext(): Context
,那么现在只有UIModule提供上下文。但这将导致追溯到getContext()部分的错误。
不确定为什么componenet的getContext()无法提供UIModule
中的上下文,e: ../di/component/UIComponent.java:35: error: android.content.Context cannot
be provided without an @Provides-annotated method.
public abstract com.data.DataManagerAdapter DataManagerAdapter();
^
android.content.Context is injected at
com.data.DataManagerAdapter.context
data.DataManagerAdapterImpl is injected at
com.di.module.DataModule.provideDataManagerAdapter$doubleplay_debug
(DataManagerAdapter)
com.data.DataManagerAdapter is provided at
com.di.component.UIComponent.DataManagerAdapter()
e: ../di/UIComponent.java:40: error: android.content.Context cannot be provided without an @Provides- or @Produces-annotated method.
public abstract void inject(@org.jetbrains.annotations.NotNull()
^
android.content.Context is injected at
com.data.DataManagerAdapter.context
com.data.DataManagerAdapter is injected at
com.di.component.UIComponent.inject(DataManagerAdapter)
e: ../di/UIComponent.java:43: error: android.content.Context cannot be provided without an @Provides-annotated method.
public abstract void inject(@org.jetbrains.annotations.NotNull()
^
android.content.Context is injected at
com.data.DataManagerAdapter.context
data.DataManagerAdapterImpl is injected at
com.di.module.DataModule.provideDataManagerAdapter$doubleplay_debug(DataManagerAdapter)
com.data.DataManagerAdapter is injected at
com.data.LoginActivity.mAccountManagerAdapter
com.data.LoginActivity is injected at
com.di.component.UIComponent.inject(LoginActivity)
现在是单个提供:
DiInjector.getUIComponent().inject(this)
===
更新:
在标记建议的情况下(将上下文作为构造函数放入参数中,并在DataManagerAdapter::init{} block)
中删除对abstract class DataManagerAdapter(var context: Context) {
// put in constructor
//@Inject
//lateinit var context: Context
... ...
}
的调用,它仍然不起作用。
class DataManagerAdapterImpl @Inject
constructor(context: Context) : DataManagerAdapter(context) {
init {
// remove it, now context is in constructor's param
//DiInjector.getUIComponent().inject(this) //<== will inject the context
}
......
}
子类
e: ../di/UIComponent.java:43: error: android.content.Context cannot be
provided without an @Provides-annotated method.
public abstract void inject(@org.jetbrains.annotations.NotNull()
^
android.content.Context is injected at
com. data.DataManagerAdapterImpl.<init>(context)
com.data.DataManagerAdapterImpl is injected at
com.di.module.DataModule.
provideDataManagerAdapter$doubleplay_debug(DataManagerAdapter)
com.data.DataManagerAdapter is injected at
com.data.LoginActivity.mAccountManagerAdapter
com.data.LoginActivity is injected at
com.di.component.UIComponent.inject(LoginActivity)
在无法解析压缩文件时仍然出现错误
generic base class DataManagerAdapter
以下理解是否正确?
LoginActivity依赖于fun inject(loginActivity: LoginActivity)
,而UIComponent的generic base class DataManagerAdapter
可以解决该问题。
fun provideDataManagerAdapter(dataManagerAdapter: DataManagerAdapterImpl):
DataManagerAdapter {
return dataManagerAdapter
},
由DataModule的
sub class DataManagerAdapterImpl
依赖于实现sub class DataManagerAdapterImpl
。
DataManagerAdapter(var context: Context)
的实现使用构造函数注入,因此它是隐式提供的。
现在,class DataManagerAdapterImpl @Inject constructor(context: Context) :
DataManagerAdapter(context) {}
和子类中的上下文是必需的参数
fun provideAppContext(): Context
因此它依赖于UIComponenet通过UIModule的"android.content.Context cannot be provided without an @Provides-annotated method"
提供的上下文。
为什么它仍然抱怨{{1}}?