android 导航将参数传递给片段构造函数
android navigation pass arguments to fragment constructor
我已经创建了导航抽屉Activity:
class MainActivity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val toolbar: Toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar)
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
val navView: NavigationView = findViewById(R.id.nav_view)
val navController = findNavController(R.id.nav_host_fragment)
appBarConfiguration = AppBarConfiguration(navController.graph, drawerLayout)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
}
我有 mobile_navigation.xml
:
<?xml version="1.0" encoding="utf-8"?>
<navigation 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:id="@+id/mobile_navigation"
app:startDestination="@id/databaseFragment">
<fragment
android:id="@+id/databaseFragment"
android:name="com.acmpo6ou.myaccounts.ui.DatabaseFragment"
android:label="fragment_database_list"
tools:layout="@layout/fragment_database_list" >
<action
android:id="@+id/actionCreateDatabase"
app:destination="@id/createDatabaseFragment" />
</fragment>
<fragment
android:id="@+id/createDatabaseFragment"
android:name="com.acmpo6ou.myaccounts.ui.CreateDatabaseFragment"
android:label="create_edit_database_fragment"
tools:layout="@layout/create_edit_database_fragment" />
</navigation>
起始目的地是DatabaseFragment
。但是有一个问题,这是我的 DatabaseFragment
:
class DatabaseFragment(
override val adapter: DatabasesAdapterInter,
val presenter: DatabasesPresenterInter
) : Fragment(), DatabaseFragmentInter {
...
companion object {
@JvmStatic
fun newInstance(
adapter: DatabasesAdapterInter,
presenter: DatabasesPresenterInter
) = DatabaseFragment(adapter, presenter)
}
}
如您所见,我的 DatabaseFragment
应该接收到其构造函数的两个参数:adapter
和 presenter
。这是因为依赖注入,在我的测试中我可以实例化 DatabaseFragment
通过模拟 adapter
和 presenter
。像这样:
...
val adapter = mock<DatabasesAdapterInter>()
val presenter = mock<DatabasesPresenterInter>()
val fragment = DatabaseFragment(adapter, presenter)
...
它适用于测试,但不适用于 android 导航。似乎 Android 导航组件创建了 DatabaseFragment
而不是我,但它们没有将任何参数传递给片段的构造函数并且它失败并因错误太长而无法在此处 post 它。
有没有办法告诉导航组件,以便它们在实例化它们时将适当的参数传递给我的片段?
谢谢!
简短的回答是否定的,您不能将参数传递给 Fragment
。
Fragment
的所有子class 必须包含一个public 无参数构造函数。框架通常会在需要时重新实例化一个片段 class ,特别是在状态恢复期间,并且需要能够找到这个构造函数来实例化它。如果无参构造函数不可用,在某些情况下会在状态恢复时出现运行时异常。
我只想添加到 i30mb1 答案:
你真的有必要在构造函数中传递这两个参数吗?
据我所知以及我对 MVP 的试验,每个视图都应该有一个演示者。因此,例如,当我创建一个新片段时,我会为它创建一个新的演示者。那么父 activity 应该有另一个演示者。如果您需要该演示者以便片段可以在活动视图中进行更改,您可以实现接口,但那是另一个话题。
如果您需要使用 POJOS 之类的导航或更简单的对象(例如字符串等)传递简单的参数。您可以使用 SafeArgs https://developer.android.com/guide/navigation/navigation-pass-data
我使用默认参数很容易地修复了所有问题,如下所示:
class DatabaseFragment(
override val adapter: DatabasesAdapterInter = DatabasesAdapter(),
val presenter: DatabasesPresenterInter = DatabasesPresenter()
) : Fragment(), DatabaseFragmentInter {
...
companion object {
@JvmStatic
fun newInstance() = DatabaseFragment()
}
}
我已经创建了导航抽屉Activity:
class MainActivity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val toolbar: Toolbar = findViewById(R.id.toolbar)
setSupportActionBar(toolbar)
val drawerLayout: DrawerLayout = findViewById(R.id.drawer_layout)
val navView: NavigationView = findViewById(R.id.nav_view)
val navController = findNavController(R.id.nav_host_fragment)
appBarConfiguration = AppBarConfiguration(navController.graph, drawerLayout)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
}
我有 mobile_navigation.xml
:
<?xml version="1.0" encoding="utf-8"?>
<navigation 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:id="@+id/mobile_navigation"
app:startDestination="@id/databaseFragment">
<fragment
android:id="@+id/databaseFragment"
android:name="com.acmpo6ou.myaccounts.ui.DatabaseFragment"
android:label="fragment_database_list"
tools:layout="@layout/fragment_database_list" >
<action
android:id="@+id/actionCreateDatabase"
app:destination="@id/createDatabaseFragment" />
</fragment>
<fragment
android:id="@+id/createDatabaseFragment"
android:name="com.acmpo6ou.myaccounts.ui.CreateDatabaseFragment"
android:label="create_edit_database_fragment"
tools:layout="@layout/create_edit_database_fragment" />
</navigation>
起始目的地是DatabaseFragment
。但是有一个问题,这是我的 DatabaseFragment
:
class DatabaseFragment(
override val adapter: DatabasesAdapterInter,
val presenter: DatabasesPresenterInter
) : Fragment(), DatabaseFragmentInter {
...
companion object {
@JvmStatic
fun newInstance(
adapter: DatabasesAdapterInter,
presenter: DatabasesPresenterInter
) = DatabaseFragment(adapter, presenter)
}
}
如您所见,我的 DatabaseFragment
应该接收到其构造函数的两个参数:adapter
和 presenter
。这是因为依赖注入,在我的测试中我可以实例化 DatabaseFragment
通过模拟 adapter
和 presenter
。像这样:
...
val adapter = mock<DatabasesAdapterInter>()
val presenter = mock<DatabasesPresenterInter>()
val fragment = DatabaseFragment(adapter, presenter)
...
它适用于测试,但不适用于 android 导航。似乎 Android 导航组件创建了 DatabaseFragment
而不是我,但它们没有将任何参数传递给片段的构造函数并且它失败并因错误太长而无法在此处 post 它。
有没有办法告诉导航组件,以便它们在实例化它们时将适当的参数传递给我的片段?
谢谢!
简短的回答是否定的,您不能将参数传递给 Fragment
。
Fragment
的所有子class 必须包含一个public 无参数构造函数。框架通常会在需要时重新实例化一个片段 class ,特别是在状态恢复期间,并且需要能够找到这个构造函数来实例化它。如果无参构造函数不可用,在某些情况下会在状态恢复时出现运行时异常。
我只想添加到 i30mb1 答案:
你真的有必要在构造函数中传递这两个参数吗?
据我所知以及我对 MVP 的试验,每个视图都应该有一个演示者。因此,例如,当我创建一个新片段时,我会为它创建一个新的演示者。那么父 activity 应该有另一个演示者。如果您需要该演示者以便片段可以在活动视图中进行更改,您可以实现接口,但那是另一个话题。
如果您需要使用 POJOS 之类的导航或更简单的对象(例如字符串等)传递简单的参数。您可以使用 SafeArgs https://developer.android.com/guide/navigation/navigation-pass-data
我使用默认参数很容易地修复了所有问题,如下所示:
class DatabaseFragment(
override val adapter: DatabasesAdapterInter = DatabasesAdapter(),
val presenter: DatabasesPresenterInter = DatabasesPresenter()
) : Fragment(), DatabaseFragmentInter {
...
companion object {
@JvmStatic
fun newInstance() = DatabaseFragment()
}
}