如何使用Hilt注入NavController
我是新手。试图从匕首转换为刀柄。但是我坚持将navController
注入活动
。
因此,要创建navController
实例,我需要访问活动和主机片段ID。在匕首中,这是我创建该实例的方法。
创建activityModule
@Module
class ActivityModule {
@ActivityScope
@Provides
fun navigation(activity: MainActivity, hosFragment: Int) =
Navigation.findNavController(activity,hosFragment)
}
首先,在第二步中
@ActivityScope
@Subcomponent(modules = [ActivityModule::class])
interface ActivitySubComponent {
@Subcomponent.Factory
interface Factory{
fun create(@BindsInstance activity: MainActivity,
@BindsInstance hostFragment: Int): ActivitySubComponent
}
fun inject(MainActivity: MainActivity)
}
activitysubcomponent
具有参加活动并主机片段ID作为参数的能力。将此子组件与其他子组件添加到ApplicationComponent
中,您可以将您的实例获取navController
的实例。
class MainActivity : AppCompatActivity() {
@Inject
lateinit var navigationController: NavController
lateinit var viewBinding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(viewBinding.root)
injector.activityComponent().create(this, R.id.hostFragment).inject(this)
}
}
喷油器
来自以下类。
interface InjectorProvider {
val component: ApplicationComponent
}
val Activity.injector get() = (application as InjectorProvider).component
val Fragment.injector get() = (requireActivity().application as InjectorProvider).component
当我试图过渡到Hilt时,我遇到的第一个问题是如何向模块提供参数。不像在匕首中,我找不到子组件工厂的替代方法。甚至可以向刀柄上的模块提供参数吗?
无论如何,我决定将fragmentContainerview
ID提供给navController
,因为它没有更改。这样,我来到了下面的解决方案。
@Module
@InstallIn(ActivityComponent::class)
object NavigationModule {
@Provides
fun navigationController(activity: Activity) =
activity.findNavController(R.id.hostFragment)
}
并试图将其注入我的mainActvity
如下所示。
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject
lateinit var navigationController: NavController
lateinit var viewBinding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(viewBinding.root)
initialization()
}
private fun initialization() {
setSupportActionBar(viewBinding.toolbar)
NavigationUI.setupActionBarWithNavController(this, navigationController)
}
}
应用程序成功地构建了,但是现在我遇到了一个运行时间错误,说“ ID不用引用此活动中的视图”,但是我的活动布局的构建如下所示。
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/purple_700"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/hostFragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/main_navigation" />
</LinearLayout>
错误指向super.oncreate(Savedinstancestate)
在MainActivity
上。请让我知道我在这里想念什么。谢谢。
I'm new to Hilt. Trying to convert from Dagger to Hilt. But I'm stuck on injecting NavController
to the Activity
.
So to create NavController
instance I need to have access to the activity and the host fragment Id. In Dagger this was my approach to create that instance.
First, create ActivityModule
@Module
class ActivityModule {
@ActivityScope
@Provides
fun navigation(activity: MainActivity, hosFragment: Int) =
Navigation.findNavController(activity,hosFragment)
}
In the second step ActivitySubComponent
has the ability to take activity and host fragment id as parameters.
@ActivityScope
@Subcomponent(modules = [ActivityModule::class])
interface ActivitySubComponent {
@Subcomponent.Factory
interface Factory{
fun create(@BindsInstance activity: MainActivity,
@BindsInstance hostFragment: Int): ActivitySubComponent
}
fun inject(MainActivity: MainActivity)
}
After adding this subcomponent with other subcomponents to the ApplicationComponent
from you can get the instance of NavController
to the fragment like below.
class MainActivity : AppCompatActivity() {
@Inject
lateinit var navigationController: NavController
lateinit var viewBinding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(viewBinding.root)
injector.activityComponent().create(this, R.id.hostFragment).inject(this)
}
}
injector
coming from the following class.
interface InjectorProvider {
val component: ApplicationComponent
}
val Activity.injector get() = (application as InjectorProvider).component
val Fragment.injector get() = (requireActivity().application as InjectorProvider).component
When I was trying to transition into Hilt, the first issue I faced was how to provide parameters to the module. Not like in Dagger I could not find an alternative for Subcomponent Factory. Is it even possible to provide parameters to a module on Hilt?
Anyways, I decided to provide the FragmentContainerView
id to the NavController
manually since it's not changing. With that, I came to the below solution in Hilt.
@Module
@InstallIn(ActivityComponent::class)
object NavigationModule {
@Provides
fun navigationController(activity: Activity) =
activity.findNavController(R.id.hostFragment)
}
And tried to inject it into my MainActvity
like below.
@AndroidEntryPoint
class MainActivity : AppCompatActivity() {
@Inject
lateinit var navigationController: NavController
lateinit var viewBinding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewBinding = ActivityMainBinding.inflate(layoutInflater)
setContentView(viewBinding.root)
initialization()
}
private fun initialization() {
setSupportActionBar(viewBinding.toolbar)
NavigationUI.setupActionBarWithNavController(this, navigationController)
}
}
Application built successfully but now I'm getting a run time error saying "ID does not reference a View inside this Activity" but my activity layout is constructed like below.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@color/purple_700"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"
app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" />
<androidx.fragment.app.FragmentContainerView
android:id="@+id/hostFragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/main_navigation" />
</LinearLayout>
Error pointing at super.onCreate(savedInstanceState)
line on the MainActivity
. Please let me know what am I missing here. Thanks.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
我能够弄清楚。上述问题必须是由于在尝试注入
navController
实例时无法使用的UI引起的。因此,刀柄具有定义接口并将该接口注入活动中的方法。我们可以通过实现该接口来定义类。这使我们有机会提供在可用时构建实例所需的参数。首先,创建下面的接口。
其次,创建一个实现类。
之后,定义
navigationModule
如下所示。最后,您可以将该实例注入下面的活动。
I was able to figure it out. The above issue must be caused by the fact the UI is not available at the time it tries to inject the
NavController
instance. So Hilt has a way of defining an interface and Injecting that interface into the Activity. And we can define the classes by that implementing that interface. This gives us a chance to provide the parameters necessary to build our instance when they are available.First, create the interface like below.
Secondly, create an implementation class.
After that define
NavigationModule
like below.Finally, you can inject that instance to the activity like below.