Android プログラミング(4) – Activity の有効・無効
シリーズとして、下記の書籍にて学習したことについてのメモを綴っています。
今回は、「HACK#7 アクティビティ Hacks」 (p.58~63) の内容について触れていきます。
adb コマンドからアクティビティを起動
adb
コマンドですが、SDK をインストールした際にパスを通した tools
ディレクトリにはもはや存在しません。代わりに adb_has_moved.txt
というふざけた名前のファイルが置いてあって、開くと次のように書かれています。
The adb tool has moved to platform-tools/ If you don't see this directory in your SDK, launch the SDK and AVD Manager (execute the android tool) and install "Android SDK Platform-tools" Please also update your PATH environment variable to include the platform-tools/ directory, so you can execute adb from any location.
そんな訳なので、先ずはあらかじめ (SDK インストールディレクトリ)
ディレクトリにもパスを通しておきましょう。/platform-tools
adb
コマンドを単に実行すると、 shell
以外のサブコマンドの説明も含むヘルプが表示されます。それを読むとわかるのですが、 shell
サブコマンドからアクセスできるシェルというのは、エミュレータを弄る回で扱ったエミュレータコンソールとは別物です。ちなみに、エミュレータコンソールのコマンドも adb
コマンドの emu
サブコマンドから実行できるようです。
アクティビティの有効・無効を動的に切り替える
このトピックは致命的なことに、アクティビティが有効になる/無効になると言うことがどういう事なのかがいまいちわかりづらくなっています。現象から言えることは、マニフェストに登録したアクティビティが <intent-filter>
要素を伴ってランチャーにアイコンを表示させるようにしていた場合、アクティビティが有効ならばそのアイコンが表示され、無効ならば表示されなくなる、ということだけでした。
そこで、メインの方のアクティビティにボタンをもう一つ加えて、そのボタンを押すとサブの方のアクティビティに遷移するようにしてみました。よーするに、前回の前半でやった内容を組み合わせちゃったわけですね。
参考までに、実際に実装したメインの方のアクティビティクラスの
onCreate()
ハンドラメソッドを以下に掲載します。
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); button_enable_branch = (Button)findViewById(R.id.bt_enable_branch); button_to_branch = (Button)findViewById(R.id.bt_to_branch); pack_man = getPackageManager(); com_name = new ComponentName(this, BranchActivity.class); is_enable_branch_activity = !(pack_man.getComponentEnabledSetting(com_name) == PackageManager.COMPONENT_ENABLED_STATE_DISABLED); setButtonText(); button_enable_branch.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { if (is_enable_branch_activity){ pack_man.setComponentEnabledSetting(com_name, PackageManager.COMPONENT_ENABLED_STATE_DISABLED, PackageManager.DONT_KILL_APP); } else { pack_man.setComponentEnabledSetting(com_name, PackageManager.COMPONENT_ENABLED_STATE_ENABLED, PackageManager.DONT_KILL_APP); } is_enable_branch_activity = !is_enable_branch_activity; setButtonText(); } }); button_to_branch.setOnClickListener(new View.OnClickListener() { public void onClick(View v) { startActivity(new Intent(RootActivity.this, BranchActivity.class)); } }); }
例によって変数名とかは結構変えてありますw。 RootActivity
がこのアクティビティで、 BranchActivity
が (有効/無効を切り替えられる) サブの方のアクティビティですね。 button_enable_branch
がこの有効/無効を切り替える方のボタン (本書のサンプルにあった mButton
に相当する方ですね)、そして button_to_branch
が BranchActivity
クラスとして定義されたサブのアクティビティに遷移するボタン、ということになります。
さて、このプログラムを実際に実行してみると、サブの方のアクティビティが有効な状態であれば (デフォルトではそうなっているはず)、以下のような画面が表示されます (ちなみに画像はちょうど「次の画面へ」ボタンを押しているところです)。
ここで「次の画面へ」ボタンを押すと、当然、サブの方のアクティビティの画面に遷移します。
さて、メインの方の画面に戻って、今度は一回「子のアクティビティを無効にする」ボタンを押して、サブの方のアクティビティを無効にしてから、「次の画面へ」ボタンを押してみることにします。
…するとどうでしょう、今度は以下の画面のようなエラーを表示して、アプリケーションは終了してしまいました。
ところでこの画面、前回も同じような画面を見たような気がします。そう、
AndroidManifest.xml
ファイル、すなわちマニフェストに登録し忘れたアクティビティを開こうとしたときに表示されたのと同じエラー画面です。
実際、 Debug パースペクティブを開いてデバッグ実行してみると、この画面が表示されるまで進めた段階で、 LogCat に以下のようなログメッセージが出力されます。
09-25 08:48:58.955: ERROR/AndroidRuntime(468): android.content.ActivityNotFoundException: Unable to find explicit activity class {jp.co.harapeko.testsome/jp.co.harapeko.testsome.BranchActivity}; have you declared this activity in your AndroidManifest.xml?
これはまさしく、マニフェストに登録し忘れたアクティビティを開こうとしたときに出力されたのとまったく同じログメッセージです。すなわち、「アクティビティを無効にする」とは、「アクティビティがマニフェストに登録されていないような状態にする」ということなのでした。
そんな訳なので、
この Hack を利用して、特定の条件を満たした時しか表示されないようなアイコンがある隠し機能があるアプリを作ると面白いかもしれませんね。
といったような使い方をするのであれば、アプリケーションの画面遷移図において隔離されている (その画面に遷移する画面が存在しない) 状態に設計されている必要がある、という注意事項をわきまえなければならないことになります。
例えば、ゲームソフトのコンフィグでゲームのオープニングをスキップできるようにする場合、単純にオープニング用のアクティビティとゲーム本編用のアクティビティとでアイコンを差し替えるように作ろうとすると、ゲーム本編用のアクティビティを無効にした場合にゲーム本編が実行できなくなるという残念な障害にぶち当たるので、ゲーム本編に即座に飛ぶスキップ用のアクティビティを間に挟む必要があるよ、ということになるでしょう。
今回は以上です。
2011 年 9 月 25 日 by 村山 俊之