我有一个带有导航抽屉的活动,其中包含很多片段。我使用架构组件中的导航库。在每个片段中,我必须写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)
。有没有更优雅的方法可以做到这一点?
答案 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
中插入onAttach
:https://dagger.dev/android#when-to-inject
DaggerActivity立即在以下位置调用AndroidInjection.inject() onCreate(),在调用super.onCreate()之前,DaggerFragment会执行 在onAttach()中也是如此。