Android、Java、Web系、Linux、マラソン等の備忘録

2012/11/07

Enumの使い方メモ

0 件のコメント
今まであまりEnumを使う機会はなかったのですが、ちょっと調べたらこれは見やすなって事でメモしておきます。Androidに限った話ではないですが、Androidっぽさも交えながらサンプルを作りました。サンプルの特徴としては、以下の3点です。
  1. Enumの定義でswitch文を判定できる
  2. Enumの定義とstring.xmlのデータを紐付ける
  3. Enumの定義した順番で欲しい場合はvalues()メソッドで
特に何か意味のある実用的なサンプルではありませんが、上記特徴を表すために....

1は言わずと知れたことですが、それに加えてと2に関して。例えば以下のようなエラーコードとエラーのメッセージを取得できるように定義したとします。

public enum ResultCode {

    // エラーコード,エラーメッセージのID
    OK(200, R.string.result_code_ok),
    ERROR_FORBIDDEN(403, R.string.result_error_fobidden),
    ERROR_NOTFOUND(404, R.string.result_error_notfound),
    ERROR_INTERNAL_SERVER(503, R.string.result_error_internalserver),
    ERROR_UNKNOWN(999, R.string.result_error_unknown),;

    int code,id;
    ResultCode(int code, int id) {
        this.code = code;
        this.id = id;
    }

    // idからエラーメッセージを取得して返す
    public String getMessage(Resources r) {
        return r.getString(id);
    }

    // エラーコードを返す
    public int getErrorCode() {
        return this.code;
    }
}

これを任意のメソッドの戻り値として利用することができます。こんな感じで

    public ResultCode function() {
     
     String page_content = null;
     
     // .....
     
     if(null == page_content) {
      return ResultCode.ERROR_NOTFOUND;
     }
     
     return ResultCode.OK;
    }



呼び出し元の戻り値ではgetErrorCodeでエラーコードを取得でき、getMessageでエラーメッセージを取得できます。エラーメッセージは、getMessageメソッドでstrings.xml経由で定義したIDから文字列に変換する工夫がしてあります。こうしておけば、多言語対応にも便利です。

switch文の判定には、前述の通り直接シンボル名で判定できます。下記サンプルは先ほどのエラーをswitch文で判定してメッセージ(Toast)の表示方法を分岐しています。ERROR_FORBIDDENの場合のメッセージはこんな感じで画面に




    private void dispErrorMessage(ResultCode result) {

        Resources resources = this.getResources();

        switch(result) {
        // ResultCode型として判定できる↓
        case OK:
            // なにもしない
            break;
        case ERROR_FORBIDDEN:
        case ERROR_NOTFOUND:
        case ERROR_INTERNAL_SERVER:
            // エラーを画面に表示
            String error_message = result.getErrorCode() + ":" + result.getMessage(resources);
            Toast.makeText(this, error_message, Toast.LENGTH_SHORT).show();
            break;
        default:
            Toast.makeText(this, ResultCode.ERROR_UNKNOWN.getMessage(resources), Toast.LENGTH_LONG).show();
            break;
        }
    }

で、特徴の3つめですが、例えばEnumで定義したものをspinnerウィジェットへ表示させている場合、spinnerでは何番目が選択されかを返しますが、それがEnumで定義したどれに当たるか知りたい時があるかもしれません。その時に、Enumの定義をvalues()メソッドで配列として取得できるので、この配列の何番目かを見れば紐付けられます。

サンプルでは、spinnerウェジェットに表示されているいずれかのスイーツを選択すると、Toastに値段を表示するものです。






Enumの定義

public enum Sweets {

    // スイーツ名, 値段
    ECLAIR(R.string.spin_product_name_eclair, R.string.spin_product_price_eclair),
    FROZEN_YOGURT(R.string.spin_product_name_froyo, R.string.spin_product_price_froyo),
    GINGERBREAD(R.string.spin_product_name_gingerbread, R.string.spin_product_price_gingerbread),
    ICE_CREAM_SANDWICH(R.string.spin_product_name_ics, R.string.spin_product_price_ics);

    int id_name,id_price;
    Sweets(int id_name, int id_price) {
        this.id_name = id_name;
        this.id_price = id_price;
    }

    public String getName(Resources r) {
        return r.getString(this.id_name);
    }

    public String getPrice(Resources r) {
        return r.getString(this.id_price);
    }
}

spinner側の処理

        Resources resources = this.getResources();

        final Sweets[] values = Sweets.values();
        ArrayAdapter<String> adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item);
        adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

        // アイテムを追加します
        for(Sweets value : values) {
            adapter.add(value.getName(resources));
        }
        Spinner spinner = (Spinner) findViewById(R.id.spinner1);
        // アダプターを設定します
        spinner.setAdapter(adapter);
        spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
            @Override
            public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
                Resources resources = MainActivity.this.getResources();

                String message = "値段:" + values[position].getPrice(resources);
                Toast.makeText(MainActivity.this, message, Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onNothingSelected(AdapterView<?> arg0) {}
        });



onItemSelectedはspinnerの項目が選択されたタイミングで実行されます。Sweetsのvalues()で取得される配列とそのメソッドで渡されるpositionで紐付けてものをgetPriceをする事で値段の文字列を取得しています。

上記の全ソースはGithubへアップしました。

takaiwa/EnumSample · GitHub

追記:2012/11/08


onItemSelected内のようなpositionが得られる場面でswitch文を使う場合

switch(values[position]) {
case ECLAIR:
    break;
case FROZEN_YOGURT:
    break;
case GINGERBREAD:
    break;
case ICE_CREAM_SANDWICH:
    break;

}

追記:2013/06/13
入れ子を表現

文字列で定義
public enum Baz{
  yin("yang"),    
  yang("yin"),
  good("evil"),   
  evil("good");

  private String opposite;

  Baz(String opposite){
    this.opposite = opposite;
  }

  public Baz getOpposite(){
     return Baz.valueOf(opposite);
  }
}

switch文で定義
public enum Baz{
  yin,
  yang,
  good,
  evil;

  public Baz getOpposite() {
    switch (this) {
        case yin: return yang;
        case yang: return yin;
        case good: return evil;
        case evil: return good;
    }
    throw new AssertionError();
}

参考:Java enum- Cannot reference a field before it is defined - Stack Overflow

PR:オラクル認定資格教科書 Javaプログラマ Bronze SE 7 スピードマスター問題集 (EXAMPRESS)
PR:Java言語プログラミングレッスン 第3版(上)

0 件のコメント :

コメントを投稿