妄想プログラマのらくがき帳 : 2月 2013

2013年2月25日月曜日

[Android]暗黙的インテントを受け取る

前回のエントリでは、暗黙的インテントを使って他アプリを起動する方法について書きました。
今回は暗黙的インテントを受け取る側(起動される側)についてです。

暗黙的インテントを受け取れるようにするには、マニフェストファイルにインテントフィルタを追加します。
インテントフィルタとは、処理できる暗黙的インテントの種類をシステムに伝えるためのものです。
<activity    
    android:name="com.example.allowingotherappstostartsample.MainActivity"
    android:label="@string/app_name" >

    <intent-filter>
        <action android:name="android.intent.action.MAIN"/>
        <category android:name="android.intent.category.LAUNCHER"/>
    </intent-filter>

    <intent-filter>
        <action android:name="android.intent.action.VIEW"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:scheme="http" />
    </intent-filter>
    
</activity>
1個目のインテントフィルタは、EclipseでAndroidプロジェクトを新規作成したときに
自動生成されるマニフェストファイルに記述されているものです。
親タグのactivityがアプリのエントリポイントであることを示すandroid.intent.action.MAINと、
ランチャーから起動可能(であることを示すandroid.intent.category.LAUNCHERが指定されています。

2個目のインテントフィルタが今回追加したもので、下記の条件を満たす暗黙的インテントを受け取れる(処理できる)ことを表しています。

・アクションがIntent.ACTION_VIEW
・データに設定されているURIがhttp
カテゴリに指定されているcategory.DEFAULTは、暗黙的インテントを受け取るには必ず指定する必要があります
(但し、android.intent.action.MAINとandroid.intent.category.LAUNCHERを指定した場合は必須ではない)。

上記のインテントフィルタを設定したアプリを起動する側のコードは以下のようになります。
Intent browserIntent = new Intent(Intent.ACTION_VIEW);
browserIntent.setData(Uri.parse("http://www.example.com"));
startActivity(browserIntent );
このコードを実行すると、Chooserにデフォルトのブラウザに加えて受け取り側アプリが表示され、
暗黙的インテントを受け取れるようになったことが分かります。

2013年2月18日月曜日

[Android]暗黙的インテントで他アプリを起動する

他アプリを起動する方法として明示的インテントと暗黙的インテントがあります。

明示的インテントは、起動するアクティビティを明示的に指定する方法です。
この方法で他アプリを起動するには、起動するアプリのパッケージ名を直接指定する必要があります。

暗黙的インテントは、起動するアクティビティを指定するのではなく、
アクティビティに実行して欲しいアクションを指定する方法です。
この方法では指定したアクションを実行できるアプリがシステムによって選択されます
(該当するアプリが複数ある場合、アプリ選択画面が表示されます)。

指定するアクションには以下のようなものがあります。

ACTION_SENDTOメッセージ送信する。
ACTION_SEND_MULTIPLE複数のデータを送信する。
ACTION_DIAL電話をかける。
ACTION_VIEWデータをユーザに表示する。
ACTION_EDITデータを編集する。

この他にも数多くのアクションが定義されています。
(http://developer.android.com/reference/android/content/Intent.htmlを参照)

また、インテントにはアクションに加えてカテゴリやデータの種類を指定できます。
カテゴリやデータを指定することで、より最適なアプリが起動されるようになります。

暗黙インテントによる他アプリ起動のサンプル

暗黙的インテントのサンプルをいくつか挙げてみます。
Uri number = Uri.parse("tel:0123456789");
Intent callIntent = new Intent(Intent.ACTION_DIAL, number);

startActivity(callIntent);
Intent emailIntent = new Intent(Intent.ACTION_SENDTO);
emailIntent.setData(Uri.parse("mailto:abc@example.com"));
emailIntent.putExtra(Intent.EXTRA_SUBJECT, "タイトル");
emailIntent.putExtra(Intent.EXTRA_TEXT, "本文");

startActivity(emailIntent);
Intent cameraIntent = new Intent(MediaStore.ACTION_IMAGE_CAPTURE);

startActivity(cameraIntent);
Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);

startActivity(mapIntent);
Intent browserIntent = new Intent(Intent.ACTION_VIEW);
browserIntent.setData(Uri.parse("http://www.example.com"));

startActivity(browserIntent);

2013年2月11日月曜日

[Android]SQLデータベースにデータを保存する

データベースにデータを保存するにはSQLiteOpenHelperクラスを使います。

まず最初にSQLiteOpenHelperを継承したクラスを作成します。
public class ClientsDbHelper extends SQLiteOpenHelper {

    /** データベースのバージョン */
    public static final int DB_VERSION = 1;  // データベーススキーマを変更した場合、インクリメントする。

    /** データベースファイル名 */
    public static final String DB_NAME = "clients.db";

    public ClientsDbHelper(Context context) {
        // SQLiteOpenHelperクラスのコンストラクタには
        // データベースのバージョンを渡す。
        // コンストラクタに渡したバージョンと
        // データベースが保持しているバージョンが異なる場合、
        // onUpgrade()、またはonDowngrade()が呼ばれる。

        super(context, DB_NAME, null, DB_VERSION);
    }

    @Override
    public void onCreate(SQLiteDatabase db) {
        // データベースが作成された時に呼び出される。
        // ここでデータベースの初期化(テーブルの作成やテーブルの初期化等)を行う。

        final String createSql = "CREATE TABLE clients("
          + "id INTEGER PRIMARY KEY AUTOINCREMENT, "
          + "name TEXT"
          + ")";
        try {
         db.execSQL(createSql);
        } catch (SQLException e) {
         e.printStackTrace();
        }
    }

    @Override
    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
        // データベースをアップグレードする必要がある場合に呼び出される。
        // ここでデータベースを新バージョンにアップグレードする処理を行う。
        // 以下は、既存データはすべて破棄しても良い場合の処理例

        db.execSQL("DROP TABLE clients"); // 旧バージョンのテーブルを破棄
        onCreate(db); // 新バージョンでテーブルを作成し直す
    }
}
onDowngrade()の実装は必須ではないので、必要な場合は実装します。

データを挿入する。

データの挿入は、SQLiteDatabase.execSQL()でSQLのINSERT文を実行する方法と
SQLiteDatabase.insert()を使う方法があります。
以下はinsert()を使う場合のコードです。
// ContentValuesに列名と値を設定
ContentValues values = new ContentValues();
values.put("name", "Taro"); 

try {
    // データベースを書き込み用で開く
    ClientsDbHelper dbHelper = new ClientsDbHelper(getApplicationContext());
    SQLiteDatabase db = dbHelper.getWritableDatabase();
    
    db.insert("clients", null, values); // 挿入先テーブルを指定して挿入
    // ↑の場合、valuesが空だとinsert()が例外をスローする。
    // これを防ぐには、次のようにnullColumnHackを指定する。
    // db.insert("clients", "name", values);
} catch (SQLException e) {
    e.printStackTrace();
}
insert()の2つ目の引数nullColumnHackには、ContentValuesが空の場合にNULLを設定する列を指定します。
SQLiteDatabaseはContentValuesが空だとinsert()に失敗(例外スロー)しますが、
nullColumnHackを指定しておくと失敗しないようにできます。

そのため、指定した列はNULLを設定できなければなりません。そうでない場合(intやNOT NULL列の場合)、insert()に失敗します。

通常、ContentValuesが空になることは無いと思うので、nullColumnHackはnullで問題ありません。

データを取得する。

データの取得は、SQLiteDatabase.rawQuery()でSQLのSELECT文を実行する方法と
SQLiteDatabase.query()を使う方法があります。
個人的な好みになりますが、rawQuery()を使った方が分かりやすく簡単だと思います。
以下はrawQuery()を使う場合のコードです。
final String querySql = "SELECT * FROM clients;";

ClientsDbHelper dbHelper = new ClientsDbHelper(getApplicationContext());
Cursor cursor = null;
try {
    // データベースを読み取り専用で開く
    SQLiteDatabase db = dbHelper.getReadableDatabase();
    
    // SELECT文を実行
    cursor = db.rawQuery(querySql, null);

    // Cursorから値を取得するための列indexを取得
    int idColumnIndex = cursor.getColumnIndexOrThrow("id");
    int nameClumnIndex = cursor.getColumnIndexOrThrow("name");
    // Cursorから値を取得
    if (cursor.moveToFirst()) {
        do {
            int id = cursor.getInt(idColumnIndex);
            String name = cursor.getString(nameClumnIndex);

            // do something

        } while (cursor.moveToNext());
    }
} catch (SQLiteException e) {
    e.printStackTrace();
} finally {
    if (cursor != null) {
        cursor.close();
    }
}

データの更新/削除も同様に、SQLiteDatabaseを使って行えます。
SQL文を実行する方法とSQLiteDatabaseのメソッドを使用する方法がありますが、
どちらの方法を使っても大差ないので、使い勝手の良い方を使うのがいいと思います。