Rクラスを外部からロードする

Androidアプリケーションのリソースはプロジェクトのパッケージ下のRという名前のクラスに変換されて自動的にコンパイルされる。

例えばプロジェクトを作成した時にorg.kazz.applicationというパッケージを作ったならば完全修飾名は

org.kazz.application.R

でリソースクラスにアクセスできる。変換〜ビルドは自動で行われるのでEclipseの場合は補完候補にすぐにででくる。

ならば外部から同Rクラス及び特定のインナークラスをロードしたい場合はどのようにすれば良いのだろう。といっても複雑なことはなく、今まで通り基本的にはパッケージ名+"R"でクラスをロードすれば良いはずだ。

Context(Activity)中のコードであれば直接クラスローダを取得できるので、そこからRクラスとそのインナークラスをロードできる。

String packageName = this.getPackageName();
String className = TextUtils.isEmpty(packageName)
                    ? "R"
                    : packageName + ".R";
ClassLoader loader = this.getClassLoader();
// org.kazz.application.R
Class clazz = loader.loadClass(className);

// org.kazz.application.R.string
Class stringClazz = loader.loadClass(className+"$string");

// org.kazz.application.R.xml
Class xmlClazz = loader.loadClass(className+"$xml");

// org.kazz.application.R.xmlクラスのフィールド"config"の値(リソースへのハンドル)を取得する
int handle = xmlClazz.getField("config").getInt(null);

// config.xmlをパースするプルパーサを取得する
XmlResourceParser parser = this.getResources().getXml(handle);


性能の観点から、Dalvik VMではリフレクションは御法度というのをどこかで見たが、メタプログラミングが当たり前の今日日、リフレクション禁止では何もできない。(事実、SDK内でもリフレクションは使用している)

今後主流になっていくであろう、Nexsus oneのリークしたスペックを見る限りでは、"1Ghz MPU/512MB RAM"と、JSDK1.3時代のPCのスペックと大して変わらず、ゲームのループ中等の、性能が気になる以外ではあまり神経質になる必要は無いだろうと思っている。(じゃないとJ2MEと決別した意味がないし)