Android のローカル・データ・ストア API を理解する

プリファレンス、SQLite、内部メモリー、外部メモリーを対象とした API を利用する

モバイル機器のローカルにデータを保存できる機能は、モバイル・アプリケーションに不可欠な機能です。モバイル・アプリケーションでは、アプリケーションの実行期間全体にわたって、またはアプリケーションの存続期間全体にわたって、必須情報を保持している必要があります。一方、開発者の皆さんは、ユーザー・プリファレンス、アプリケーションの構成などの情報を常に保持しておく必要があります。また、アクセスの可視性などの特性に応じて、あるいは複雑な構造化されたデータ型を扱う必要がある場合には、内部ストレージや外部ストレージを利用する必要があるかどうかを判断する必要があります。この記事では、Android のデータ・ストレージ API について学びますが、特にプリファレンス、SQLite、内部メモリー、外部メモリーを対象とした API に焦点を当てます。

よく使われる頭文字語

  • ADT: Android Development Tools
  • API: Application program interface
  • IDE: Integrated development environment
  • JDK: Java Development Kit
  • JSON: JavaScript Object Notation
  • SDK: Software Development Kit
  • SQL: Structured Query Language
  • UI: User interface
  • XML: Extensible Markup Language

前提条件

この記事を読み進めるためには、以下のスキルとツールが必要です。

  • Java™ 技術と Eclipse (あるいは皆さんお気に入りの IDE) の使い方に関する基本的な知識
  • Java Development Kit (バージョン 5 または 6 が必要です)
  • Eclipse (バージョン 3.4 または 3.5)
  • Android SDK と ADT プラグイン

ダウンロードとセットアップに関しては、この記事の最後にある「参考文献」を参照してください。


サンプル・アプリケーション

ここでは Android アプリケーション開発におけるローカル・ストアの側面に焦点を当てるために、さまざまなタイプの API の実行をテストできるサンプル・アプリケーションを取り上げます。このアプリケーションのソース・コードはダウンロードすることができます。図 1 に、このアプリケーションがサポートするアクションを示します。

図 1. サンプル・アプリケーションのユース・ケース
サンプル・アプリケーションのユース・ケースを示す図

図 1 は以下のユース・ケースを示しています。

  • プリファレンスの管理と保存
  • アプリケーションのアセットからの情報のロード
  • 内部メモリー、外部メモリー、ローカル・データベースへの情報のエクスポート
  • 内部メモリーとローカル・データベースからの情報の読み取り
  • 保存された情報のクリア
  • 画面上への情報の表示

この記事では全体をとおして、以下のようにアプリケーションのローカル・ストアを利用します。

  • ユーザー・プリファレンスを取り込んでローカルに保存し、アプリケーション全体で使用します。
  • ローカルの内部メモリーまたは外部メモリーに保存されているアプリケーション内部のアセットから、ユーザーの画像を取得し、画面に描画します。
  • アプリケーションのアセットから友達のリストを JSON で取得します。友達のリストは構文解析された後、ローカルの内部メモリー、外部メモリー、リレーショナル・データベースに保存され、画面に描画されます。

このサンプル・アプリケーションには表 1 のクラスが定義されています。

表 1. サンプル・アプリケーションのクラス
クラス説明
MainActivityメインのアクティビティーが含まれるクラスであり、サンプル・コードの大部分はここにあります。
Friend友達を表します。
AppPreferenceActivityプリファレンス・アクティビティーとプリファレンス画面
DBHelperSQLite データベースを管理するためのヘルパー・クラス

このサンプル・アプリケーションでは 2 つのタイプのデータを使います。一方のタイプはアプリケーションのプリファレンスであり、名前と値のペアとして保存されています。プリファレンスに対しては、以下の情報を定義します。

  • ファイル名: 友達の名前のリストのロードと保存に使われます。
  • ファイル名: ユーザーの画像のロードと保存に使われます。
  • フラグ: セットされている場合には、保存されているすべてのデータは、アプリケーションの起動時に自動的に削除されます。

もう一方のタイプのデータは友達のリストです。友達のリストは最初、Facebook Graph API の JSON フォーマットで表現されています。このフォーマットは name オブジェクトと Friend オブジェクトの配列で構成されています (リスト 1)。

リスト 1. 友達のリスト (Facebook Graph API の JSON フォーマットで表現)
{
   "data": [
      {
         "name": "Edmund Troche",
         "id": "500067699"
      }
   ]
}

上記のフォーマットは単純なため、Friend オブジェクトとデータベース・スキーマは単純になります。リスト 2Friend クラスを示しています。

リスト 2. Friend クラス
package com.cenriqueortiz.tutorials.datastore;

import android.graphics.Bitmap;

/**
 * Represents a Friend
 */
public class Friend {
    public String id;
    public String name;
    public byte[] picture;
    public Bitmap pictureBitmap;;
}

ID と名前の他に、このサンプル・アプリケーションでは友達の画像への参照も保持します。サンプル・アプリケーションでは画像の参照を使用しませんが、サンプル・アプリケーションを拡張して Facebook から画像を取得し、メインの画面に表示させることは簡単です。

データベース・スキーマは Friend の情報を保存するための 1 つのテーブルで構成されています。このテーブルには以下の 3 列があります。

  • 一意の ID またはキー
  • Facebook の ID
  • Friend の名前

リスト 3 に、このリレーショナル・データベースのテーブルを宣言するための SQL 文を示します。

リスト 3. Friend データベース・テーブル
db.execSQL("create table " + TABLE_NAME + " (_id integer primary key autoincrement, " 
+ " fid text not null, name text not null) ");

これらの情報を基にメイン画面に名前を表示することや、ID を使用することで、選択したユーザーの詳細情報を追加で取得することができます。このサンプル・アプリケーションでは名前のみを表示します。追加で情報を取得する方法については、読者の皆さんが試すのにお任せします。また、直接 Facebook にアクセスするようにコードを変更するのも簡単です。


アプリケーションのプリファレンスを保存する

このセクションではプリファレンス API とプリファレンス画面について説明します。Android の API には、プリファレンスを扱う方法がいくつか用意されています。1 つの方法は、SharedPreferences を直接使用し、設計者独自の画面設計とプリファレンス管理を使用する方法です。また別の方法として、PreferenceActivity を使用する方法があります。PreferenceActivity を使用することで、自動的に画面へのプリファレンスの描画方法が指定されます (ただし、デフォルトのプリファレンスは、システムに設定されているプリファレンスと同様の表示になります)。またユーザーが SharedPreferences を使って各プリファレンスを操作すると、プリファレンスが自動的に保存されます。

サンプル・アプリケーションを単純にするために、PreferenceActivity を使ってプリファレンスと「Preferences (プリファレンス)」画面を管理します (図 2)。「Preferences (プリファレンス)」画面には、「Assets (アセット)」と「Auto Settings (自動設定)」という 2 つのセクションが表示されます。「Assets (アセット)」セクションでは、「Friends List (友達のリスト)」または「Picture (画像)」という選択肢に対してファイル名を入力することができます。「Auto Settings (自動設定)」セクションでは、チェックボックスを選択することによって起動時に情報を削除することができます。

図 2. 実装された「Preferences (プリファレンス)」画面
実装された「Preferences (プリファレンス)」画面のスクリーン・キャプチャー

図 2 では、レイアウトを (プログラムで行う代わりに) XML を使って宣言する方法で定義しています。XML を使って宣言する方が簡潔で読みやすいソース・コードになるため、望ましい方法となります。リスト 4 は「Preferences (プリファレンス)」画面の UI を XML で宣言する方法を示しています。

リスト 4. 「Preferences (プリファレンス)」画面の XML 宣言
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:id="@+id/prefs_screen"
        android:key="preferencescreen"
    >
    <PreferenceCategory android:title="Assets">
        <EditTextPreference 
            android:key="@string/prefs_assetname_friendslist_key"
            android:title="Friends List" 
            android:summary="Please enter filename"
            android:defaultValue="friends.txt"
        />
        <EditTextPreference 
            android:key="@string/prefs_assetname_picture_key"
            android:title="Picture" 
            android:summary="Please enter filename"
            android:defaultValue="pict2.jpg"
        />
    </PreferenceCategory>

    <PreferenceCategory android:title="Auto Settings">
        <CheckBoxPreference
            android:key="@string/prefs_autodelete_key"
            android:title="Delete at Startup" 
            android:summary="Check to clear at startup"
            android:defaultValue="false"
        />
    </PreferenceCategory>
</PreferenceScreen>

PreferenceScreen は、EditTextPreference の 2 つのインスタンスと CheckBoxPreference で構成されており、PreferenceCategory によって 2 つのカテゴリー・グループ (1 つは Asset、もう 1 つは Auto Settings) に分けられています。

サンプル・アプリケーションの設計では、メニュー項目を使って「Preferences (プリファレンス)」画面を呼び出す必要があります。そのために、Intent メッセージを使って AppPreferenceActivity というプリファレンス画面のアクティビティーを呼び出します (リスト 5)。この記事では Intent の動作の詳細については説明しません。Intent の詳細については「参考文献」を参照してください。

リスト 5. AppPreferenceActivity
/*
 * AppPreferenceActivity is a basic PreferenceActivity
 * C. Enrique Ortiz | http://CEnriqueOrtiz.com
 */
package com.cenriqueortiz.tutorials.datastore;

import android.os.Bundle;
import android.preference.PreferenceActivity;

public class AppPreferenceActivity extends PreferenceActivity {

    /**
     * Default Constructor
     */
    public AppPreferenceActivity() {}

   /** 
    * Called when the activity is first created. 
    *   Inflate the Preferences Screen XML declaration.
    */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.prefs); // Inflate the XML declaration
    }   

}

サンプル・アプリケーションでは、リスト 6 のようにメニュー項目ハンドラーの内部から Intent を呼び出します。

リスト 6. Intent を使ってプリファレンス・アクティビティーを呼び出す
/**
 * Invoked when a menu item has been selected
 */
@Override
public boolean onOptionsItemSelected(MenuItem item) {
    switch (item.getItemId()) {

        // Case: Bring up the Preferences Screen
        case R.id.menu_prefs: // Preferences
            // Launch the Preference Activity
            Intent i = new Intent(this, AppPreferenceActivity.class);
            startActivity(i);
            break;

        case R.id.menu...:
            :
            break;

    }
    return true;
}

また、AndroidManifest XML ファイルの中で、すべての Intent を定義する必要があります (リスト 7)。

リスト 7. AndroidManifest.xml で Intent を定義する
:

<application android:icon="@drawable/icon" android:label="@string/app_name">

    :
    :
    
    <activity 
        android:name="AppPreferenceActivity" 
        android:label="Preferences">
    </activity>  

     :

</application>

ユーザーが「Preferences (プリファレンス)」画面を操作すると、PreferenceActivitySharedPreferences を使ってプリファレンスを自動的に保存することを思い出してください。アプリケーションはさまざまなタスクを実行する際、これらのプリファレンスを使用します。リスト 8 は、保存されたプリファレンスを SharedPreferences を直接使ってロードする方法を示しています。ロードされたプリファレンスをサンプル・コードでどのように使用しているのかは、この記事に付属のサンプル・コードを参照してください。またリスト 8 には、(PrefenceActivity を使わずに) 皆さん自身がプリファレンスを管理しようとするときのために、SharedPreferencesEditor を使ってプリファレンスを直接保存する方法も示しています。

リスト 8 は、保存されたプリファレンスを SharedPreferences を使ってロードする方法と、保存されたプリファレンスを Editor を使って変更する方法を示しています。

リスト 8. SharedPreferences を使う
/////////////////////////////////////////////////////////////
// The following methods show how to use the SharedPreferences
/////////////////////////////////////////////////////////////

/**
 * Retrieves the Auto delete preference
 * @return the value of auto delete
 */
public boolean prefsGetAutoDelete() {
    boolean v = false;
    SharedPreferences sprefs = 
       PreferenceManager.getDefaultSharedPreferences(appContext); 
    String key = appContext.getString(R.string.prefs_autodelete_key);
    try {
        v = sprefs.getBoolean(key, false);
    } catch (ClassCastException e) {
    }
    return v;
}   

/**
 * Sets the auto delete preference
 * @param v the value to set
 */
public void  prefsSetAutoDelete(boolean v) {
    SharedPreferences sprefs = 
    PreferenceManager.getDefaultSharedPreferences(appContext); 
    Editor e = sprefs.edit();
    String key = appContext.getString(R.string.prefs_autodelete_key);               
    e.putBoolean(key, v);
    e.commit();
}

次は、データベースを使ってデータを保存する方法について説明します。


SQLite データベースを使う

Android は SQLite を使ったローカルのリレーショナル・データベースをサポートしています。(以下の一連のリストで定義される) テーブルは、サンプル・アプリケーションで使われる重要なデータベース・クラスの概要を示しています。

このサンプル・アプリケーションでは、DBHelper クラスを使ってデータベース操作の一部をカプセル化しています (リスト 9)。

リスト 9. DBHelper
package com.cenriqueortiz.tutorials.datastore;

import java.util.ArrayList;

import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;

public class DBHelper extends SQLiteOpenHelper {

データベースのバージョン、データベースの名前、テーブルの名前として、定数が定義されています (リスト 10)。

リスト 10. DBHelper を初期化する
    private SQLiteDatabase db;
    private static final int DATABASE_VERSION = 1;
    private static final String DB_NAME = "sample.db";
    private static final String TABLE_NAME = "friends";

    /**
     * Constructor
     * @param context the application context
     */
    public DBHelper(Context context) {
        super(context, DB_NAME, null, DATABASE_VERSION);
        db = getWritableDatabase();
    }

データベースを作成する準備ができると onCreate() メソッドが呼び出されます。このメソッドの中でテーブルが作成されます (リスト 11)。

リスト 11. データベース・テーブルを作成する
    /**
     * Called at the time to create the DB.
     * The create DB statement
     * @param the SQLite DB
     */
    @Override
    public void onCreate(SQLiteDatabase db) {
        db.execSQL(
                "create table " + TABLE_NAME + " (_id integer primary key autoincrement, 
" + " fid text not null, name text not null) ");
    }

insert() メソッドは MainActivity によってデータベースに情報がエクスポートされるときに呼び出されます (リスト 12)。

リスト 12. 行を挿入する
    /**
     * The Insert DB statement
     * @param id the friends id to insert
     * @param name the friend's name to insert
     */
    public void insert(String id, String name) {
        db.execSQL("INSERT INTO friends('fid', 'name') values ('"
                + id + "', '"
                + name + "')");
    }

clearAll() メソッドは MainActivity によってデータベースの内容がクリアされるときに呼び出されます (リスト 13)。

リスト 13. データベース・テーブルを削除する
    /**
     * Wipe out the DB
     */
    public void clearAll() {
        db.delete(TABLE_NAME, null, null);
    }

SELECT ALL を実行するメソッドとしては、cursorSelectAll()listSelectAll() の 2 つが用意されています。cursorSelectAll() はカーソルを返し、listSelectAll() は Friend オブジェクトの ArrayList を返します。これらのメソッドは、MainActivity によってデータベースから情報がロードされるときに呼び出されます (リスト 14)。

リスト 14. Select All を実行して ArrayList を返す
    /**
     * Select All returns a cursor
     * @return the cursor for the DB selection
     */
    public Cursor cursorSelectAll() {
        Cursor cursor = this.db.query(
                TABLE_NAME, // Table Name
                new String[] { "fid", "name" }, // Columns to return
                null,       // SQL WHERE
                null,       // Selection Args
                null,       // SQL GROUP BY 
                null,       // SQL HAVING
                "name");    // SQL ORDER BY
        return cursor;
    }

listSelectAll() メソッドは ArrayList コンテナー内部の選択された行を返します。この選択された行は MainActivity によってメイン画面の ListView にバインドされます (リスト 15)。

リスト 15. Select All を実行してカーソルを返す
    /**
     * Select All that returns an ArrayList
     * @return the ArrayList for the DB selection
     */
    public ArrayList<Friend> listSelectAll() {
        ArrayList<Friend> list = new ArrayList<Friend>();
        Cursor cursor = this.db.query(TABLE_NAME, new String[] { "fid", "name" }, 
null, null, null, null, "name");
        if (cursor.moveToFirst()) {
            do {
                Friend f = new Friend();
                f.id = cursor.getString(0);
                f.name = cursor.getString(1);
                list.add(f);
            } while (cursor.moveToNext());
        }
        if (cursor != null && !cursor.isClosed()) {
            cursor.close();
        }
        return list;
    }

onUpgrade() メソッドはデータベースのバージョンの変更が検出されると呼び出されます (リスト 16)。

リスト 16. データベースのバージョンの変更を検出する
    /**
     * Invoked if a DB upgrade (version change) has been detected
     */
    @Override
    /**
     * Invoked if a DB upgrade (version change) has been detected
     */
    @Override
    public void onUpgrade(SQLiteDatabase db, 
       int oldVersion, int newVersion) {
        // Here add any steps needed due to version upgrade
        // for example, data format conversions, old tables 
        // no longer needed, etc
    }
}

MainActivity が実行される間、DBHelper が使われるのは、データベースに情報をエクスポートするとき、データベースから情報をロードするとき、そしてデータベースをクリアするときです。MainActivity を作成するときには、まず DBHelper をインスタンス化します。onCreate() によって実行される他のタスクには、さまざまな画面のビューの初期化などがあります。

リスト 17. MainActivity の onCreate() によってデータベースを初期化する
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    appContext = this;
    setContentView(R.layout.main);
    dbHelper = new DBHelper(this);
    listView = (ListView) findViewById(R.id.friendsview);
    friendsArrayAdapter = new FriendsArrayAdapter(
       this, R.layout.rowlayout, friends);
    listView.setAdapter(friendsArrayAdapter);
    :
    :
}

リスト 18 は、アセットから友達のリストをロードして構文解析し、データベースに挿入する方法を示しています。

リスト 18. MainActivity によってデータベースに挿入する
String fname = prefsGetFilename();
if (fname != null && fname.length() > 0) {
    buffer = getAsset(fname);
    // Parse the JSON file
    String friendslist = new String(buffer);
    final JSONObject json = new JSONObject(friendslist);
    JSONArray d = json.getJSONArray("data");
    int l = d.length();
    for (int i2=0; i2<l; i2++) {
        JSONObject o = d.getJSONObject(i2);
        String n = o.getString("name");
        String id = o.getString("id");
        dbHelper.insert(id, n);
    }
    // Only the original owner thread can touch its views                           
    MainActivity.this.runOnUiThread(new Runnable() {
        public void run() {
            friendsArrayAdapter.notifyDataSetChanged();
        }
    });         
}

リスト 19SELECT ALL の実行方法と、メイン画面の ListView にデータをバインドする方法を示しています。

リスト 19. MainActivitySelect All によって ListView にデータをバインドする
final ArrayList<Friend> dbFriends = dbHelper.listSelectAll();
if (dbFriends != null) {
    // Only the original owner thread can touch its views                           
    MainActivity.this.runOnUiThread(new Runnable() {
        public void run() {
            friendsArrayAdapter = 
            new FriendsArrayAdapter(
                MainActivity.this, R.layout.rowlayout, dbFriends);
            listView.setAdapter(friendsArrayAdapter);
            friendsArrayAdapter.notifyDataSetChanged();
        }
    });
}

次は、サンプル・アプリケーションで内部ストレージ API を使用する方法について調べてみましょう。


機器の内部ストレージを利用してプライベート・データを保存する

データ・ストレージ API を使用すると、内部ストレージを使ってデータを保存することができます。プライベートな情報も保存することができ、その情報への読み取りアクセスまたは書き込みアクセスを他のアプリケーションに許可することもできます。このセクションではデータ・ストレージ API の説明として、android.content.Context.openFileInputandroid.content.Context.openFileOutput を使ってプライベート・データを保存する方法と、データを永続的に保存する代わりに getCacheDir() を使ってキャッシュする方法について説明します。

リスト 20 に示すスニペットは内部のプライベート・ストアに書き込む方法を示しています。ストレージをプライベートにするためには openFileOutput() を使用し、MODE_PRIVATE を指定します。

リスト 20. ローカルのプライベート・ストアに書き込む
/**
 * Writes content to internal storage making the content private to 
 * the application. The method can be easily changed to take the MODE 
 * as argument and let the caller dictate the visibility: 
 * MODE_PRIVATE, MODE_WORLD_WRITEABLE, MODE_WORLD_READABLE, etc.
 * 
 * @param filename - the name of the file to create
 * @param content - the content to write
 */
public void writeInternalStoragePrivate(
        String filename, byte[] content) {
    try {
        //MODE_PRIVATE creates/replaces a file and makes 
        //  it private to your application. Other modes:
        //    MODE_WORLD_WRITEABLE
        //    MODE_WORLD_READABLE
        //    MODE_APPEND
        FileOutputStream fos = 
           openFileOutput(filename, Context.MODE_PRIVATE);
        fos.write(content);
        fos.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

リスト 21 のスニペットは内部のプライベート・ストアから読み取る方法を示しています。openFileInput() が使われていることに注意してください。

リスト 21. ローカルのプライベート・ストアから読み取る
/**
 * Reads a file from internal storage
 * @param filename the file to read from
 * @return the file content
 */
public byte[] readInternalStoragePrivate(String filename) {
    int len = 1024;
    byte[] buffer = new byte[len];
    try {
        FileInputStream fis = openFileInput(filename);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        int nrb = fis.read(buffer, 0, len); // read up to len bytes
        while (nrb != -1) {
            baos.write(buffer, 0, nrb);
            nrb = fis.read(buffer, 0, len);
        }
        buffer = baos.toByteArray();
        fis.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return buffer;
}

リスト 22 は内部のプライベート・ストアから削除する方法を示しています。

リスト 22. ローカルのプライベート・ストアから削除する
/**
 * Delete internal private file 
 * @param filename - the filename to delete
 */
public void deleteInternalStoragePrivate(String filename) {
    File file = getFileStreamPath(filename);
    if (file != null) {
        file.delete();
    }
}

今度はパブリック・データを、外部ストレージを使って保存する方法について説明します。


機器の外部ストレージを利用してパブリック・データを保存する

データ・ストレージ API を使用すると、外部ストレージを使ってデータを保存することができます。プライベートな情報も保存することができ、その情報への読み取りアクセスまたは書き込みアクセスを他のアプリケーションに許可することもできます。このセクションでは、パブリック・データを保存するための API のコーディング方法として、getExternalStorageState()getExternalFilesDir()getExternalStorageDirectory()getExternalStoragePublicDirectory() などについて説明します。パブリック・データへのパスとしては、/Android/data/<パッケージ名>/files/ を使用します。

外部ストレージを使う前に、外部ストレージが利用できるかどうか、そして外部ストレージが書き込み可能であるかどうかを調べる必要があります。以下の 2 つのコード・スニペットは、それらの条件をテストするためのヘルパー・メソッドです。リスト 23 は外部ストレージが利用できるかどうかをテストします。

リスト 23. 外部ストレージが利用できるかどうかをテストする
/**
 * Helper Method to Test if external Storage is Available
 */
public boolean isExternalStorageAvailable() {
    boolean state = false;
    String extStorageState = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED.equals(extStorageState)) {
        state = true;
    }
    return state;
}

リスト 24 は外部ストレージが読み取り専用かどうかをテストします。

リスト 24. 外部ストレージが読み取り専用かどうかをテストする
/**
 * Helper Method to Test if external Storage is read only
 */
public boolean isExternalStorageReadOnly() {
    boolean state = false;
    String extStorageState = Environment.getExternalStorageState();
    if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(extStorageState)) {
        state = true;
    }
    return state;
}

リスト 25 はパブリック・データを外部ストレージに書き込む方法を示しています。

リスト 25. 外部ストレージに書き込む
/**
 * Write to external public directory
 * @param filename - the filename to write to
 * @param content - the content to write 
 */
public void writeToExternalStoragePublic(String filename, byte[] content) {

    // API Level 7 or lower, use getExternalStorageDirectory() 
    //  to open a File that represents the root of the external 
    // storage, but writing to root is not recommended, and instead 
    // application should write to application-specific directory, as shown below.

    String packageName = this.getPackageName();
    String path = "/Android/data/" + packageName + "/files/";

    if (isExternalStorageAvailable() && 
       !isExternalStorageReadOnly()) {
        try {
            File file = new File(path, filename);
            file.mkdirs();
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(content);
            fos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

リスト 26 は外部ストレージから読み取る方法を示しています。

リスト 26. 外部ストレージから読み取る
/**
 * Reads a file from internal storage
 * @param filename - the filename to read from
 * @return the file contents
 */
public byte[] readExternallStoragePublic(String filename) {
    int len = 1024;
    byte[] buffer = new byte[len];
    String packageName = this.getPackageName();
    String path = "/Android/data/" + packageName + "/files/";

    if (!isExternalStorageReadOnly()) {     
        try {
            File file = new File(path, filename);            
            FileInputStream fis = new FileInputStream(file);
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            int nrb = fis.read(buffer, 0, len); //read up to len bytes
            while (nrb != -1) {
                baos.write(buffer, 0, nrb);
                nrb = fis.read(buffer, 0, len);
            }
            buffer = baos.toByteArray();
            fis.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    return buffer;
}

リスト 27 のスニペットは外部ストレージからファイルを削除する方法を示しています。

リスト 27. 外部ストレージからファイルを削除する
/**
 * Delete external public file 
 * @param filename - the filename to write to
 */
void deleteExternalStoragePublicFile(String filename) {
    String packageName = this.getPackageName();
    String path = "/Android/data/" + packageName + "/files/"+filename;
    File file = new File(path, filename);
    if (file != null) {
        file.delete();
    }
}

外部ストレージを操作するためには特別なアクセス権 (WRITE_EXTERNAL_STORAGE) が必要です。このアクセス権を要求するためには AndroidManifest.xml を使用します (リスト 28)

リスト 28. WRITE_EXTERNAL_STORAGE
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

外部ストレージ API を利用すると、ファイルはタイプ (Pictures、Ringtones など) に応じて、あらかじめ定義されているディレクトリーに保存され、誰もがそのファイルを利用できるようになります。この記事では説明しませんが、その方法については理解しておく必要があります。また、外部ストレージに保存されたデータはいつでも消去される可能性があることを忘れないでください。


関連するメソッド

長期間永続化する必要のない一時ファイルがある場合、それらの一時ファイルをキャッシュに保存することができます。キャッシュは (1 メガバイト未満の) 中程度または小さなデータの保存に便利な特殊なメモリーです。ただし、利用可能なメモリー量によっては、キャッシュの内容はいつでもパージされる可能性があることを忘れてはなりません。

リスト 29 は、内部メモリーの中にあるキャッシュへのパスを返すヘルパー・メソッドを示しています。

リスト 29. 内部メモリーの中にあるキャッシュへのパスを取得する
/**
 * Helper method to retrieve the absolute path to the application 
 * specific internal cache directory on the file system. These files 
 * will be ones that get deleted when the application is uninstalled or when 
 * the device runs low on storage. There is no guarantee when these 
 * files will be deleted.
 * 
 * Note: This uses a Level 8+ API.
 * 
 * @return the absolute path to the application specific cache 
 * directory
 */
public String getInternalCacheDirectory() {
    String cacheDirPath = null;
    File cacheDir = getCacheDir();
    if (cacheDir != null) {
        cacheDirPath = cacheDir.getPath();
    }
    return cacheDirPath;        
}

リスト 30 は外部メモリーの中にあるキャッシュへのパスを返すヘルパー・メソッドを示しています。

リスト 30. 外部メモリーの中にあるキャッシュへのパスを取得する
/**
 * Helper method to retrieve the absolute path to the application 
 * specific external cache directory on the file system. These files 
 * will be ones that get deleted when the application is uninstalled or when 
 * the device runs low on storage. There is no guarantee when these 
 * files will be deleted.
 * 
 * Note: This uses a Level 8+ API.
 * 
 * @return the absolute path to the application specific cache 
 * directory
 */
public String getExternalCacheDirectory() {
    String extCacheDirPath = null;
    File cacheDir = getExternalCacheDir();
    if (cacheDir != null) {
        extCacheDirPath = cacheDir.getPath();
    }
    return extCacheDirPath;     
}

パブリック・データを機器の外部ストレージを利用して保存する方法について、ここまでのサンプル・アプリケーションを使った説明で十分理解できたことと思います。


まとめ

この記事では Android のストレージ API について、プリファレンスから始まり、SQLite、内部メモリー、外部メモリーの使い方に至るまで説明しました。これらのプリファレンス API を利用すると、アプリケーションは単純なプリファレンス情報を収集、保存することができます。SQLite API を利用すると、さらに複雑なデータを保存することができ、また外部ストレージと内部ストレージを利用することにより、そのアプリケーションでしか利用できないようにファイルを保存したり、あるいは他のアプリケーションからも利用できるようにファイルを保存したりすることができます。セッションにまたがってデータを永続的に保存すると、アプリケーションはネットワークに接続されていない場合にも動作することができます。この記事で身につけた知識を使えば、こうしたあらゆる種類のストレージを Android アプリケーションの開発に活用できるはずです。


ダウンロード

内容ファイル名サイズ
Article source codeandroid.storage.source.zip38KB

参考文献

学ぶために

  • Facebook の Mobile Applications のページを訪れてください。携帯電話に合わせてフォーマット設定され、あらゆる Web サイトで利用できるように用意されている API と同じ API を使用して、皆さん自身のモバイル・アプリケーションに Facebook を組み込む方法を学んでください。
  • Facebook 開発者のページで皆さんの Facebook アプリケーションを登録してください。
  • Facebook 開発者用のドキュメント、Extended Permissions を調べ、ユーザーのプライベート・プロファイル部分にアプリケーションからアクセスする必要がある場合、あるいはユーザーに代わってアプリケーションによってコンテンツを Facebook に公開する必要がある場合に拡張パーミッションを要求する方法を学んでください。
  • Facebook 開発者用の公式ドキュメントを調べ、Facebook の強力な API を活用してください。これらの API により、皆さんの Web サイトの成長と活躍を促すソーシャル・エクスペリエンスを実現することができます。
  • Facebook Authentication のページを訪れ、Facebook プラットフォームを使ってアプリケーションを開発する際の認証と承認について学んでください。
  • Facebook 開発者ロードマップを利用して、コードの変更が必要となる変更への計画を立ててください。
  • Develop Android applications with Eclipse」(Frank Ableson 著、developerWorks、2008年2月) を読んでください。Android アプリケーションを開発するために最も容易な方法は Eclipse を使う方法です。この developerWorks チュートリアルでは、そのためのすべてを学ぶことができます。
  • Android 開発入門」(Frank Ableson 著、developerWorks、2009年5月) では、Android プラットフォームを紹介し、基本的な Android アプリケーションのコーディング方法を説明しています。
  • Android によるネットワーキング」(Frank Ableson 著、developerWorks、2009年6月) を読み、Android のネットワーク機能を学んでください。
  • Android で XML を扱う」(Michael Galpin 著、developerWorks、2009年6月) を読み、Android で XML を処理するためのさまざまなオプションと、それらのオプションを使って独自の Android アプリケーションを作成する方法を学んでください。
  • Under the Hood of Native Web Apps for Android」を読み、Android でハイブリッド・アプリケーションを作成する方法を学んでください。
  • Unlocking Android』(Frank Ableson 著、2010年 Manning Publications 刊) には Android 開発のすべての側面が説明されています。
  • Mobile Design and Development』(Brian Fling 著、2009年 O'Reilly Media 刊) を読み、モバイル製品を作成するための実用的なガイドライン、技術標準、手法、ベスト・プラクティスについて学んでください。
  • Android developers サイトで Data Storage の項目を読み、アプリケーションのデータを永続化するための適切な方法を選択してください。
  • Android developers サイトで Intent の項目を読み、実行すべき操作を抽象化して記述する方法を学んでください。
  • Android SDK のドキュメントから Android API に関する最新情報を入手することができます。
  • Android のスポンサーである、Open Handset Alliance のホームページを訪れてください。
  • この著者による他の記事を読んでください (C. Enrique Ortiz 著、developerWorks、2004年7月から現在まで)。Android、モバイル・アプリケーション、Web サービス、その他の技術についての記事が公開されています。
  • developerWorks の XML ゾーンで XML に関するスキルを向上するためのリソースを入手してください。
  • My developerWorks で developerWorks のエクスペリエンスをパーソナライズしてください。
  • XML および関連技術において IBM 認定技術者になる方法については、IBM XML certification を参照してください。
  • developerWorks の XML ゾーンを XML の技術ライブラリーとして利用してください。広範な話題を網羅した技術記事やヒント、チュートリアル、技術標準、IBM Redbooks などが用意されています。また、他にも XML に関するヒント記事があります。
  • developerWorks の Technical events and webcasts で最新情報を入手してください。
  • 今すぐ Twitter に参加して developerWorks のツイートをフォローしてください。
  • developerWorks podcasts でソフトウェア開発者のための興味深いインタビューや議論を聞いてください。
  • developerWorks On demand demos をご覧ください。初心者のための製品インストール方法やセットアップのデモから、上級開発者のための高度な機能に至るまで、多様な話題が解説されています。

製品や技術を入手するために

  • Facebook SDK for Android (現在はアルファ・リリース) を利用して Facebook を Android モバイル・アプリケーションに組み込んでください。
  • Facebook プラットフォームを利用して、Facebook と Web でのソーシャル・アプリケーション構築スキルを磨いてください。
  • Facebook の Old Rest API (Graph API の前のバージョン) を利用すると、単純な HTTP リクエストを使って Facebook Web サイトとプログラムでやり取りすることができます。
  • Facebook プラットフォームのコア API、Facebook Graph API (最新バージョン) を詳しく調べてください。
  • OAuth 2.0 プロトコル仕様 (2010年7月) を調べ、Facebook プラットフォームでサポートされている OAuth 認証を活用してください。
  • 公式な Android developers サイトを訪れ、Android SDK をダウンロードし、API の資料にアクセスし、また Android に関する最新ニュースを入手してください。バージョン 1.5 またはそれ以降であれば構いません。
  • Android open source project のサイトを訪れ、Android 互換の機器を作成するために必要なオープンソース情報とソース・コードを見つけてください。
  • Java Platform, Standard Edition の最新版、JDK 6 Update 21 を入手してください。
  • 最新の Eclipse IDE を入手してください。
  • IBM 製品の評価版をダウンロードするか、あるいは IBM SOA Sandbox のオンライン試用版で、DB2®、Lotus®、Rational®、Tivoli®、WebSphere® などが提供するアプリケーション開発ツールやミドルウェア製品を試してみてください。

議論するために

コメント

developerWorks: サイン・イン

必須フィールドは(*)で示されます。


IBM ID が必要ですか?
IBM IDをお忘れですか?


パスワードをお忘れですか?
パスワードの変更

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


お客様が developerWorks に初めてサインインすると、お客様のプロフィールが作成されます。会社名を非表示とする選択を行わない限り、プロフィール内の情報(名前、国/地域や会社名)は公開され、投稿するコンテンツと一緒に表示されますが、いつでもこれらの情報を更新できます。

送信されたすべての情報は安全です。

ディスプレイ・ネームを選択してください



developerWorks に初めてサインインするとプロフィールが作成されますので、その際にディスプレイ・ネームを選択する必要があります。ディスプレイ・ネームは、お客様が developerWorks に投稿するコンテンツと一緒に表示されます。

ディスプレイ・ネームは、3文字から31文字の範囲で指定し、かつ developerWorks コミュニティーでユニークである必要があります。また、プライバシー上の理由でお客様の電子メール・アドレスは使用しないでください。

必須フィールドは(*)で示されます。

3文字から31文字の範囲で指定し

「送信する」をクリックすることにより、お客様は developerWorks のご使用条件に同意したことになります。 ご使用条件を読む

 


送信されたすべての情報は安全です。


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=60
Zone=XML, Open source
ArticleID=607210
ArticleTitle=Android のローカル・データ・ストア API を理解する
publish-date=11302010