このページの本文へ

これで作れる! Androidのアプリケーション 第7回

Androidアプリの設定画面を作成する

2010年08月12日 18時00分更新

文● 塩田紳二

  • この記事をはてなブックマークに追加
  • 本文印刷

WorldClockでの設定画面の処理を詳しく見る

 実際に設定画面の処理はどうなるのでしょうか。

サンプルプログラムである世界時計のメイン画面。都市名とともに4つ並んでいるのが「アイテム」でひとつひとつ都市名と現在時刻が表示される。また背景は時間によって変わるようになっている

 まずは呼び出すところですが、これはメニューの処理ルーチン内にあります。以下に示した265行目で呼び出しているsettingが設定画面に移行するルーチンです。

public boolean onOptionsItemSelected(MenuItem item) {
  switch (item.getItemId()) {
  case MENU_ITEM_ADD:
    additem();
    break;
  case MENU_ITEM_SET:
    setting();
    break;
  case MENU_ITEM_DTSET:
    setsystemdate();
    break;
  case MENU_ITEM_END:
    endApp();
    break;
  }
  return true;
}

 以下の関数は、MyPrefsクラスを呼び出すインテントになっており、結果を受け取るタイプ(startActivityForResult)です。

private void setting(){
  Intent intent = new Intent(this,
    com.tyrell_replicants.worldclock.MyPrefs.class);
  startActivityForResult(intent,Intent_Setting);
}

 MyPrefsクラスは、以下のMyPrefs.javaファイルで定義されており、かなり簡単なコードでしかありません。

package com.tyrell_replicants.worldclock;
import com.tyrell_replicants.worldclock.R;
import android.os.Bundle;
import android.preference.PreferenceActivity;

public class MyPrefs extends PreferenceActivity {
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    addPreferencesFromResource(R.xml.preferences);
    setResult(RESULT_OK,null);
  }

 ここでやっているのは、以下のxmlファイルから画面を作り出して、表示させているだけです。前述のように画面上で行われた操作により、設定値は自動的に変更されるので、ここでは何もする必要がないのです。

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
  xmlns:android="http://schemas.android.com/apk/res/android"
  android:orderingFromXml="true">
  <PreferenceCategory android:title="@string/prefs_title">
    <ListPreference android:entryValues="@array/timeformatvalue"
      android:entries="@array/timeformat"
      android:title="@string/prefs_format_title"
      android:dialogTitle="@string/prefs_format_title"
      android:key="@string/prefs_format"
      android:summary="@string/prefs_format_summary">
      </ListPreference>
    <CheckBoxPreference android:title="@string/prefs_second_title"
      android:summary="@string/prefs_second_summary"
      android:summaryOn="@string/prefs_second_on"
      android:summaryOff="@string/prefs_second_off"
      android:key="@string/prefs_second">
      </CheckBoxPreference>
    <CheckBoxPreference android:title="@string/prefs_background_title"
      android:summary="@string/prefs_backGround_summary"
      android:summaryOn="@string/prefs_background_on"
      android:summaryOff="@string/prefs_background_off"
      android:key="@string/prefs_background">
      </CheckBoxPreference>
    <CheckBoxPreference android:title="@string/prefs_home1st_title"
      android:summary="@string/prefs_home1st_summary"
      android:key="@string/prefs_home1st"
      android:summaryOn="@string/prefs_home1st_summary_on"
      android:summaryOff="@string/prefs_home1st_summary_off">
      </CheckBoxPreference>
  </PreferenceCategory>
</PreferenceScreen>

 具体的には、MyPrefsクラスは、「PreferencesActivity」を継承しています。これは、設定画面専用のアクティビティです。定義しているメソッドはonCreate1つだけです。この中では、「addPreferencesFromResurce」メソッドでxmlファイルを使って画面を構築させています。xmlファイルでは、設定用のパーツが定義されていて、設定値は自動的に保存され、ユーザーは、コードを書いて何かをする必要がありません。通常の設定であれば、これだけで済みます。

 設定値は、必ずしも設定画面だけで書き込むとは限りません。Preferenceオブジェクトは、基本的には、アプリケーションの状態などを保存し、次回起動したときに状態を再現するといった用途にも利用されます。

設定値の参照と書き込み

 WorldClockでは起動時に設定値を参照しています。場所は前回(関連記事)のサンプルファイルに含まれる、workdClock.javaの92行目付近からです。

myPrefs = PreferenceManager.getDefaultSharedPreferences(this);
bgcolor = myPrefs.getBoolean(this.getString(R.string.prefs_background), true);
localTimeFormat = localTimeFormatSelect(myPrefs);
if (myPrefs.getString(myS(R.string.prefs_format), "f24").equals("f24")) {
  timeformat = myS(R.string.f24);
} else {
  timeformat = myS(R.string.f12);
}

 手順としては、PreferenceManagerを使って、自分自身の設定値を取り出します。これに対して、getXXXXを使って文字列や真偽値を取り出します。たとえば文字列を取り出すには、getStringメソッドを使い、

myPrefs.getString(KEY_String,Defaut_Value);

とします。ここで「KEY_String」は、値を保存するときに使った文字列キーで、xmlファイルでは、keyとして定義した文字列になります。前述したように、keyをids.xmlによる文字列リソースとして定義したので、参照するときには、文字列リソースのIDである「R.string.xxxx」を使い「this.getString(R.string.xxxx)」とします。この記述が面倒なので、mySという関数を作ってあります。

 Default_valueは、万一、キーに対して値が設定されていなかった。あるいはキー自体が未定義だった場合に戻す値です。このパラメータがあるため、このmyPrefsに対するgetXXXXメソッドは、ヌル値や初期化されていない値が帰ってくる心配をする必要がありません。

 Preferenceに値を書き込む手順は少し複雑です。参照(読み出し)と同じくPreferenceを取得し、さらに書き込み処理を行なうEditorオブジェクトを取得します。そのあと、editorオブジェクトのputStringやputBooleanといったメソッドを使って、Preferenceに書き込み、最後にEditorオブジェクトのcommitメソッドを実行します。

 WorldClock内部では、save_allという関数(worldclock.javaの507行目)の中で書き込みを行なっています。

private void save_all(){
  SharedPreferences p= PreferenceManager.getDefaultSharedPreferences(this);
  SharedPreferences.Editor edit = p.edit();
  Map<String,?> ad = (Map<String, ?>) p.getAll();
  String strname = this.getString(R.string.Prefs_itemName);
  for(String k:ad.keySet()){
    if (k.contains(strname)){
      String n = (String) k.subSequence(strname.length(), k.length());
      edit.remove(k);
      edit.remove(this.getString(R.string.Prefs_itemID)+n);
      edit.remove(this.getString(R.string.Prefs_itemHome)+n);
    }
  }
  int i = 0;
  for(TzItem t:items){
    edit.putString(this.getString(R.string.Prefs_itemName)
      +Integer.toString(i) , t.mTZ.mName);
    edit.putString(this.getString(R.string.Prefs_itemID)
      +Integer.toString(i) , t.mTZ.mTimeZoneID);
    edit.putBoolean(this.getString(R.string.Prefs_itemHome)
      +Integer.toString(i) , t.mHome);
    i++;
    }
  edit.commit();
}

 このWorldClockでは、アイテムと呼ぶ、各タイムゾーンの時刻表示に関する情報を保存しています。情報としては「都市名」「タイムゾーンID」「ホームフラグ」の3つがあります。また、Preferenceオブジェクトは、キーとなる文字列を渡して値を取得する方式になっています。このため、各アイテムは「itemName0」「itemID0」「itemHome0」などと名前と数字を組み合わせた3つのデータになっています。もしアイテムが1つ削除されると、同じ番号を持つ、この3つのデータを消さねばなりません。

 実際には、どのアイテムが消されるのかはユーザーの操作次第で、書き込むときには、数字を詰めて書き込む必要があるため、大きな数字のアイテム情報を残さないように、最初に最初にすべてのアイテムデータを消し、その後で、すべてのアイテム情報を書き込むようにしています。

 Preferenceに登録された情報をすべて取得するにはgetAllメソッドを使います。その戻り値は、MAPオブジェクト(キーと値を組にした構造)になります。このMAPオブジェクトに対して、「itemName」という文字列(リソースとしてはR.string.Prefs_itemName)を含むキーを探し、数字の不可された正しいPreferenceオブジェクトのキーを得て、同じ数字を持つ他のPreferenceオブジェクトのキー(itemIDXとitemHomeX)を削除するようにしています。

カテゴリートップへ

この連載の記事

注目ニュース

ASCII倶楽部

プレミアムPC試用レポート

ピックアップ

ASCII.jp RSS2.0 配信中

ASCII.jpメール デジタルMac/iPodマガジン