【问题标题】:Inject Adapter class to Fragment using Dagger2使用 Dagger2 将适配器类注入片段
【发布时间】:2019-02-27 18:59:43
【问题描述】:

我已按照 Android Architecture Blueprints Dagger2 进行依赖注入:URL

现在我想将 Adapter 注入我的 Fragment 类:

@ActivityScoped
class MainFragment @Inject
constructor(): DaggerFragment(), ArtistClickCallback {

    @Inject lateinit var adapter : ArtistAdapter 
}

主模块类:

@Module
abstract class MainModule {
    @FragmentScoped
    @ContributesAndroidInjector(modules = [MainFragmentModule::class])
    internal abstract fun mainFragment(): MainFragment

    @Binds
    internal abstract fun bindArtistClickCallback(mainFragment: MainFragment) : ArtistClickCallback
}

MainFragmentModule:

@Module
class MainFragmentModule {

    @Provides
    fun provideArtistAdapter() = ArtistAdapter()
}

这是我的适配器类:

 class ArtistAdapter @Inject constructor(
  private val artistClickCallback : ArtistClickCallback
) : PagedListAdapter<LastFmArtist, RecyclerView.ViewHolder>(POST_COMPARATOR)

当我构建项目时,出现以下 Kotlin 编译器错误:

error: [Dagger/DependencyCycle] Found a dependency cycle:
public abstract interface AppComponent extends dagger.android.AndroidInjector<com.sample.android.lastfm.LastFmApp> {
                ^
      com.sample.android.lastfm.ui.main.MainFragment is injected at


com.sample.android.lastfm.ui.main.MainModule.bindArtistClickCallback$app_debug(mainFragment)
  com.sample.android.lastfm.ArtistClickCallback is injected at
      com.sample.android.lastfm.ui.main.ArtistAdapter.artistClickCallback
  com.sample.android.lastfm.ui.main.ArtistAdapter is injected at
      com.sample.android.lastfm.ui.main.MainFragment.adapter
  com.sample.android.lastfm.ui.main.MainFragment is injected at
      com.sample.android.lastfm.ui.main.MainActivity.mainFragment
  com.sample.android.lastfm.ui.main.MainActivity is injected at
      dagger.android.AndroidInjector.inject(T) [com.sample.android.lastfm.di.AppComponent → com.sample.android.lastfm.di.ActivityBindingModule_MainActivity$app_debug.MainActivitySubcomponent]

你能建议我如何解决这个问题吗?

代码可以在URL找到

【问题讨论】:

    标签: android dagger-2


    【解决方案1】:

    您的片段应该@ActivityScoped 作为范围。此外,不要对片段(或任何其他框架类型)使用构造函数注入!在某些情况下,Android 框架会创建这些对象,而您最终会在类中得到错误的引用。通过其构建器将片段添加到相应的组件中。

    您还使用提供注释的方法以及构造函数注入 (@Inject constructor())。选择一个。由于您还使用了字段注入 ArtistAdapter 中,您将遇到的下一个“错误”将是任何地方的null callback because you don't inject the adapter。您只需创建对象。
    构造函数注入通常应该受到青睐,它也会注入字段。把下面的完全删除,保留constructor上的注解:

    @Provides
    fun provideArtistAdapter() = ArtistAdapter()
    

    继续前进,您的错误源自MainActivitySubcomponent(最后一行),似乎是因为您的MainFragment 被绑定为ArtistClickCallback,但需要ArtistAdapter,这需要ArtistClickCallback...因此你的依赖周期。

    一旦你解决了上面提到的问题(在这种情况下是片段上的@Inject 构造函数),这个问题应该会自行解决,因为它起源于由 Dagger 在MainActivitySubcomponent 中构造的MainFragment,这是错误的无论如何放置,因为您的片段应该具有比活动更低的范围。

    您还需要将绑定 (@Binds fun bindArtistClickCallback) 移动到 MainFragmentModule,因为 Activity 组件中没有要绑定的片段(您当前添加绑定的位置)

    当您解决所有这些问题时,您会将片段绑定到正确的 FragmentSubcomponent,您将在其中将其绑定为回调,然后您可以使用它创建适配器并且它应该可以工作。

    我建议您更彻底地了解 Dagger,并确保了解指出的所有问题/修复。


    应该是这样的

    @FragmentScoped
    class MainFragment(): DaggerFragment(), ArtistClickCallback {
    
      @Inject lateinit var adapter : ArtistAdapter 
    }
    
    @Module
    abstract class MainModule {
      @FragmentScoped
      @ContributesAndroidInjector(modules = [MainFragmentModule::class])
      internal abstract fun mainFragment(): MainFragment
    }
    
    @Module
    class MainFragmentModule {
    
      @Binds
      internal abstract fun bindArtistClickCallback(mainFragment: MainFragment) : ArtistClickCallback
    }
    
    class ArtistAdapter @Inject constructor(
      private val artistClickCallback : ArtistClickCallback
    ) : PagedListAdapter<LastFmArtist, RecyclerView.ViewHolder>(POST_COMPARATOR)
    

    【讨论】:

    • 谢谢。我收到以下错误:MainFragment cannot be provided without an @Inject constructor or an @Provides-annotated method. This type supports members injection but cannot be implicitly provided.
    • MainFragmentModule 在这种情况下应该是抽象的,因为里面的方法也是抽象的。
    • 在谷歌示例中,他们使用了@ActivityScoped 以及注入构造函数:github.com/googlesamples/android-architecture/blob/…
    • @Ali 你是对的,看起来他们是这样的。似乎他们通过构造函数注入创建片段以在@ActivityScope aka Activity 中使用......但他们仍然有片段的子组件......最终会导致片段被注入两次(?)......一旦您在片段中添加任何 @FragmentScoped 依赖项,这似乎也会中断,因为更高的范围无法再提供它
    • 通过对片段使用注入的构造函数,我收到以下错误:ArtistClickCallback cannot be provided without an @Provides-annotated method.你能建议如何解决这个问题吗?
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-09-29
    • 2022-01-15
    • 1970-01-01
    相关资源
    最近更新 更多