Android Inject Dependency(Dagger 2)使用@ContributesAndroidInjector进行片段内部

时间:2018-06-10 06:37:37

标签: android dependency-injection kotlin dagger-2

我在项目中使用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(我也应该为它添加一个模块),它可以正常工作。
哪个部分是已实施错误?

1 个答案:

答案 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类如FragmentManagerActivityFragmentBroadcastReceiverService都不适合成为您对象中的依赖项使用Dagger 2的图表。

开始使用Dagger 2时常见的错误是尝试并注入所有内容,就像手动更新任何内容一样。这在Android中是不可能的。

请从模块中取出Fragments,FragmentManager,PagerAdapter等。不要尝试使用Dagger 2提供这些或绑定它们。然后使用Dagger 2注入域层或数据层对象,如存储库,Retrofit服务等。如果您遇到困难,您可以随时发布另一个问题。

看看官方Google Android Architecture blueprints。理想情况下,您的解决方案应该与它们类似。