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_branchBranchActivity クラスとして定義されたサブのアクティビティに遷移するボタン、ということになります。

さて、このプログラムを実際に実行してみると、サブの方のアクティビティが有効な状態であれば (デフォルトではそうなっているはず)、以下のような画面が表示されます (ちなみに画像はちょうど「次の画面へ」ボタンを押しているところです)。

もう一つのアクティビティが有効な状態の時に、そのアクティビティを開こうとしているところ。

もう一つのアクティビティが有効な状態の時に、そのアクティビティを開こうとしているところ。


ここで「次の画面へ」ボタンを押すと、当然、サブの方のアクティビティの画面に遷移します。
もう一つのアクティビティは問題なく開く。

もう一つのアクティビティは問題なく開く。


さて、メインの方の画面に戻って、今度は一回「子のアクティビティを無効にする」ボタンを押して、サブの方のアクティビティを無効にしてから、「次の画面へ」ボタンを押してみることにします。
もう一つのアクティビティが無効な状態の時に、そのアクティビティを開こうとしているところ。

もう一つのアクティビティが無効な状態の時に、そのアクティビティを開こうとしているところ。


…するとどうでしょう、今度は以下の画面のようなエラーを表示して、アプリケーションは終了してしまいました。
アクティビティは無効なので開くことができず、エラーを表示してアプリは終了する。

アクティビティは無効なので開くことができず、エラーを表示してアプリは終了する。


ところでこの画面、前回も同じような画面を見たような気がします。そう、 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 村山 俊之

タグ: ,

コメントをどうぞ