如何通过Dagger 2使Fragment与宿主Activity保持存活?
实现带底部导航的MainActivity与Fragment的Dagger注入方案
我来分享一下针对这个需求的完整实现方案,完全参考了谷歌蓝图示例里的自定义作用域用法,分模块给你拆解清楚:
1. 先定义自定义作用域注解
首先我们需要实现@ActivityScoped和@FragmentScoped这两个自定义作用域,用来限定依赖的生命周期与对应组件保持一致:
import javax.inject.Scope /** * 限定依赖生命周期与Activity一致 */ @Scope @MustBeDocumented @Retention(value = AnnotationRetention.RUNTIME) annotation class ActivityScoped /** * 限定依赖生命周期与Fragment一致 */ @Scope @MustBeDocumented @Retention(value = AnnotationRetention.RUNTIME) annotation class FragmentScoped
2. MainActivity的Module(@ActivityScoped)
这个Module负责关联MainActivity下的所有Fragment注入器,标注@ActivityScoped确保依赖只在当前Activity生命周期内有效:
import dagger.Module import dagger.android.ContributesAndroidInjector @Module abstract class MainActivityModule { // 为GalleryFragment自动生成注入子组件,并关联GalleryModule @FragmentScoped @ContributesAndroidInjector(modules = [GalleryModule::class]) abstract fun contributeGalleryFragment(): GalleryFragment // 为ProfileFragment自动生成注入子组件,这里假设ProfileFragment有对应Module @FragmentScoped @ContributesAndroidInjector(modules = [ProfileModule::class]) abstract fun contributeProfileFragment(): ProfileFragment }
用@ContributesAndroidInjector可以省去手动编写Fragment子组件的代码,是Dagger Android推荐的简化写法。
3. GalleryFragment的Module(@FragmentScoped)
GalleryModule负责提供GalleryFragment所需的所有依赖,标注@FragmentScoped保证每个GalleryFragment实例都拥有独立的依赖实例:
import dagger.Module import dagger.Provides @Module class GalleryModule { // 示例:提供GalleryFragment需要的仓库类依赖 @FragmentScoped @Provides fun provideGalleryRepository(): GalleryRepository { return GalleryRepositoryImpl() } }
在GalleryFragment内部,只需通过@Inject注解即可完成依赖注入:
class GalleryFragment : Fragment() { @Inject lateinit var galleryRepository: GalleryRepository override fun onCreate(savedInstanceState: Bundle?) { AndroidInjection.inject(this) super.onCreate(savedInstanceState) // 此时galleryRepository已完成注入可直接使用 } // Fragment其他业务逻辑... }
4. AppComponent 根组件定义
最后定义根组件AppComponent,作为整个依赖注入体系的入口,包含全局模块和MainActivity的Module:
import dagger.Component import dagger.android.AndroidInjector import dagger.android.support.AndroidSupportInjectionModule import javax.inject.Singleton @Singleton @Component( modules = [ AndroidSupportInjectionModule::class, MainActivityModule::class, // 其他全局依赖模块... ] ) interface AppComponent : AndroidInjector<MyApplication> { @Component.Factory interface Factory : AndroidInjector.Factory<MyApplication> }
在自定义Application类中初始化Dagger:
class MyApplication : DaggerApplication() { override fun applicationInjector(): AndroidInjector<out DaggerApplication> { return DaggerAppComponent.factory().create(this) } }
底部导航切换Fragment的逻辑
在MainActivity中,通过底部导航的点击事件切换Fragment即可,Dagger会自动完成Fragment的依赖注入:
class MainActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { AndroidInjection.inject(this) super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) val bottomNav = findViewById<BottomNavigationView>(R.id.bottom_nav) bottomNav.setOnItemSelectedListener { item -> when (item.itemId) { R.id.nav_gallery -> { supportFragmentManager.beginTransaction() .replace(R.id.fragment_container, GalleryFragment::class.java, null) .commit() true } R.id.nav_profile -> { supportFragmentManager.beginTransaction() .replace(R.id.fragment_container, ProfileFragment::class.java, null) .commit() true } else -> false } } // 默认加载GalleryFragment if (savedInstanceState == null) { bottomNav.selectedItemId = R.id.nav_gallery } } }
内容的提问来源于stack exchange,提问作者Boris Rozhkovsky
相关产品推荐
相关产品推荐

