31

ソースコードはこちらから入手できます: https://github.com/novemberox/NavigationTestこのサンプルの修正版です: http://developer.android.com/training/implementing-navigation/ancestral.html

3 つのアクティビティがあります。

  • Main Activityアプリケーションへのメインエントリのみ
  • Category Activity詳細アクティビティの親です
  • Detail Activity

Main Activityと開くボタンがCategory ActivityありDetail Activityます。 Category Activtyには、開くボタンが 1 つだけありますDetail Activity。最後にDetail Activity、テキストが表示され、ActionBar のクリックをシミュレートするアップ ボタンがあります。

私の「クリック」パスは次のとおりです。

  • メインアクティビティを開く
  • 詳細アクティビティを開く
  • 「アップボタン」をクリック
  • カテゴリ アクティビティが表示されます
  • 戻るをクリックすると、状態が復元された Main Activity に移動します

そして、これは予想されるフローであり、Jelly Bean より前のすべての Android で問題なく動作しています (Galaxy Nexus 4.1.1 およびエミュレーター 4.2 Google exp pack でテスト済み)。ICS でも動作します。最初に指摘したサンプルのように、サポート ライブラリと NavUtils や TaskStackBuilder などのクラスを使用しています。

JB で「上へ」ボタンをクリックすると、メイン アクティビティに戻り、状態が正しく復元されます。サポート ライブラリのソース コードを調べたところ、NavUtils.navigateUpToメソッドが のようなネイティブ JB コードを呼び出していることがわかりましActivity#navigateUpToた。NavUtils#navigateUpTo()私は両方を試しNavUtils.navigateUpFromSameTask()ましたが、同じ不満足な結果でした。

この素晴らしい流れを実現するために何をすればよいか、何か提案はありますか?

4

2 に答える 2

63

まず最初に、API 17(Android 4.2)までのデバイスをターゲットにしている場合はtargetSdkVersion、マニフェストでを17に設定します。これは古いデバイスのサポートを壊すことはなく、新しいデバイスで正しく機能するようにするだけです。もちろん、それはあなたの問題を解決しません-それをするのは良いことです。

何を使うべきですか?

このページのAncestralNavigationの例に基づいてコードを作成していると思います。2番目の例を使用しました。

Intent upIntent = new Intent(this, MyParentActivity.class);
if (NavUtils.shouldUpRecreateTask(this, upIntent)) {
    // This activity is not part of the application's task, so create a new task
    // with a synthesized back stack.
    TaskStackBuilder.from(this)
        .addNextIntent(new Intent(this, MyGreatGrandParentActivity.class))
        .addNextIntent(new Intent(this, MyGrandParentActivity.class))
        .addNextIntent(upIntent)
        .startActivities();
    finish();
 } else {
     // This activity is part of the application's task, so simply
     // navigate up to the hierarchical parent activity.
     NavUtils.navigateUpTo(this, upIntent);
 }

ただし、必要な動作については、次のように置き換える必要がありますNavUtils.navigateUpTo

upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(upIntent);
finish();

なぜICS以前で動作するのですか?

一般に、サポートライブラリは、後のAPIで導入された動作を概算しようとしています。の場合NavUtils、サポートライブラリはAPI 16(別名Android 4.1)で導入された動作を概算しようとしています。API 16より前のプラットフォームの場合、NavUtilsは以下を使用します。

@Override
public void navigateUpTo(Activity activity, Intent upIntent) {
    upIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
    activity.startActivity(upIntent);
    activity.finish();
}

これは、で指定されたアクティビティのインスタンスのバックスタックを調べますupInent。見つかった場合は、それまでのすべてをクリアして復元します。それ以外の場合は、アクティビティを起動するだけです。

API 16以降のプラットフォームでは、サポートライブラリがActivityAPIのネイティブ呼び出しに処理を渡します。ドキュメントによると:

パブリックブールnavigateUpTo(Intent upIntent)

このアクティビティからupIntentで指定されたアクティビティに移動し、プロセスでこのアクティビティを終了します。upIntentで示されたアクティビティがタスクの履歴にすでに存在する場合、このアクティビティと、履歴スタックで示されたアクティビティの前にある他のすべてのアクティビティが終了します。

示されたアクティビティが履歴スタックに表示されない場合、タスクのルートアクティビティに到達するまで、このタスクの各アクティビティが終了し、「アプリ内ホーム」動作が発生します。これは、正規の親アクティビティを通過しないパスがアクティビティに到達する可能性がある場合に、複雑なナビゲーション階層を持つアプリで役立ちます。

upIntentそのことから、バックスタックにない場合にで指定されたアクティビティを起動するかどうかは不明です。ソースコードを読んでも、物事を明確にするのに役立ちません。ただし、アプリが示している動作から判断すると、アクティビティを起動しようとはしていないようです。upIntent

どちらの実装が正しいか間違っているかに関係なく、最終的にはFLAG_ACTIVITY_CLEAR_TOP、ネイティブAPI 16の動作ではなく、動作が必要になります。残念ながら、これはサポートライブラリの概算を複製する必要があることを意味します。

どちらが正しい?

免責事項:私はGoogleで働いていないので、これが私の最善の推測です。

私の推測では、API16以降の動作は意図された動作です。これは、Androidの内部にアクセスでき、APIでは不可能なことを実行できる組み込みの実装です。API 16より前では、インテントフラグを使用する以外に、この方法でバックスタックを巻き戻すことはできなかったと思います。したがって、FLAG_ACTIVITY_CLEAR_TOPフラグは、 API16より前のプラットフォームで使用可能なAPI16の動作に最も近いものです。

残念ながら、その結果、ネイティブ実装とサポートライブラリ実装の間に、シナリオで驚き最小の原則に違反することになります。それは、これがAPIの予期しない使用であるかどうか疑問に思います。つまり、Androidは、アクティビティに直接ジャンプするのではなく、アクティビティへの完全なナビゲーションパスをトラバースすることを期待しているのだろうか。

念のため

考えられる誤解を1つ回避するためshouldUpRecreateTaskに、親がバックスタックにないことを魔法のように判断し、を使用してすべてを合成するプロセスを実行することを誰かが期待する可能性がありますTaskStackBuilder

ただし、shouldUpRecreateTask基本的に、アクティビティがアプリによって直接起動されたか(この場合は戻りますfalse)、別のアプリから起動されたか(この場合は戻りますtrue)を決定します。この本から、サポートライブラリはインテントの「アクション」がそうでないかどうかをチェックしますACTION_MAIN(私はそれを完全には理解していません)が、API16プラットフォームではタスクアフィニティに基づいてこのチェックを実行します。それでも、このアプリの場合、shouldUpRecreateTaskfalseを返すようになります。

于 2013-02-09T23:19:49.377 に答える