適切な「戻る」ナビゲーションを提供する

「戻る」ナビゲーションとは、ユーザーがこれまでにアクセスした画面の履歴を遡って移動する機能です。すべての Android デバイスにこのナビゲーション タイプ用の [戻る] ボタンが用意されているため、アプリの UI には [戻る] ボタンを追加しないでください。ユーザーの Android デバイスによっては、このボタンが物理ボタンの場合もあれば、ソフトウェア ボタンの場合もあります。

Android は、ユーザーがアプリ内を移動する際、デスティネーションのバックスタックを保持します。これにより、通常は [戻る] ボタンを押すと、以前のデスティネーションに適切に移動できます。ただし、可能な限り最高のユーザー エクスペリエンスを提供するために、アプリ独自の [戻る] 動作を実装する必要性が生じることがあります。たとえば、WebView を使用している場合、デフォルトの [戻る] ボタンの動作をオーバーライドして、アプリ内の前の画面ではなく、ウェブ閲覧履歴をさかのぼれるようにできます。

カスタムの「戻る」ナビゲーションを実装する

FragmentActivity および AppCompatActivity の基本クラスである ComponentActivity では、getOnBackPressedDispatcher() を呼び出して取得できる OnBackPressedDispatcher を使用して、[戻る] ボタンの動作を制御できます。

OnBackPressedDispatcher は、[戻る] ボタンイベントを 1 つまたは複数の OnBackPressedCallback オブジェクトにディスパッチする方法を制御します。OnBackPressedCallback のコンストラクタは、初期有効状態のブール値を取ります。コールバックが有効になっている場合(つまり、 isEnabled()true を返す場合)に限り、ディスパッチャはコールバックの handleOnBackPressed() を呼び出して、[戻る] ボタンイベントを処理します。有効状態を変更するには、setEnabled() を呼び出します。

コールバックは、addCallback メソッドを通じて追加されます。LifecycleOwner を取る addCallback() メソッドを使用することを強くおすすめします。これにより、LifecycleOwnerLifecycle.State.STARTED の場合に限り、OnBackPressedCallback が追加されるようになります。また、対象の LifecycleOwner が破棄されると、アクティビティによって、登録済みコールバックが削除されます。これにより、メモリリークが防止されるため、アクティビティよりも寿命が短いフラグメントや各種ライフサイクル オーナー内で使用する場合に適しています。

コールバック実装の例を以下に示します。

Kotlin

class MyFragment : Fragment() {

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        // This callback will only be called when MyFragment is at least Started.
        val callback = requireActivity().onBackPressedDispatcher.addCallback(this) {
            // Handle the back button event
        }

        // The callback can be enabled or disabled here or in the lambda
    }
    ...
}

Java

public class MyFragment extends Fragment {

    @Override
    public void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // This callback will only be called when MyFragment is at least Started.
        OnBackPressedCallback callback = new OnBackPressedCallback(true /* enabled by default */) {
            @Override
            public void handleOnBackPressed() {
                // Handle the back button event
            }
        };
        requireActivity().getOnBackPressedDispatcher().addCallback(this, callback);

        // The callback can be enabled or disabled here or in handleOnBackPressed()
    }
    ...
}

addCallback() を通じて複数のコールバックを提供できます。 その場合、コールバックは、追加した順序と逆の順序で呼び出され、最後に追加したコールバックが、[戻る] ボタンイベントを最初に処理するチャンスを与えられます。たとえば、onetwothree という名前の 3 つのコールバックをこの順序で追加した場合、threetwoone という順序で呼び出されます。

コールバックは、「チェーン オブ レスポンシビリティ」パターンに従います。チェーン内の各コールバックが呼び出されるのは、前のコールバックが有効になっていない場合に限られます。つまり、上記の例の場合、コールバック three が有効状態でない場合に限り、コールバック two が呼び出されます。同様に、コールバック two が有効状態でない場合に限り、コールバック one が呼び出されます。

なお、addCallback() を通じてコールバックを追加する場合、LifecycleOwnerLifecycle.State.STARTED 状態になるまで、コールバックは「チェーン オブ レスポンシビリティ」には追加されません。

上記で説明した順序を維持するため、OnBackPressedCallback の有効状態を変更する場合は、一時的な変更にとどめておくことを強くおすすめします。この点は特に、複数のネスト ライフサイクル オーナーに対してコールバックを登録する場合に重要になります。

他方、OnBackPressedCallback を完全に削除する場合は、remove() を呼び出します。ただし、対象の LifecycleOwner破棄されるとコールバックも自動的に削除されるため、この処理は通常必要ありません。

onBackPressed() アクティビティ

onBackPressed() を使用して [戻る] ボタンイベントを処理している場合は、代わりに OnBackPressedCallback を使用することをおすすめします。ただし、この変更に対応できない場合は、次のルールが適用されます。

  • addCallback を通じて登録するコールバックはすべて、super.onBackPressed() を呼び出したときに評価されます。
  • Android 12(API レベル 32)以前では、登録された OnBackPressedCallback インスタンスに関係なく、常に onBackPressed が呼び出されます。