AndroidのRクラスをコレクションにする

動的にリソースにアクセスしたいとか、リソース配列を作るのにlist = {R.xx.xxxx1, R.xx.xxxx2, ....}とかするのが面倒なときとかはRクラスをコレクションにするといい。AndroidはリフレクションNGとか誰かが言ってた気がするけどまぁいいや。
例:ImageButtonの画像をランダムに変更するアプリの場合

画像準備
用意した画像をdrawable以下に配置

Rクラスを覗く
Rクラスはresディレクトリのディレクトリ名で内部クラスを持っている。
フィールド名はディレクトリ以下のファイル名になっている
つまり、内部クラスの名前とフィールド名が分かればOK

/* AUTO-GENERATED FILE.  DO NOT MODIFY.
 *
 * This class was automatically generated by the
 * aapt tool from the resource data it found.  It
 * should not be modified by hand.
 */

package com.example;

public final class R {
    public static final class attr {
    }
    public static final class drawable {
        public static final int icon=0x7f020000;
        public static final int up29671=0x7f020001;
        public static final int up29673=0x7f020002;
        public static final int up29674=0x7f020003;
        public static final int up29676=0x7f020004;
        public static final int up29692=0x7f020005;
        public static final int up29706=0x7f020006;
    }
    public static final class id {
        public static final int ImageButton01=0x7f050000;
    }
    public static final class layout {
        public static final int main=0x7f030000;
    }
    public static final class string {
        public static final int app_name=0x7f040001;
        public static final int hello=0x7f040000;
    }
}

リソースをコレクションにする
Rクラスの内部クラスの一覧を取得するにはPackage#getClasses ※ここでandroid.R.getClassesとかやると楽しいかもしれないが幸せにはなれない
今回はイメージだけ必要なので、クラス名をdrawableに限定する。音楽をランダムに再生したいとかなら"raw"とかにする
Class#getFieldsでディレクトリ内のファイル名が取得できる
取得したものをコレクションに格納すれば出来上がり。
今後リソースが100個に増えたりとか、名前が変わったとかでもソースの改修は必要ない。
MapとList両方があるけど、今回はListしか使わない。

// Rクラスの全ての内部クラスを取得
Class<?>[] classes = com.example.R.class.getClasses();
for (Class<?> cls : classes) {
	// 内部クラスがdrawbleならコレクションを作る
	if (cls.getSimpleName().equals("drawable")) {
		Field[] fields = cls.getFields();
		String name;
		for (Field field : fields) {
			try {
				name = field.getName();
				if(name.equals("icon")){	//iconは無視
					continue;
				}
				// drawableコレクションに格納
				this.drawableMap.put(field.getName(), ((Integer) field
						.get(field.getName())));
				this.drawableList.add((Integer) field.get(field
						.getName()));

ソース

package com.example;

import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Random;

import android.app.Activity;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageButton;

public class S_RTest extends Activity {
	private ImageButton button;
	private HashMap<String, Integer> drawableMap;
	private ArrayList<Integer> drawableList;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		this.drawableMap = new HashMap<String, Integer>();
		this.drawableList = new ArrayList<Integer>();
		createDrawbleCollection();
		displayCollection();

		this.button = (ImageButton)findViewById(R.id.ImageButton01);
		setImage();
		this.button.setOnClickListener(new OnClickListener() {
			
			@Override
			public void onClick(View v) {
				button.getId();
				setImage();
			}
		});
	}

	public void setImage(){
		Random rand = new Random();
		//リソースIDをランダムに取得
		Bitmap bitmap = BitmapFactory.decodeResource(getResources(),
				drawableList.get(rand.nextInt(drawableList.size())));
		//画像を200,200にリサイズ
		Bitmap resize = Bitmap.createScaledBitmap (bitmap, 200, 200, false);
		button.setImageBitmap(resize);
		
	}
	
	public void createDrawbleCollection() {
		// Rクラスの全ての内部クラスを取得
		Class<?>[] classes = com.example.R.class.getClasses();
		for (Class<?> cls : classes) {
			// 内部クラスがdrawbleならコレクションを作る
			if (cls.getSimpleName().equals("drawable")) {
				Field[] fields = cls.getFields();
				String name;
				for (Field field : fields) {
					try {
						name = field.getName();
						if(name.equals("icon")){	//iconは無視
							continue;
						}
						// drawableコレクションに格納
						this.drawableMap.put(name, ((Integer) field
								.get(name)));
						this.drawableList.add((Integer) field.get(name));

					} catch (IllegalArgumentException e) {
						e.printStackTrace();
					} catch (IllegalAccessException e) {
						e.printStackTrace();
					}
				}
			}
		}
	}

	public void displayCollection() {
		for (String key : this.drawableMap.keySet()) {
			Log.v("map", key + ":" + this.drawableMap.get(key));
		}

		for (Integer val : this.drawableList) {
			Log.v("list", String.valueOf(val));
		}
	}
}