导航体系结构组件 - 将参数数据传递到起始目标



我有一个活动 A 启动活动 B,它向它传递了一些意图数据。活动 B 托管来自新导航体系结构组件的导航图。我想将该意图数据作为参数传递给 startDestination 片段,该怎么做?

好的,多亏了谷歌团队的伊恩·莱克,我找到了解决这个问题的方法。 假设您有一个活动 A,它将使用一些意图数据启动活动 B,并且您希望在 startDestination 中获取该数据,如果您使用安全参数,您在这里有两个选择,这是我的情况,您可以这样做

StartFragmentArgs.fromBundle(requireActivity().intent?.extras)

以从意图中读取参数。如果您不使用安全参数,则可以从自用requireActivity().intent?.extras的捆绑包中提取数据,这将返回您可以使用的捆绑包,而不是片段getArguments()方法。就是这样,我尝试了一下,一切正常。

我认为这在 1.0.0 版本中再次发生了变化。谷歌在官方文档中很好地隐藏了这些信息。或者至少我很难找到它,但在迁移到导航组件指南中偶然发现了它。如何将参数传递到起始目标如下所述:将活动目标参数传递到开始目标片段

总之

  1. 您必须以编程方式设置导航图:
findNavController(R.id.main_content)
.setGraph(R.navigation.product_detail_graph, intent.extras)
  1. 不要在 NavHostFragment XML 声明中设置图形。
  2. 阅读接收器端的附加内容:
val args by navArgs<ProductDetailsArgs>()  
val productId = args.productId

更新:谷歌表示,确实缺少将参数传递给初始导航目标的官方文档。希望它能尽快作为导航组件文档的一部分添加。

TLDR:您必须手动膨胀图形,将键/值添加到默认Args,并在navController上设置图形。

步骤 1

文档告诉您在Activity布局的<fragment>标签中设置图形。像这样:

<fragment
android:id="@+id/navFragment"
android:name="androidx.navigation.fragment.NavHostFragment"
app:graph="@navigation/nav_whatever"
app:defaultNavHost="true"
/>

删除设置graph=的行。

步骤 2

在将显示您的NavHostFragment的活动 中,像这样膨胀图形:

val navHostFragment = navFragment as NavHostFragment
val inflater = navHostFragment.navController.navInflater
val graph = inflater.inflate(R.navigation.nav_whatever)

其中navFragment是您在 XML 中为片段提供的 id,如上所述。

第 3 步 [至关重要!

创建一个捆绑包来保存要传递给startDestination片段的参数,并将其添加到图形的默认参数中:

val bundle = Bundle()
// ...add keys and values
graph.addDefaultArguments(bundle)

步骤 4

在主机的navController上设置图形:

navHostFragment.navController.graph = graph

它已在1.0.0-alpha07中修复。查看详细信息。

该解决方案类似于Elliot Schrock的答案,但由官方API包装。

我们必须手动给NavHostFragment充气或graph

NavHostFragment.create(R.navigation.graph, args)

navController.setGraph(R.navigation.graph, args)

参数是我们想要传递给起始目的地的数据。

以下 将数据从官方文档传递到起始目标部分:

首先,构造一个保存数据的捆绑包:

val bundle = Bundle().apply {
putString(KEY, "value")
}

接下来,使用以下方法之一将捆绑包传递到起始目标:

  • 如果要以编程方式创建导航主机

    NavHostFragment.create(R.navigation.graph, bundle)
    
  • 否则,您可以通过调用以下重载之一来设置开始目标参数NavController.setGraph()

    navHostFragment.navController.setGraph(R.navigation.graph, bundle)
    

然后,应使用Fragment.getArguments()检索起始目标中的数据。

编辑:

您也可以使用FragmentArgs而不是手动创建捆绑包,这使其更方便且类型安全:

navHostFragment.navController.setGraph(R.navigation.graph, MyFragmentArgs(arg).toBundle())

然后在片段中,您可以按以下方式检索参数:

private val args: PodFragmentArgs by navArgs()

确保您的片段在导航.xml文件中具有参数元素:

<fragment
android:id="@+id/myFragment"
android:name="MyFragment"
android:label="fragment_my"
tools:layout="@layout/fragment_my">
<argument
android:name="argName"
android:defaultValue="@null"
app:argType="string"
app:nullable="true" />
</fragment>

所以最后,我找到了解决这个问题的方法。

在撰写此答案时,我正在使用Navigation 2.2.0-alpha01

如果要将一些数据作为来自主机活动的参数直接传递到起始目标,则需要在主机活动的 onCreate() 方法中手动设置主机的导航图,如下所示:

获取导航控制器:

val navController by lazy { findNavController(R.id.<your_nav_host_id>) }

然后在主机活动的onCreate()

val bundle = Bundle()
bundle.putString("some_argument", "some_value")
navController.setGraph(R.navigation.<you_nav_graph_xml>, bundle)

或者,如果您想将整个意图附加内容按原样传递到 startDestination:

navController.setGraph(R.navigation.<you_nav_graph_xml>, intent.extras)

由于intent.extras只会返回Bundle

使用 setGraph() 方法设置 navGraph 时,应避免在 NavHostFragment 定义,因为这样做会导致膨胀 并设置导航图两次。

在 startDestination 片段中读取这些参数时:

如果您使用的是安全 Args 插件(非常推荐),那么在您的片段中:

private val args by navArgs<DummyFragmentArgs>()

安全 Args 插件将通过将 Args 附加到您的片段名称来生成 Args 类。例如,如果片段被调用DummyFragment则 Safe Args 将生成一个名为DummyFragmentArgs的类

其中navArgs<>是安卓 KTX 中定义的扩展函数

如果你没有使用Android KTX,你可以得到args对象,如下所示:

val args = DummyFragmentArgs.fromBundle(arguments!!)

获取参数对象后,您可以简单地获取参数:

args.someArgument

请注意我们如何将"some_argument"作为参数传递,并且我们正在使用安全参数将其someArgument读取

如果您没有使用Safe Args(但没有理由不使用它),则可以像这样访问您的参数:

arguments?.getString("some_argument")

所有这些都记录在迁移到导航组件文档中: https://developer.android.com/guide/navigation/navigation-migrate#pass_activity_destination_args_to_a_start_destination_fragment

addDefaultArguments不再出现在最新版本的库中。我已经解决了这样的问题:

val navHostFragment = fragment_navigation_onboarding as NavHostFragment
val navController = navHostFragment.navController
val navInflater = navController.navInflater
val graph:NavGraph = navInflater.inflate(R.navigation.navigation_your_xml)
val model = Model()//you might get it from another activity
graph.addArgument("Data", NavArgument.Builder().setDefaultValue(model).build()) // This is where you pass the bundle data from Activity to StartDestination
navHostFragment.navController.graph = graph

阅读解决方案后,我制作了一个适合我需求的解决方案, 此解决方案假定数据发送到托管此图的活动

在起始目的地:

@Override
public void onAttach(Context context) {
super.onAttach(context);
// work around get get starting destination with activity bundle
userId = getActivity().getIntent().getIntExtra(KEY_USER_ID, -1);
}

所以对于仍在为此苦苦挣扎的人们。我找到了另一种不使用 Safe-Args 的方法,并使用 @Elliot 的答案的步骤。

因此,假设您在活动 B 中从活动 A 收到了一些参数,并且您的活动 B 有一个片段 startDestination 您正在初始化 Nav 控制器,如下所示:

navController = Navigation.findNavController(this, R.id.detailFragment);

从导航控制器中,您将可以访问您在XML中设置的图形,如下所示,并且可以在defaultArguments中设置参数:

navController.getGraph().addDefaultArguments(extras);

注意:如果图形 xml 中已经存在键的值,这也将更新键的值

现在在你的片段中,你必须从你的 NavHostFragment 中找到默认参数,如下所示:

Bundle defaultArguments = NavHostFragment.findNavController(this).getGraph().getDefaultArguments();

你会在那里有值。我不知道为什么@Elliot认为这是至关重要的,但它应该是这样吗?

更新 alpha09:addDefault 参数在此版本中不再受支持,您必须使用 NavArgument

您可以将数据传递到应用的起始目标。首先,您必须显式构造一个保存数据的捆绑包。接下来,使用以下方法之一将捆绑包传递到起始目标 您可以从代码中设置手动图形并添加参数,并从 XML 中删除app:navGraph并在活动中使用此代码行

navController.setGraph(R.navigation.graph, args)

我使用了艾略特·施洛克的答案,但以不同的方法添加了捆绑包

navController.setGraph(R.navigation.nav_graph, intent.extras!!)
class HadithActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_hadith)
val navHostFragment =
supportFragmentManager.findFragmentById(R.id.fragmentContainerView) as NavHostFragment
val navController = navHostFragment.navController
navController.setGraph(R.navigation.nav_hadith, intent.extras)
}
}

activity_hadith.xml

<androidx.fragment.app.FragmentContainerView
android:id="@+id/fragmentContainerView"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:navGraph="@navigation/nav_hadith" />

相关内容

  • 没有找到相关文章

最新更新