2012/07/03

Android:Upナビゲーションを実現するparentActivityName属性


JellyBeanでUPナビゲーションに関するAPIが追加されています。

AndroidManifest.xmlで定義するactivity要素のandroid:parentActivityName属性が新設
されました。
ここに"親"となるActivity(parentActivity)を指定することにより、UPナビゲーシ
ョンの遷移先を指定することができます。
http://developer.android.com/guide/topics/manifest/activity-element.html#parent

開発者はandroid:parentActivityNameを指定するだけで、UPナビゲーションを実現できます。
下記のようなonOptionsItemSelected()でandroid.R.id.homeを拾うようなコードはもう不
要です。
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {
        case android.R.id.home:
            // app icon in Action Bar clicked; go home
            Intent intent = new Intent(this, HomeActivity.class);
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
            startActivity(intent);
            return true;
        default:
            return super.onOptionsItemSelected(item);
    }
}
この機能を使用することで、今まで暗に推奨されていたルール(UPナビゲーションで発行
するIntentにはFLAG_ACTIVITY_CLEAR_TOPを指定する等)を守る責任を開発者が背負う必要
がなくなります。
# これで、UPナビゲーションの動作が端末上で統一されますね。

下記はandroid:parentActivityNameを指定した簡単なサンプルです。

<activity
    android:name=".ChildActivity"
    android:label="@string/title_activity_child"
    android:parentActivityName=".ParentActivity" >
    <intent-filter>
        <category android:name="android.intent.category.DEFAULT" />
    </intent-filter>
</activity>
---
2012/07/05 加筆・修正
一部誤解を招きそうな文章となっていたのを修正。
parentActivityNameで指定したActivityのタスクアフィニティが、自Activityの現在属している
タスクアフィニティと異なる場合に動作が変わる旨を追記
---

android:parentActivityName版UPナビゲーションの動作は非常にシンプルです。
基本は親Activityを起動するIntentをFLAG_ACTIVITY_CLEAR_TOPのような効果を付けて起
動します。

ただし、自Activityが現在属しているタスクアフィニティと、親Activityのタスクアフィ
ニティが異なる場合、UPナビゲーションは新たにタスクを生成して、そこに親Activityを
配置します。

また、android:parentActivityNameで指定した親Activity名に不正(存在しない)Activity
名を指定してもActivityNotFound例外は発生しません。
これは、UPナビゲーションは"親Activityの起動"ではなく、ナビゲーション階層の上部へ
の移動に重きを置いているためでしょう。

下記に各シーン毎のUPナビゲーション動作を列挙します。
(parentActivityのlaunchModeはstandardを指定)

●前提条件:
自Activityが現在属しているタスクアフィニティと、親Activityのタスクアフィニティが
同じ場合

【+親Activityが自Activityと同じスタック上に存在する場合】
parentActivityより上にあるActivity(自Activity含む)は破棄される。
また、parentActivityも再表示ではなく再生成される。


【+親Activityが自Activityと同じスタック上に複数存在する場合】
Activityスタック上でよりpeekに近い(最も上にある)Activityの位置に遷移する。
これ以外は"親Activityが自Activityと同じスタック上に存在する場合"と同様


【+親Activityが自Activityと同じスタック上に存在しない場合】
ルートActivity、またはランチャーが再表示される(再生成ではない)。


●前提条件:
自Activityが現在属しているタスクアフィニティと、親Activityのタスクアフィニティが
異なる場合

UPナビゲーションを契機に新たにタスクを生成します。
親Activityはこのタスクに生成され、自Activityは破棄されます。

後者の前提条件は例えば下記のようなケースで起こりえます。
http://developer.android.com/design/media/navigation_between_apps_up.png

詳しくは下記を参照
http://developer.android.com/intl/ja/design/patterns/navigation.html



●おわりに...


この機能はUPナビゲーションの実装を容易にします。
しかし、その反面UPナビゲーションを細かく制御することができません。
parentActivityを起動するIntentに関与したくなるケースがあるかもしれません。

この問題を解決するためにActivityクラスが拡張され、また新規クラスが作成されました。
http://developer.android.com/sdk/api_diff/16/changes/android.app.Activity.html
http://developer.android.com/reference/android/app/TaskStackBuilder.html

Activityには、アップナビゲーションに関するonNavigateUp()や
onPrepareNavigateUpTaskStack()が追加されました。
また、クロスタスクナビゲーションを実現するための合成バックスタックを構築するため
のユーティリティクラスTaskStackBuilderが新設されました。
UPナビゲーションのカスタマイズ方法は次の投稿にまとめます。

以上です。