activity 目的地

在导航图中,目的地可以是 activity。虽然最佳实践是在应用中使用单个 activity,但应用通常会为应用内的不同组件或屏幕使用不同的 activity。在这种情况下,activity 目的地会很有用。

Compose 和 Kotlin DSL

在 Compose 中以及将 Kotlin DSL 与 fragment 一起使用时,向导航图添加 activity 目的地的方法基本相同。这是因为,将 NavGraph 传递给 NavHost 可组合项时,您使用的是相同的 createGraph() lambda。

如需了解详情,请参阅使用 Kotlin DSL 程序化地构建图表

XML

创建 activity 目的地与创建 fragment 目的地类似。不过,activity 目的地的性质截然不同。

默认情况下,Navigation 库会将 NavController 附加到 Activity 布局,并且处于活动状态的导航图的作用域限定为处于活动状态的 Activity。如果用户导航到其他 Activity,则当前导航图不再位于作用域内。这意味着,Activity 目的地应被视为导航图中的端点。

如需添加 activity 目的地,请使用其完全限定的类名称指定目的地 Activity

<?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"
    android:id="@+id/navigation_graph"
    app:startDestination="@id/simpleFragment">

    <activity
        android:id="@+id/sampleActivityDestination"
        android:name="com.example.android.navigation.activity.DestinationActivity"
        android:label="@string/sampleActivityTitle" />
</navigation>

此 XML 相当于以下对 startActivity() 的调用:

Kotlin

startActivity(Intent(context, DestinationActivity::class.java))

Java

startActivity(new Intent(context, DestinationActivity.class));

在某些情况下,您可能会发现此方法不适合。例如,您可能对 activity 类没有编译时依赖项,或者您可能更希望执行隐式 intent 的间接级别。目的地 Activity 的清单条目中的 intent-filter 规定了您需要如何构建 Activity 目的地。

例如,请考虑使用以下清单文件:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.android.navigation.activity">
    <application>
        <activity android:name=".DestinationActivity">
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <data
                    android:host="example.com"
                    android:scheme="https" />
                <category android:name="android.intent.category.BROWSABLE" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>
</manifest>

您需要使用与清单条目中的属性相匹配的 actiondata 属性来配置相应的 Activity 目的地:

<?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"
    android:id="@+id/navigation_graph"
    app:startDestination="@id/simpleFragment">
    <activity
        android:id="@+id/localDestinationActivity"
        android:label="@string/localActivityTitle"
        app:action="android.intent.action.VIEW"
        app:data="https://example.com"
        app:targetPackage="${applicationId}" />
</navigation>

为当前 applicationId 指定 targetPackage 会将范围限制为包含主应用的当前应用。

如果您希望将特定应用作为目的地,也可以使用同一机制。以下示例将目的地定义为 applicationIdcom.example.android.another.app 的应用。

<?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"
    android:id="@+id/navigation_graph"
    app:startDestination="@id/simpleFragment">
    <activity
        android:id="@+id/localDestinationActivity"
        android:label="@string/localActivityTitle"
        app:action="android.intent.action.VIEW"
        app:data="https://example.com"
        app:targetPackage="com.example.android.another.app" />
</navigation>

动态参数

前面的示例使用固定网址来导航到目的地。您可能还需要支持动态网址,在动态网址中,系统会将其他信息作为网址的一部分发送。例如,您可以在格式类似于 https://example.com?userId=<actual user ID> 的网址中发送用户 ID。

在这种情况下,请使用 dataPattern,而不是 data 属性。然后,您可以为 dataPattern 值中的具名占位符提供要被替代的参数:

<?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"
    android:id="@+id/navigation_graph"
    app:startDestination="@id/simpleFragment">
    <activity
        android:id="@+id/localDestinationActivity"
        android:label="@string/localActivityTitle"
        app:action="android.intent.action.VIEW"
        app:dataPattern="https://example.com?userId={userId}"
        app:targetPackage="com.example.android.another.app">
        <argument
            android:name="userId"
            app:argType="string" />
    </activity>
</navigation>

在以下示例中,您可以使用 Safe ArgsBundle 指定 userId 值:

Kotlin

navController.navigate(
    R.id.localDestinationActivity,
    bundleOf("userId" to "someUser")
)

Java

Bundle args = new Bundle();
args.putString("userId", "someUser");
navController.navigate(R.id.localDestinationActivity, args);

此示例用 someUser 替换了 {userId},创建了一个 URI 值 https://example.com?userId=someUser