適切な Back ナビゲーションの提供

Back ボタンによるナビゲーションは、ユーザーが以前アクセスした画面の履歴をさかのぼって順番に移動する方法です。すべての Android デバイスに、このタイプのナビゲーションに使用する Back ボタンが用意されているため、アプリの UI には Back ボタンを追加しないでください

ほとんどの場合、ユーザーがアプリを操作している間はアクティビティのバックスタックがシステムに保持されるため、ユーザーが Back ボタンを選択すると、システムはナビゲーションを正しくさかのぼることができます。ただし、ユーザーの操作性を最適にするためにアプリ側で Back ボタンの動作を手動で指定することが必要になるケースもあります。

Back ボタンと Up ボタンを使用したナビゲーションタスクとバックスタックAndroid の設計: ナビゲーションもご覧ください。

Back の動作を手動で指定する必要があるナビゲーション パターンの例:

次に、上記の状況で Back ボタンによる適切なナビゲーションを実装する方法について説明します。

ディープリンク用の新しいバックスタックを合成する

通常、ユーザーがあるアクティビティから次のアクティビティに移動するたびに、バックスタックは増えていきます。ただし、ユーザーがディープリンクを使ってアプリに入り、アプリのタスクでそのアクティビティが最初のアクティビティになる場合、そのアクティビティはバックスタックがまったくない新しいタスクで実行されることになるため、新しいバックスタックを合成することが必要になります。

たとえば、通知によってユーザーをアプリ階層の深い場所にあるアクティビティに誘導する場合は、タスクのバックスタックにアクティビティを追加し、ユーザーが Back を選択したときにアプリを終了するのではなくアプリ階層の上に移動できるようにする必要があります。このパターンについて詳しくは、ナビゲーションの設計ガイドをご覧ください。

マニフェストで親アクティビティを指定する

Android 4.1(API レベル 16)以降では、<activity> 要素で android:parentActivityName 属性を指定することで各アクティビティの論理的な親を宣言できます。この情報をもとにシステムは論理的な Back ボタンや UP ボタンの論理的なナビゲーション パスを判断できるため、ナビゲーション パターンがわかりやすくなります。

アプリが Android 4.0 以下に対応している場合は、アプリに Support Library を含め、<activity> の内側に <meta-data> 要素を追加します。次に、android:parentActivityName 属性と一致するように、親アクティビティを android.support.PARENT_ACTIVITY の値として指定します。

例:

<application ... >
    ...
    <!-- The main/home activity (it has no parent activity) -->
    <activity
        android:name="com.example.myfirstapp.MainActivity" ...>
        ...
    </activity>
    <!-- A child of the main activity -->
    <activity
        android:name="com.example.myfirstapp.DisplayMessageActivity"
        android:label="@string/title_activity_display_message"
        android:parentActivityName="com.example.myfirstapp.MainActivity" >
        <!-- The meta-data element is needed for versions lower than 4.1 -->
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.example.myfirstapp.MainActivity" />
    </activity>
</application>

親アクティビティをこのように宣言しておくと、どのアクティビティが各アクティビティの適切な親であるかを識別することで、NavUtils API を使用して新しいバックスタックを合成できます。

アクティビティの開始時にバックスタックを作成する

ユーザーをアプリに誘導させるイベントが発生すると、バックスタックへのアクティビティの追加が開始されます。つまり、startActivity() を呼び出すのではなく、TaskStackBuilder API を使用して、新しいバックスタックに入れる必要がある各アクティビティを定義します。その後、startActivities() を呼び出してターゲット アクティビティを開始するか、getPendingIntent() を呼び出して適切な PendingIntent を作成します。

たとえば、通知によってユーザーをアプリ階層の深い場所にあるアクティビティに誘導する場合は、次のコードで、アクティビティを開始してターゲット タスクに新しいバックスタックを挿入する PendingIntent を作成できます。

Kotlin

val detailsIntent = Intent(this, DetailsActivity::class.java)

val pendingIntent: PendingIntent? = TaskStackBuilder.create(this)
        // add all of DetailsActivity's parents to the stack,
        // followed by DetailsActivity itself
        .addNextIntentWithParentStack(detailsIntent)
        .getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT)

val builder = NotificationCompat.Builder(this)
        .setContentIntent(pendingIntent)
...

Java

// Intent for the activity to open when user selects the notification
Intent detailsIntent = new Intent(this, DetailsActivity.class);

// Use TaskStackBuilder to build the back stack and get the PendingIntent
PendingIntent pendingIntent =
        TaskStackBuilder.create(this)
                        // add all of DetailsActivity's parents to the stack,
                        // followed by DetailsActivity itself
                        .addNextIntentWithParentStack(detailsIntent)
                        .getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);

NotificationCompat.Builder builder = new NotificationCompat.Builder(this);
builder.setContentIntent(pendingIntent);
...

このコードで作成される PendingIntent は、開始するアクティビティ(detailsIntent で定義)だけではなく、タスクに挿入するバックスタック(DetailsActivity のすべての親を detailsIntent で定義)も指定します。そのため、DetailsActivity が開始した場合、Back ボタンを押すと、DetailsActivity クラスの各親アクティビティを順番にさかのぼって移動することになります。

注: addNextIntentWithParentStack() メソッドを動作させるには、上記のように、android:parentActivityName 属性(および対応する <meta-data> 要素)を使用して、マニフェスト ファイルで各アクティビティの論理的な親を宣言する必要があります。

フラグメントの Back ナビゲーションを実装する

アプリでフラグメントを使用している場合は、個々の FragmentTransaction オブジェクトで、バックスタックに追加するコンテキストの変更を表すことができます。たとえば、フラグメントを切り替えてハンドセットに master/detail フローを実装する場合は、詳細画面で Back ボタンを選択するとマスター画面に戻るように設定する必要があります。この操作を設定するには、トランザクションをコミットする前に addToBackStack() を呼び出します。

Kotlin

// Works with either the framework FragmentManager or the
// support package FragmentManager (supportFragmentManager).
supportFragmentManager.beginTransaction()
        .add(detailFragment, "detail")
        // Add this transaction to the back stack
        .addToBackStack(null)
        .commit()

Java

// Works with either the framework FragmentManager or the
// support package FragmentManager (getSupportFragmentManager).
getSupportFragmentManager().beginTransaction()
                           .add(detailFragment, "detail")
                           // Add this transaction to the back stack
                           .addToBackStack(null)
                           .commit();

バックスタックに FragmentTransaction オブジェクトがある場合にユーザーが Back ボタンを選択すると、FragmentManager はバックスタックから最新のトランザクションを取り出し、逆行アクション(トランザクションでフラグメントが追加された場合はそのフラグメントを削除するなど)を実行します。

注: トランザクションが水平方向のナビゲーション(タブの切り替えなど)の場合や、コンテンツの外観を変更する場合(フィルタを調整する場合など)は、バックスタックにトランザクションを追加しないでください。Back ボタンを使用したナビゲーションが適切である場合について詳しくは、ナビゲーションの設計ガイドをご覧ください。

アプリで、アクションバーなど、フラグメントの現在の状態を反映するように他のユーザー インターフェース要素を更新する場合は、トランザクションをコミットするときに UI を更新してください。トランザクションをコミットするときだけでなく、バックスタックが変更された後もユーザー インターフェースを更新する必要があります。FragmentTransaction が元に戻されたかどうかは、FragmentManager.OnBackStackChangedListener を設定することで判断できます。

Kotlin

supportFragmentManager.addOnBackStackChangedListener {
    // Update your UI here.
}

Java

getSupportFragmentManager().addOnBackStackChangedListener(
        new FragmentManager.OnBackStackChangedListener() {
            public void onBackStackChanged() {
                // Update your UI here.
            }
        });

WebView の Back ナビゲーションを実装する

アプリの一部が WebView に含まれている場合は、Back ボタンを使用して閲覧履歴をさかのぼることをおすすめします。履歴状態があれば、onBackPressed() をオーバーライドして WebView に切り替えることができます。

Kotlin

override fun onBackPressed() {
    if (mWebView.canGoBack()) {
        mWebView.goBack()
    } else {
        // Otherwise defer to system default behavior.
        super.onBackPressed()
    }
}

Java

@Override
public void onBackPressed() {
    if (mWebView.canGoBack()) {
        mWebView.goBack();
        return;
    }

    // Otherwise defer to system default behavior.
    super.onBackPressed();
}

履歴が長くなる可能性がある非常に動的なウェブページでこのメカニズムを使用する場合はご注意ください。ドキュメント ハッシュの変更が頻繁に行われるページなど、長い履歴が生成されるページでは、ユーザーがアクティビティの外に出ることが難しくなる可能性があります。

WebView の使用について詳しくは、WebView でウェブアプリを作成する方法についての説明をご覧ください。