我在项目中使用Dagger 2进行依赖注入
问题是当我试图在片段类中注入一个ViewPageAdapter
时,它依赖于FragmentManager
,如下所示:
@Inject
lateinit var mainTripsFragmentAdapter: MainTripsFragmentAdapter
我收到以下构建错误:
错误:[dagger.android.AndroidInjector.inject(T)]如果没有@ Provide-annotated方法,则无法提供android.support.v4.app.FragmentManager。
公共抽象接口AppComponent扩展dagger.android.AndroidInjector { ^ 注入android.support.v4.app.FragmentManager com.example.presenters.main.trips.MainTripsFragmentAdapter。(fragmentManager,...) 注入com.example.presenters.main.trips.MainTripsFragmentAdapter com.example.presenters.main.trips.MainTripsFragment.mainTripsFragmentAdapter 注入com.example.presenters.main.trips.MainTripsFragment com.example.presenters.main.MainActivity.tripsFragment 注入com.example.presenters.main.MainActivity dagger.android.AndroidInjector.inject(arg0中) 组件中存在与匹配键的绑定:com.example.di.FragmentBuilder_BindMainTripsFragment $ app_debug.MainTripsFragmentSubcomponent
我研究了3天,我读过很多文章,但我无法弄清楚问题出在哪里!
我会发布相关的代码,抱歉,如果它太长了
需要Fragment
的{{1}}:
PagerAdapter
BaseFragment:
class MainTripsFragment @Inject constructor() : BaseFragment() {
@Inject
lateinit var mainTripsFragmentAdapter: MainTripsFragmentAdapter
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
pager.adapter = mainTripsFragmentAdapter
}
}
以下是abstract class BaseFragment : DaggerFragment() {
override fun onAttach(context: Context?) {
AndroidSupportInjection.inject(this)
super.onAttach(context)
}
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? = inflater.inflate(getLayout(), container, false)
abstract fun getLayout(): Int
}
:
FragmentPagerAdapter
这是与DI相关的课程:
AppComponent:
class MainTripsFragmentAdapter @Inject constructor(
fragmentManager: FragmentManager,
private val mainCurrentTripsFragment: MainCurrentTripsFragment,
private val mainHistoryTripsFragment: MainHistoryTripsFragment
) : FragmentPagerAdapter(fragmentManager) {
override fun getItem(position: Int) = when (position) {
0 -> mainCurrentTripsFragment
1 -> mainHistoryTripsFragment
else -> mainCurrentTripsFragment
}
override fun getCount() = 2
}
FragmentBuilder:
@Singleton
@Component(modules = [
AndroidInjectionModule::class,
ActivityBuilder::class,
FragmentBuilder::class
])
interface AppComponent : AndroidInjector<DaggerApplication> {
fun inject(app: App)
override fun inject(instance: DaggerApplication)
@Component.Builder
interface Builder {
@BindsInstance
fun application(app: Application): Builder
fun build(): AppComponent
}
}
FragmentModule:
@Module
abstract class FragmentBuilder {
@ContributesAndroidInjector
internal abstract fun bindMainHomeFragment(): MainHomeFragment
@Module
internal interface MainTripsFragmentModule {
@Binds
fun bindMainTripsFragment(fragment: MainTripsFragment): Fragment
}
@ContributesAndroidInjector(modules = [FragmentModule::class, MainTripsFragmentModule::class])
internal abstract fun bindMainTripsFragment(): MainTripsFragment
@ContributesAndroidInjector
internal abstract fun bindMainCurrentTripsFragment(): MainCurrentTripsFragment
@ContributesAndroidInjector
internal abstract fun bindMainHistoryTripsFragment(): MainHistoryTripsFragment
}
ActivityBuilder:
@Module
class FragmentModule {
@Provides
fun provideFragmentManager(fragment: Fragment) = fragment.childFragmentManager
}
MainActivity:
@Module
abstract class ActivityBuilder {
@ContributesAndroidInjector
internal abstract fun contributeMainActivity(): MainActivity
}
BaseActivity:
class MainActivity : BaseActivity() {
@Inject
lateinit var tripsFragment: MainTripsFragment
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
showFragment(tripsFragment)
}
private fun showFragment(fragment: Fragment) {
supportFragmentManager
.beginTransaction()
.replace(R.id.layout_container, fragment)
.commit()
}
}
申请类:
@SuppressLint("Registered")
abstract class BaseActivity : AppCompatActivity(), HasSupportFragmentInjector {
@Inject
lateinit var fragmentInjector: DispatchingAndroidInjector<Fragment>
override fun onCreate(savedInstanceState: Bundle?) {
AndroidInjection.inject(this)
super.onCreate(savedInstanceState)
}
override fun supportFragmentInjector() = fragmentInjector
}
有一点是,如果我class App : Application(), HasActivityInjector {
@Inject
lateinit var activityInjector: DispatchingAndroidInjector<Activity>
override fun activityInjector(): AndroidInjector<Activity> = activityInjector
override fun onCreate() {
super.onCreate()
DaggerAppComponent.builder()
.application(this)
.build()
.apply {
inject(this@App)
}
}
}
PagerAdapter Inside My Activity(我也应该为它添加一个模块),它可以正常工作。
哪个部分是已实施错误?
答案 0 :(得分:2)
这里有很多问题:
class MainTripsFragmentAdapter @Inject constructor(
fragmentManager: FragmentManager,
private val mainCurrentTripsFragment: MainCurrentTripsFragment,
private val mainHistoryTripsFragment: MainHistoryTripsFragment
) : FragmentPagerAdapter(fragmentManager) {
override fun getItem(position: Int) = when (position) {
0 -> mainCurrentTripsFragment //no!!
1 -> mainHistoryTripsFragment
else -> mainCurrentTripsFragment
}
override fun getCount() = 2
}
getItem
中的 PagerAdapter
表示&#34;创建项目&#34;。当您使用PagerAdapter
将片段的创建委托给适配器时。你不应该编写代码来缓存和存储片段,这是FragmentManager
的工作。
相反,您的FragmentAdapter
应该是这样的:
override fun getItem(position: Int) = when (position) {
0 -> MainCurrentTripsFragment.instantiate()
1 -> MainHistoryTripsFragment.instantiate()
else -> MainCurrentTripsFragment.instantiate()
}
在Fragments中的伴随对象内声明instantiate
方法:
class MainCurrentTripsFragment: Fragment() {
companion object {
@JvmStatic
fun instantiate(args: Bundle?) {
val frag = MainCurrentTripsFragment()
frag.arguments = args
}
}
}
这是在Android中使用带有Fragments的PagerAdapter
的标准习惯用法。您不应该在对象图中提供PagerAdapters或Fragments作为依赖项。实际上,操作系统控制的许多Android类如FragmentManager
,Activity
,Fragment
,BroadcastReceiver
,Service
都不适合成为您对象中的依赖项使用Dagger 2的图表。
开始使用Dagger 2时常见的错误是尝试并注入所有内容,就像手动更新任何内容一样。这在Android中是不可能的。
请从模块中取出Fragments,FragmentManager,PagerAdapter等。不要尝试使用Dagger 2提供这些或绑定它们。然后使用Dagger 2注入域层或数据层对象,如存储库,Retrofit服务等。如果您遇到困难,您可以随时发布另一个问题。
看看官方Google Android Architecture blueprints。理想情况下,您的解决方案应该与它们类似。