我对Daggers依赖注入还很陌生。我正在使用Dagger 2和Kotlin开发新的应用程序。我从一个用于构建的基础入门应用开始。在App.kt中,每个活动都是自动注入的,到现在为止还很酷。但是,现在实施Facebook和Google社交登录遇到了一个问题。
当应用尝试启动Facebook或Google登录活动时,我收到错误消息:
"No injector factory bound for Class<external.activities.classNameHere>"
由于这些外部类未实现@Module批注,因此我无法提供它们。
我的临时解决方案是在自动注入之前检查正在注入的活动,并跳过那些外部类。但是,这似乎有些奇怪,我想知道是否有更好的解决方案,或者是否缺少某些东西。我可以看到这个if语句随着时间的流逝变得很长。
registerActivityLifecycleCallbacks(object : ActivityLifecycleCallbacks() {
override fun onActivityCreated(p0: Activity?, p1: Bundle?) {
p0?.let {
if (p0 is FacebookActivity || p0 is CustomTabMainActivity || p0 is CustomTabActivity ) {
Log.d("KSULog", "App.kt is not injecting activity " + p0.toString())
}
else {
AndroidInjection.inject(p0)
}
}
}
})
}
感谢您的光临。
答案 0 :(得分:3)
执行此操作的方法非常简单。 如果您查看Google样本,将会有一个明确的方向。像GitHubBrowserSample
因此,您将像这样创建一个interface Injectable
,基本上是一个标记器界面。
/**
* Marks an activity / fragment injectable.
*/
interface Injectable
每个活动或片段都会实现此接口,例如(在Kotlin中)
open class BaseActivity : AppCompatActivity(),Injectable {
@Inject
lateinit var viewModelFactory: ViewModelProvider.Factory
lateinit var baseActivityViewModel: BaseActivityViewModel
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
AndroidInjection.inject(this)
baseActivityViewModel = ViewModelProviders.of(this, viewModelFactory)
.get(BaseActivityViewModel::class.java)
}
}
重要的行是:
open class BaseActivity : AppCompatActivity(),Injectable
AndroidInjection.inject(this)
创建一个Activity模块以贡献Activity对象
/**
* Module to contribute all the activities.
*/
@Module
abstract class ActivityModule {
@ContributesAndroidInjector
internal abstract fun contributeSplashActivity(): SplashActivity
}
最后是DaggerInjector
以启用注入
/**
* Helper to inject all the activities and fragments that are marked Injectable.
*/
object DaggerInjector {
fun injectAll(application: TurtleApp) {
DaggerAppComponent.builder()
.application(application)
.build().inject(application)
application
.registerActivityLifecycleCallbacks(object : Application.ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
injectComponents(activity)
}
override fun onActivityStarted(activity: Activity) {
}
override fun onActivityResumed(activity: Activity) {
}
override fun onActivityPaused(activity: Activity) {
}
override fun onActivityStopped(activity: Activity) {
}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
}
override fun onActivityDestroyed(activity: Activity) {
}
})
}
private fun injectComponents(activity: Activity) {
if (activity is Injectable) {
AndroidInjection.inject(activity)
}
// (activity as? FragmentActivity)?.supportFragmentManager?.registerFragmentLifecycleCallbacks(
// object : FragmentManager.FragmentLifecycleCallbacks() {
// override fun onFragmentCreated(fm: FragmentManager?, f: Fragment?,
// savedInstanceState: Bundle?) {
// if (f is Injectable) {
// AndroidSupportInjection.inject(f)
// }
// }
// }, true)
}
}
取消注释代码以启用Fragment
注入。
答案 1 :(得分:1)
您的解决方案很好,但是正如您所说的那样,扩展性不好。
您可以查看Google Samples之一,他们在其中实现了HasSupportFragmentInjector
接口,以确定他们是否要注入活动。
private fun handleActivity(activity: Activity) {
if (activity is HasSupportFragmentInjector) {
AndroidInjection.inject(activity)
}
if (activity is FragmentActivity) {
activity.supportFragmentManager
.registerFragmentLifecycleCallbacks(
object : FragmentManager.FragmentLifecycleCallbacks() {
override fun onFragmentCreated(
fm: FragmentManager,
f: Fragment,
savedInstanceState: Bundle?
) {
if (f is Injectable) {
AndroidSupportInjection.inject(f)
}
}
}, true
)
}
}
答案 2 :(得分:-1)
您应该能够像注入其他类一样注入它们。提供Java中的示例。假设您有AppComponent
和AppModule
类:
@Component(modules = AppModule.class)
public interface AppComponent {
....
void inject(App app);
....
}
@Module
public class AppModule {
@Provides
FacebookActivity providesFacebookActivity() {
return new FacebookActivity();
}
}
然后,您可以注释FacebookActivity以注入到您的主要活动中。
@Inject FacebookActivity mFacebookActivity;
因此,我的外部活动已注入我的主要活动中,而主要活动又实现了AndroidInjection.inject(this)
中定义的AppComponent
。该组件链接到AppModule
为@Provides
的{{1}}。