&autolink(id=main)
目次
参考にするリンク
構成説明
画面構成。
今回説明する画面構成を描いておく。
まずは HomeAsUp を有効にする。
setDisplayHomeAsUpEnabled(true)
onCreate()でもどこでもいいので次の一文を書く。
getActionBar().setDisplayHomeAsUpEnabled(true);
アプリアイコンの左に「<」の矢印が出ればイベントがくるようになる。
onOptionsItemSelected(MenuItem)
そうしたら onOptionsItemSelected で android.R.id.home を受ける。
@Override
public boolean onOptionsItemSelected
(MenuItem item
) { boolean result = true;
switch (item.getItemId()) {
case android.R.id.home:
Toast.makeText(this, "home", Toast.LENGTH_SHORT).show();
break;
default:
result = super.onOptionsItemSelected(item);
break;
}
return result;
}
この実装だと「home」っていうToastが表示される。
Top画面に戻るだけならこれでいい。
Developers Guid によるとこうなる。
これでどの画面からでも HomeActivity に戻ることができる。
@Override
public boolean onOptionsItemSelected
(MenuItem item
) { boolean result = true;
switch (item.getItemId()) {
case android.R.id.home:
// 戻る先は HomeActivity
Intent intent = new Intent(this, HomeActivity.class);
// 戻るときに開いていたActivityを全部閉じる
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
break;
default:
result = super.onOptionsItemSelected(item);
break;
}
return result;
}
ここまでのソース(これを各Activityで継承)
public class MyBaseActivity extends Activity
abstract public class MyBaseActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActionBar().setDisplayHomeAsUpEnabled(true);
}
@Override
public boolean onOptionsItemSelected
(MenuItem item
) { boolean result = true;
switch (item.getItemId()) {
case android.R.id.home:
// 戻る先は HomeActivity
Intent intent = new Intent(this, HomeActivity.class);
// 戻るときに開いていたActivityを全部閉じる
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
break;
default:
result = super.onOptionsItemSelected(item);
break;
}
return result;
}
}
特定のActivityに戻るように書き換える。
○○画面を通過していたらそこに戻りたい理由。
で、本題。
1つ1つのActivityやFragmentに同じことを書くのは嫌なので、
共用のユーティリティクラスやActivity/Fragmentを継承した
MyBaseActivity みたいなものを普段は作る。
そこで自動的に HomeActivity に戻るようにすると、
- [HomeActivity] => [FirstActivity]
- [HomeActivity] => [FirstActivity] => [IlkActivity]
- [HomeActivity] => [FirstActivity] => [IkinciActivity]
- [HomeActivity] => [SecondActivity]
- [HomeActivity] => [SecondActivity] => [ErsteActivity]
のどれからでも HomeActivity に戻る・・・のだが、
- FirstActivity を経由していたら FirstActivity に戻る
- SecondActivity を経由していたら SecondActivity に戻る
としたい。
これだけなら 第3階層 の
- IlkActivity
- IkinciActivity
- ErsteActivity
に、専用の MyBaseActivity を作ればいいんだけど、
は 他アプリ からも起動される画面なので、
SecondActivityを通過していないから戻りたくない。
そんなワガママなことをしたい。
解1:ActivityLifecycleCallbacksでActivityの通過を受ける。
Activityのスタックを管理(ActivityStackManager)
長いのでファイルで。
ActivityStackManager.java
では適当に解説。
ActivityStackManager#ActStack
各Activityのスタックを覚える。
あとで android.content.ComponentName を使ってIntentを投げるので覚えておく。
インスタンスの見分け方は色々あるけれど、
Activity#toString は ハッシュコード付きなんで“ほぼ”特定可能。
絶対特定したいなら「専用の見分ける」コードを作るといい。
ActivityStackManager#searchRootComponentName(Activity)
指定Activityが登録してあるスタックの、ルートComponentNameを返す。
普段はIntentを投げるActivityから呼び出される想定なので、
そのActivityの登録を見に行く。
他の使い方が全く思いつかないのでこうしているけれど、
専用の「見分ける何か」をActivityに準備しているなら、
それを渡すようにしてもいいと思う。
Activityのスタックを管理(Application)
ま、これは定型文。
使うだけならこれでも十分。
public class TestApplication extends Application {
private static final ActivityStackManager CALLBACK = new ActivityStackManager();
@Override
public void onCreate() {
super.onCreate();
registerActivityLifecycleCallbacks(CALLBACK);
}
public ComponentName getRootComponentName(Activity activity) {
return CALLBACK.searchRootComponentName(activity);
}
}
Activityのスタックを管理(Activity)
自分がルートの場合「name.equals(this.getComponentName())」は
とりあえず戻ることにした。
それ以外の時は「intent.setComponent(name);」を設定することで
ルートに戻る。
Intent.makeRestartActivityTask(ComponentName)
を使いたかったが
Intent.FLAG_ACTIVITY_CLEAR_TASK
が指定されているので全てのActivityを殺してしまう。
ちょっと今回の意図と違う動きなので自分で投げることに。
ソースはこんな感じで。
@Override
abstract public class MyBaseActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActionBar().setDisplayHomeAsUpEnabled(true);
}
@Override
public boolean onOptionsItemSelected
(MenuItem item
) { boolean result = true;
switch (item.getItemId()) {
case android.R.id.home:
TestApplication application = (TestApplication) getApplication();
ComponentName name = application.getRootComponentName(this);
if (name.equals(this.getComponentName())) {
onBackPressed();
} else {
Intent intent = new Intent();
intent.setComponent(name);
// 戻るときにそれ以降で開いていたActivityを全部閉じる
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
}
break;
default:
result = super.onOptionsItemSelected(item);
break;
}
return result;
}
}
解1:まとめ
ActivityLifecycleCallbacksを利用すればスタックを保存できるので、
どんな場所にも移動できる処理は書ける。
ActivityStackManager.java
で管理自体は可能。
でも、本当にやりたいのはAndroid標準でサポートしているナニカを使い、
できるだけ自動で動かしたいところだ。
まとめ
現在は「解1」しか手段を持っていない。
それでも実現自体は可能なので問題ないのだが・・・。
ActivityのLifecycleはどうしてもフレームワークの実装に偏るので、
日本の端末では特殊な動作でフレームワークがActivityを消すルートがありそうで
この実装では怖い。
もっと簡単に、手軽にスタックを取得できないものだろうか。
関連リンク
取得中です。
&trackback()
最終更新:2012年02月13日 00:03