Intentチュートリアル2

前準備(デバッグ用にintentを送信)

intentは複数アクティビティの連携であるため、動作確認するためには必ず送信元が必要となる。ユニットテストとしては送信元も作る必要があるが、とりあえず試してみたいといった場合には不便だ。そういった場合はコンソールでAndroidエミュレータ上のlinuxにアクセスしてそこからintentを送る方式が便利だ。

Android SDKに含まれる実行ファイルを使うため、次の作業はインストール時にAndroid SDKのパスを設定していない場合はAndroid SDKをインストールしたパス+toolsの中で作業する必要がある。まずはadb shellを実行するとAndroidエミュレータ上のlinuxに接続される。その後、amコマンドでintentを送信することができる。

暗黙的なintentの送信
am start -a アクション名(android.intent.action.EDIT等) -d content://xxxxx(file:/xxやhttp://xxの様なタイプ://リソース) -t xxx/yyy(text/css等のMIME/TYPE)
明示的なintentの送信
am start -n パッケージ名/.アクティビティクラス(com.suddenAngerSystem/.BroadCastIntentの様な)

暗黙的なintent

intentはアクションとパラメータの組み合わせだけで送信先を具体的に指定しない暗黙的なやり方でも送受信される。その場合はアクティビティ自身がシステムに対してどういったintentを受信するのか登録する必要がある。登録の仕方としては二通りあり、javaのソースでIntentFilterクラスを使用して動的に登録する方法とマニフェストファイルで宣言して静的に登録する方法である。ここではマニフェストファイルで宣言して静的に登録する方法を示す。

マニフェストファイルにはintent-filter要素で受け付けるアクション種別、カテゴリー、データ形式を宣言する。アクション種別はAndroid側で標準的なオペレーションを準備しているのでそれを使用する。また、データ形式にはfoo://xxxxの様なintentのUriパラメータで指定するパターンを示す。(通常は別途説明するコンテンツプロバイダーの形content://xxxxの形式を使用する)

まずは、実例を見てみよう。以下ではVIEWアクションとfoo://xxxxの様なパラメータを受け付ける用に登録している。

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="com.suddenAngerSystem"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".BroadCastIntent"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <!-- 暗黙のintent用のフィルタ -->
            <intent-filter>
                <action android:name="android.intent.action.VIEW" />
                <category android:name="android.intent.category.DEFAULT" />
                <!-- foo://xxxxのようなリクエストを受け付ける -->
                <data android:scheme="foo" android:mimeType="text/html" />
            </intent-filter>
        </activity>
    </application>
    <uses-sdk android:minSdkVersion="3" />
</manifest>
	

以下は起動時にintentの値をチェックし、暗黙のintentかそれとも直接起動されたかを確認している。(本来はUriMatcherで要求Uriの確認をすべきなのだが、例が複雑となるため実施していないので注意すること。コンテンツプロバイダーで別途説明する。)

package com.suddenAngerSystem;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.TextView;

public class BroadCastIntent extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        //暗黙のintentの場合
        if(Intent.ACTION_VIEW.equals(getIntent().getAction())) {
            final Uri uri = getIntent().getData();
            TextView view = new TextView(this);
            view.setText("暗黙のintentで起動された");
            this.addContentView(view, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        }
        else {
            TextView view = new TextView(this);
            view.setText("通常起動された");
            this.addContentView(view, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        }
    }
}
	

今まで述べてきた方式だと一つのintent(アクションとパラメータの組)に対して複数のアクティビティが対応してしまうケースが出てきてしまう。Androidはそういった場合の解決方法としてユーザーに一度どのアクティビティを優先させるかのダイアログを表示して選択させる。一度選択された後はそれがデフォルトとして使用される。

BroadCastIntent

システムで時刻変更がなされたとするとアラームアプリは設定を変更する必要が出てくるかもしれない。そうした、システム全体に影響を与える様な事項についてはそれらの情報を必要とするシステムにあるアプリケーション全てに対して通知が必要がある。それの実装手段がブロードキャストのintentとなる。逆に言えばブロードキャスト的なintentを受け取ることを宣言することによって、システムの監視ができることになる。ブロードキャスト的なintentは通常のintentとは受信の仕方が異なる。まず、ブロードキャスト的なintentはContextクラスのregisterReceiverメソッドでBroadCastReceiverインターフェースを継承したハンドラと受け取るアクション等を定義したIntentFilterクラスのインスタンスを登録する。そしてブロードキャスト的なintentが発生するとハンドラのonReceive関数が起動される。

具体的な例で見ていこう。ブロードキャストintentを受信するとアラートダイアログを表示するハンドラreceiverとフィルターfilterをregisterReceiverでシステムに登録している。(以下の例では考慮していないが、本来はアクティビティが非アクティブになるタイミングでunregisterReceiverメソッドを使用してブロードキャストのハンドラを解除する等の考慮が必要となる。)

package com.suddenAngerSystem;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.net.Uri;
import android.os.Bundle;
import android.view.View;
import android.view.ViewGroup.LayoutParams;
import android.widget.TextView;

public class BroadCastIntent extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);

        //暗黙のintentの場合
        if(Intent.ACTION_VIEW.equals(getIntent().getAction())) {
            final Uri uri = getIntent().getData();
            TextView view = new TextView(this);
            view.setText("暗黙のintentで起動された");
            this.addContentView(view, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
        }
        else {
            TextView view = new TextView(this);
            view.setText("通常起動された");
            this.addContentView(view, new LayoutParams(LayoutParams.FILL_PARENT, LayoutParams.FILL_PARENT));
            registerReceiver(receiver, filter);
        }
    }

    //無名クラスでハンドラを定義
    private static final BroadcastReceiver receiver = new BroadcastReceiver() {
		@Override
		public void onReceive(Context context, Intent intent) {
	    	AlertDialog.Builder builder = new AlertDialog.Builder(context);
	    	builder.setTitle("タイトル");
	    	builder.setMessage("メッセージ");
	    	builder.setPositiveButton("OK",new android.content.DialogInterface.OnClickListener() {
		        public void onClick(android.content.DialogInterface dialog,int whichButton) {
		        }
		    });
	    	builder.create();
	    	builder.show();
		}
    };

    //ブロードキャストintent向けのintentフィルターを作成
    private static final IntentFilter filter = new IntentFilter();
    static {
    	filter.addAction(Intent.ACTION_BATTERY_LOW);
    	//バッテリーのData形式が良く分からないので、とりあえず適当
    	filter.addDataScheme("foo");
    }
}
	

ブロードキャストのintentを送信した際の動作は以下の様になる。

コンテンツプロバイダー、サービスのintentについては別途説明する。

参考サイト