匕首提供的依赖项取决于活动的视图

时间:2018-09-19 16:42:35

标签: android dagger-2 android-architecture-components

我有一个带有导航抽屉的活动,其中包含很多片段。我使用架构组件中的导航库。在每个片段中,我必须写navController = Navigation.findNavController(activity!!, R.id.fragment_container)。我想摆脱这个样板代码。所以我决定用Dagger注入它。

@Module
class MainActivityModule {
    @ActivityScope
    @Provides
    fun provideNavController(activity: MainActivity): NavController {
        return Navigation.findNavController(activity, R.id.fragment_container)
    }
}

@Suppress("unused")
@Module
abstract class ActivityBuildersModule {
    @ActivityScope
    @ContributesAndroidInjector(
            modules = [MainActivityModule::class, MainActivityFragmentBuildersModule::class])
    abstract fun contributeMainActivity(): MainActivity
}

向片段中注入可以很好地工作,但是当我尝试向活动中注入应用程序时崩溃:

09-19 19:22:37.152 22342-22342/com.dmitrysimakov.gymlab
    E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.dmitrysimakov.gymlab, PID: 22342
java.lang.RuntimeException: Unable to start activity
    ComponentInfo{com.dmitrysimakov.gymlab/com.dmitrysimakov.gymlab.MainActivity}:
    java.lang.IllegalArgumentException: ID does not reference a View inside this Activity
    .....

所以我必须在活动中复制navController = Navigation.findNavController(activity!!, R.id.fragment_container)。有没有更优雅的方法可以做到这一点?

2 个答案:

答案 0 :(得分:1)

应用程序因活动而崩溃,因为调用provideNavController时您尚未使用setContentView设置内容视图

第1步:如果扩展DaggerAppCompatActivity复制其代码并扩展AppCompatActivity,则只需执行第2步。

步骤2:将AndroidInjection.inject(this)方法中的onCreate行移到setContentView(...)之后

但是请注意,这可能会导致诸如this之类的其他问题,因此,为了使您的nav控制器从您的活动中脱颖而出,最好的选择可能只是使用扩展名,如果您有一个内置扩展名在您的build.gradle中具有'android.arch.navigation:navigation-ui-ktx:1.0.0-alpha05'依赖项:

findNavController(R.id.fragment_container)

因此,对于您的活动,您可以使用此扩展名,并且无论如何,如果您使用建议的单个活动的方式,那么在大多数情况下,您将从片段中导航,在那里您仍然可以使用匕首注入

答案 1 :(得分:0)

对我来说,最好的解决方法是将片段插入onAttach中,并提供NavController

我认为接受的解决方案不太理想,因为将注射延迟到 setContentView很危险:在来回浏览该Fragment时,将再次调用setContentView以重新创建视图层次结构。 如果该片段需要观察ViewModels或存储库,则需要将其注入。因此,我们需要将观察ViewModel的时间推迟到setContentView为止,这可能最终导致Fragment观察具有多个订阅的ViewModel,这可能会导致错误。

实际上,建议在Fragments中插入onAttachhttps://dagger.dev/android#when-to-inject

DaggerActivity立即在以下位置调用AndroidInjection.inject() onCreate(),在调用super.onCreate()之前,DaggerFragment会执行 在onAttach()中也是如此。

我在https://stackoverflow.com/a/60061872/789110中回答了