Android 导航架构组件:如何将包数据传递到 startDestination
Android Navigation Architecture Component: How to pass bundle data to startDestination
我有一个 activity,它有一个 NavHostFragment
。 activity 在其意图中接收某些值。我想将此数据传递给导航图的第一个片段,即 startDestination
。我找不到与此相关的任何文档。
我已经完成了 ,但我似乎找不到 navController.getGraph()
的 addDefaultArguments
方法。
是否可以将捆绑包传递给 startDestination
?
我也找不到这个方法。它在体系结构组件文档中不存在。
但这是另一种将参数设置为起始目的地的方法:
// Kotlin Code, in Fragment
with(findNavController().graph) {
get(startDestination).addArgument(...)
}
我也遇到了同样的问题,
我是这样解决的:
- 从
your_activity.xml
中删除 NavHostFragment 的 xml 设置:即删除 app:navGraph="@navigation/nav_graph
这就是您的 XML 应该的样子。
<fragment
android:id="@+id/nav_host"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
/>
在 activity 的 onCreate()
中以编程方式为 NavHostFragment 添加 设置。
并使用 NavGraph.addDefaultArguments(bundleData)
api
传递包数据
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.editor_layout)
setupNavigation()
}
private fun setupNavigation() {
val navHostFragment = nav_host as NavHostFragment
val navController = navHostFragment.navController
val navInflater = navController.navInflater
val graph = navInflater.inflate(R.navigation.nav_graph)
graph.addDefaultArguments(intent!!.extras!!) // This is where you pass the bundle data from Activity to StartDestination
navHostFragment.navController.graph = graph
}
更新:
我的项目Gradle文件中的依赖项:
dependencies {
def nav_version = "1.0.0-alpha08"
implementation "android.arch.navigation:navigation-fragment:$nav_version" // use -ktx for Kotlin
implementation "android.arch.navigation:navigation-ui:$nav_version" // use -ktx for Kotlin}
}
注意: 在导航组件版本 1.0.0-alpha09
中由于某种原因 google 没有方法,因为 addDefaultArguments()
可能很快就会修复。但是较低版本的 addDefaultArguments()
method.I 已经在 java 和 kotlin 中进行了检查,所以请尝试使用 1.0.0-alpha07
或 1.0.0-alpha08
我检查了源代码,发现在导航目标和参数方面有很多变化。
我认为将参数传递给起始目的地的正确方法是使用 'addArgument' 方法,如下所示:
val argument1 = 1 //First value
val argument2 = "Value" //Second value
val navArgument1=NavArgument.Builder().setDefaultValue(argument1).build()
val navArgument2=NavArgument.Builder().setDefaultValue(argument2).build()
navController.getGraph().addArgument("Key1",navArgument1)
navController.getGraph().addArgument("Key2",navArgument2)
也许有更好的方法,但我没有找到。
class MainActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navHostFragment = container as NavHostFragment
val inflater = navHostFragment.navController.navInflater
val graph = inflater.inflate(R.navigation.main_nav)
var data : Data = intent.getParcelableExtra("DATA") as Data
var bundle : Bundle = Bundle()
bundle.putParcelable("DATA", data)
graph.addDefaultArguments(bundle)
graph.addDefaultArguments(intent!!.extras!!)
navHostFragment.navController.graph = graph
}
}
在Activity中添加上述代码,用于使用导航发送数据
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
var data = NavHostFragment.findNavController(this).graph.defaultArguments.getParcelable("DATA") as Booking
}
在fragment端添加以上代码
您可以像这样在图表中添加参数
<fragment
android:id="@+id/exampleFragment"
android:label="example_fragment"
android:name="com.example.yourapp.ui.ExampleFragment"
tools:layout="@layout/example_fragment">
<argument
android:name="exampleArgs"
app:argType="reference"
android:defaultValue="@string/example"/>
</fragment>
https://developer.android.com/guide/navigation/navigation-pass-data
导航 1.0.0
val navHostFragment = root_nav_host_fragment as NavHostFragment
val navController = navHostFragment.navController
val navInflater = navController.navInflater
val graph = navInflater.inflate(R.navigation.navigation)
val sectionId = intent.getIntExtra(KEY_SECTION_ID, -1)
val bundle = bundleOf(KEY_SECTION_ID to sectionId)
navHostFragment.navController.setGraph(graph, bundle)
回答我自己的问题,因为我在更新的导航文档中找到了正确的方法。
在写这个答案时,我正在使用 Navigation 2.2.0-alpha01
如果您想将一些数据作为参数直接从主机 activity 传递到起始目的地,您需要在主机 activity 的 onCreate() 方法中手动设置主机的导航图,如下图:
获取导航控制器:
val navController by lazy { findNavController(R.id.<your_nav_host_id>) }
然后在主机activity的onCreate()
val bundle = Bundle()
bundle.putString("some_argument", "some_value")
navController.setGraph(R.navigation.<you_nav_graph_xml>, bundle)
或者,如果您想将整个 intent extras 原样传递给 startDestination:
navController.setGraph(R.navigation.<you_nav_graph_xml>, intent.extras)
因为 intent.extras
只会 return 一个 Bundle
When you are setting the navGraph using setGraph() method, you should avoid setting the app:NavGraph attribute in
the NavHostFragment definition, because doing so results in inflating
and setting the navigation graph twice.
在您的 startDestination 片段中阅读这些参数时:
如果您使用的是 Safe Args Plugin(非常推荐),那么在您的片段中:
private val args by navArgs<DummyFragmentArgs>()
Safe Args 插件会通过将 Args 附加到您的片段名称来生成 Args class。例如,如果您的片段名为 DummyFragment
,那么 Safe Args 将生成一个名为 DummyFragmentArgs
的 class
其中 navArgs<>
是 Android KTX
中定义的扩展函数
如果您不使用 Android KTX,您可以像这样获取 args 对象:
val args = DummyFragmentArgs.fromBundle(arguments!!)
获取参数对象后,您可以简单地获取参数:
args.someArgument
注意我们是如何将 "some_argument"
作为参数传递的,我们正在使用 Safe Args
将其读取为 someArgument
如果您没有使用 Safe Args(尽管没有理由不使用它),您可以像这样访问您的参数:
arguments?.getString("some_argument")
所有这些都记录在此处的“迁移到导航组件”文档中:
https://developer.android.com/guide/navigation/navigation-migrate#pass_activity_destination_args_to_a_start_destination_fragment
经过一番研究,我找到了解决方案。它适用于最新的导航库版本。参考以下代码:
将此添加到您的 activity 布局中。注意:我们没有在 xml 文件中设置 app:navGraph 参数。我们会动态设置。
<fragment
android:id="@+id/fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
app:defaultNavHost="true" />
在您的 activity java 文件中,编写以下代码并进行相应的更改。使用 NavArgument 传递参数值并将参数添加到自定义 Navgraph,然后设置图形。
public class YourActivity extends AppCompatActivity {
private NavArgument nameArg, mailArg;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.profile);
nameArg = new NavArgument.Builder().setDefaultValue("your name").build();
mailArg = new NavArgument.Builder().setDefaultValue("your email id").build();
NavController navController = Navigation.findNavController(this, R.id.fragment);
NavInflater navInflater = navController.getNavInflater();
NavGraph navGraph = navInflater.inflate(R.navigation.nav_profile_graph);
navGraph.addArgument("your name key", nameArg);
navGraph.addArgument("your mail key", mailArg);
navController.setGraph(navGraph);
}
}
编写下面的导航图并将相同的参数键添加到起始片段。
<?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/nav_graph"
app:startDestination="@+id/profile_basic">
<fragment
android:id="@+id/profile_basic"
android:name="com.yourpackage.ProfileBasicFragment"
android:label="Profile Basic"
tools:layout="@layout/fragment_profile_basic">
<argument android:name="your name key"
app:argType="string"/>
<argument android:name="your mail key"
app:argType="string"/>
</fragment>
</navigation>
在您的片段中,只需使用 getArguments() 函数获取值。
String name = getArguments().getString("your name key");
String mail = getArguments().getString("your mail key");
虽然这是一个迟到的答案,但有一种使用导航传递捆绑包的非常简单的方法controller/Navigation架构:
将发送数据的片段
//Best to put in onViewCreated
val navController = findNavController()
//Put in code where you want to start navigation
val b = Bundle()
b.putString("key_1", "Data 1")
b.putString("key_2", "Data 2")
navController.navigate(R.id.action_signupFragment_to_signinFragment,b)
将接收数据的片段
val data_1: String = arguments?.getString("key_1")?:""
val data_1: String = arguments?.getString("key_2")?:""
根据您发送的数据类型,您需要更新安全调用或使变量可为空。
我有一个 activity,它有一个 NavHostFragment
。 activity 在其意图中接收某些值。我想将此数据传递给导航图的第一个片段,即 startDestination
。我找不到与此相关的任何文档。
我已经完成了 navController.getGraph()
的 addDefaultArguments
方法。
是否可以将捆绑包传递给 startDestination
?
我也找不到这个方法。它在体系结构组件文档中不存在。
但这是另一种将参数设置为起始目的地的方法:
// Kotlin Code, in Fragment
with(findNavController().graph) {
get(startDestination).addArgument(...)
}
我也遇到了同样的问题,
我是这样解决的:
- 从
your_activity.xml
中删除 NavHostFragment 的 xml 设置:即删除 app:navGraph="@navigation/nav_graph
这就是您的 XML 应该的样子。
<fragment
android:id="@+id/nav_host"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
/>
在 activity 的
传递包数据onCreate()
中以编程方式为 NavHostFragment 添加 设置。 并使用NavGraph.addDefaultArguments(bundleData)
apioverride fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.editor_layout) setupNavigation() } private fun setupNavigation() { val navHostFragment = nav_host as NavHostFragment val navController = navHostFragment.navController val navInflater = navController.navInflater val graph = navInflater.inflate(R.navigation.nav_graph) graph.addDefaultArguments(intent!!.extras!!) // This is where you pass the bundle data from Activity to StartDestination navHostFragment.navController.graph = graph }
更新:
我的项目Gradle文件中的依赖项:
dependencies {
def nav_version = "1.0.0-alpha08"
implementation "android.arch.navigation:navigation-fragment:$nav_version" // use -ktx for Kotlin
implementation "android.arch.navigation:navigation-ui:$nav_version" // use -ktx for Kotlin}
}
注意: 在导航组件版本 1.0.0-alpha09
中由于某种原因 google 没有方法,因为 addDefaultArguments()
可能很快就会修复。但是较低版本的 addDefaultArguments()
method.I 已经在 java 和 kotlin 中进行了检查,所以请尝试使用 1.0.0-alpha07
或 1.0.0-alpha08
我检查了源代码,发现在导航目标和参数方面有很多变化。 我认为将参数传递给起始目的地的正确方法是使用 'addArgument' 方法,如下所示:
val argument1 = 1 //First value
val argument2 = "Value" //Second value
val navArgument1=NavArgument.Builder().setDefaultValue(argument1).build()
val navArgument2=NavArgument.Builder().setDefaultValue(argument2).build()
navController.getGraph().addArgument("Key1",navArgument1)
navController.getGraph().addArgument("Key2",navArgument2)
也许有更好的方法,但我没有找到。
class MainActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val navHostFragment = container as NavHostFragment
val inflater = navHostFragment.navController.navInflater
val graph = inflater.inflate(R.navigation.main_nav)
var data : Data = intent.getParcelableExtra("DATA") as Data
var bundle : Bundle = Bundle()
bundle.putParcelable("DATA", data)
graph.addDefaultArguments(bundle)
graph.addDefaultArguments(intent!!.extras!!)
navHostFragment.navController.graph = graph
}
}
在Activity中添加上述代码,用于使用导航发送数据
override fun onActivityCreated(savedInstanceState: Bundle?) {
super.onActivityCreated(savedInstanceState)
var data = NavHostFragment.findNavController(this).graph.defaultArguments.getParcelable("DATA") as Booking
}
在fragment端添加以上代码
您可以像这样在图表中添加参数
<fragment
android:id="@+id/exampleFragment"
android:label="example_fragment"
android:name="com.example.yourapp.ui.ExampleFragment"
tools:layout="@layout/example_fragment">
<argument
android:name="exampleArgs"
app:argType="reference"
android:defaultValue="@string/example"/>
</fragment>
https://developer.android.com/guide/navigation/navigation-pass-data
导航 1.0.0
val navHostFragment = root_nav_host_fragment as NavHostFragment
val navController = navHostFragment.navController
val navInflater = navController.navInflater
val graph = navInflater.inflate(R.navigation.navigation)
val sectionId = intent.getIntExtra(KEY_SECTION_ID, -1)
val bundle = bundleOf(KEY_SECTION_ID to sectionId)
navHostFragment.navController.setGraph(graph, bundle)
回答我自己的问题,因为我在更新的导航文档中找到了正确的方法。
在写这个答案时,我正在使用 Navigation 2.2.0-alpha01
如果您想将一些数据作为参数直接从主机 activity 传递到起始目的地,您需要在主机 activity 的 onCreate() 方法中手动设置主机的导航图,如下图:
获取导航控制器:
val navController by lazy { findNavController(R.id.<your_nav_host_id>) }
然后在主机activity的onCreate()
val bundle = Bundle()
bundle.putString("some_argument", "some_value")
navController.setGraph(R.navigation.<you_nav_graph_xml>, bundle)
或者,如果您想将整个 intent extras 原样传递给 startDestination:
navController.setGraph(R.navigation.<you_nav_graph_xml>, intent.extras)
因为 intent.extras
只会 return 一个 Bundle
When you are setting the navGraph using setGraph() method, you should avoid setting the app:NavGraph attribute in the NavHostFragment definition, because doing so results in inflating and setting the navigation graph twice.
在您的 startDestination 片段中阅读这些参数时:
如果您使用的是 Safe Args Plugin(非常推荐),那么在您的片段中:
private val args by navArgs<DummyFragmentArgs>()
Safe Args 插件会通过将 Args 附加到您的片段名称来生成 Args class。例如,如果您的片段名为 DummyFragment
,那么 Safe Args 将生成一个名为 DummyFragmentArgs
其中 navArgs<>
是 Android KTX
如果您不使用 Android KTX,您可以像这样获取 args 对象:
val args = DummyFragmentArgs.fromBundle(arguments!!)
获取参数对象后,您可以简单地获取参数:
args.someArgument
注意我们是如何将 "some_argument"
作为参数传递的,我们正在使用 Safe Args
someArgument
如果您没有使用 Safe Args(尽管没有理由不使用它),您可以像这样访问您的参数:
arguments?.getString("some_argument")
所有这些都记录在此处的“迁移到导航组件”文档中: https://developer.android.com/guide/navigation/navigation-migrate#pass_activity_destination_args_to_a_start_destination_fragment
经过一番研究,我找到了解决方案。它适用于最新的导航库版本。参考以下代码:
将此添加到您的 activity 布局中。注意:我们没有在 xml 文件中设置 app:navGraph 参数。我们会动态设置。
<fragment android:id="@+id/fragment" android:name="androidx.navigation.fragment.NavHostFragment" android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1" app:defaultNavHost="true" />
在您的 activity java 文件中,编写以下代码并进行相应的更改。使用 NavArgument 传递参数值并将参数添加到自定义 Navgraph,然后设置图形。
public class YourActivity extends AppCompatActivity { private NavArgument nameArg, mailArg; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.profile); nameArg = new NavArgument.Builder().setDefaultValue("your name").build(); mailArg = new NavArgument.Builder().setDefaultValue("your email id").build(); NavController navController = Navigation.findNavController(this, R.id.fragment); NavInflater navInflater = navController.getNavInflater(); NavGraph navGraph = navInflater.inflate(R.navigation.nav_profile_graph); navGraph.addArgument("your name key", nameArg); navGraph.addArgument("your mail key", mailArg); navController.setGraph(navGraph); } }
编写下面的导航图并将相同的参数键添加到起始片段。
<?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/nav_graph" app:startDestination="@+id/profile_basic"> <fragment android:id="@+id/profile_basic" android:name="com.yourpackage.ProfileBasicFragment" android:label="Profile Basic" tools:layout="@layout/fragment_profile_basic"> <argument android:name="your name key" app:argType="string"/> <argument android:name="your mail key" app:argType="string"/> </fragment> </navigation>
在您的片段中,只需使用 getArguments() 函数获取值。
String name = getArguments().getString("your name key"); String mail = getArguments().getString("your mail key");
虽然这是一个迟到的答案,但有一种使用导航传递捆绑包的非常简单的方法controller/Navigation架构:
将发送数据的片段
//Best to put in onViewCreated
val navController = findNavController()
//Put in code where you want to start navigation
val b = Bundle()
b.putString("key_1", "Data 1")
b.putString("key_2", "Data 2")
navController.navigate(R.id.action_signupFragment_to_signinFragment,b)
将接收数据的片段
val data_1: String = arguments?.getString("key_1")?:""
val data_1: String = arguments?.getString("key_2")?:""
根据您发送的数据类型,您需要更新安全调用或使变量可为空。