先日、友人の浅海さん @asami224 から、Androidの開発を簡単にする、いろいろな手法が
提案されているという話を聞きました。問題意識はあったのですが、具体的な動きは、全く、
チェックしていませんでした。
面白そうな話題なので、簡単に、どんな取り組みなのか紹介したいと思います。
既に、知っている人は、ごめんなさい。
Androidのプログラムでは、次のようなコードを、沢山書きます。
name = (TextView) findViewById(R.id.name);
thumbnail = (ImageView) findViewById(R.id.thumbnail);
loc = (LocationManager)
getSystemService(Activity.LOCATION_SERVICE);
icon = getResources().getDrawable(R.drawable.icon);
myName = getString(R.string.app_name);
こうしたコードは、Androidでは、お約束の定型的なコードなのですが、少し面倒だと
思ったことありませんか?
よく考えると、変というか、無駄なことがあることがわかります。
というのも、これらのコードは、Rファイルで定義された、あるいは、SystemServiceで
定義されているインスタンスを取得しているのですが、Rファイルは、もともとは、自分で
定義した情報から生成されたものですし、SystemServiceは、もともと決まったものです。
型変換のキャストも、当たり前と言えば、当たり前です。
このあたりは、プログラマが考えて指定しなくても、与えられた情報からコンピュータ自身に
考えて処理してもらうことが出来るはずです。
そこで登場するのが、DI(Dependency Injection)という考え方です。Dependency 従属性
というのは、プログラムの中のあるインスタンスは、任意のものでは無くて、他のものによって
(従属して)、性質が決まっていることがあると言うことです。この例の場合では、Rファイルに
従属して、いくつかのインスタンスの性質は決まっています。
Dependency Injection というのは、こうした従属性を持つインスタンスをプログラムの中で
利用する際に、インスタンスの生成の時点で、こうした性質を持つインスタンスを作って
プログラムに、「注入(Injection)」しようというものです。
こうした手法を使うと、次のようなAndroidプログラムは、とても簡単になります。
class AndroidWay extends Activity {
TextView name;
ImageView thumbnail;
LocationManager loc;
Drawable icon;
String myName;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
name = (TextView) findViewById(R.id.name);
thumbnail = (ImageView) findViewById(R.id.thumbnail);
loc = (LocationManager)
getSystemService(Activity.LOCATION_SERVICE);
icon = getResources().getDrawable(R.drawable.icon);
myName = getString(R.string.app_name);
name.setText( "Hello, " + myName );
}
}
これは、こうなります。
class RoboWay extends RoboActivity {
@InjectView(R.id.name) TextView name;
@InjectView(R.id.thumbnail) ImageView thumbnail;
@InjectResource(R.drawable.icon) Drawable icon;
@InjectResource(R.string.app_name) String myName;
@Inject LocationManager loc;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
name.setText( "Hello, " + myName );
}
}
こちらの方が、すっきりしていませんか?
このサンプルは、RoboGuiceというプロジェクトから取ったものです。
http://code.google.com/p/roboguice/wiki/SimpleExample?tm=6
(残念ながら、プロジェクトが整備中なのか、サンプルのソースを見ようとすると、
404が出てしまいますが。)
@InjectView(R.id.name) TextView name;
が、nameというインスタンスを、プログラムに「注入」しているところで、
name = (TextView) findViewById(R.id.name);
の代わりの役割を果たしています。以下、同様です。
@で始まる文字列は、Javaでは、Annotationと言われるものです。
Annotationを自分で作るのは、少し面倒ですが、Annotationを使うのは
とても簡単です。6年前のものですが、「Annotationプログラミング入門」
http://marulec.cloud-market.jp/archive/2004/20050309/annotation_2.pdf
プログラムを簡単にして、開発を容易にしようという取り組みを、EoD
(Ease of Development)と言います。AnnotationやDIは、EoDの有力な
手法です。エンタープライズの世界では、EoDの手法は広く普及しています。
SpringやSeasar2を使ったことがある人は、よくご存じだと思います。
これから、Androidの世界で、プログラミングを簡単にする新しい手法が
(本当は、新しくはないのですが)、どんどん広まっていくと思います。
AndroidでのDI利用のプロジェクト
Roboguice http://code.google.com/p/roboguice/
RoboguiceのTestでの応用
thorikawaさんのblog http://d.hatena.ne.jp/thorikawa/20101127/p1
@vvakameさんの日記 http://d.hatena.ne.jp/vvakame/20100901/1283354793
esmasuiさんのblog http://d.hatena.ne.jp/esmasui/20100904/1283617914
浅海さんのAndroidプログラム自動生成プロジェクト goldenport-android-library
https://github.com/asami/goldenport-android-library
Java自体は、Androidアプリを作って初めてやりました。
まず最初に思ったのが、この問題でした。
書くのがめんどくさいって事でした。
色々錯誤して、あっているかどうかはわかりませんが。。。
最近はこんな感じにしています。
/* 共通オブジェクト */
public class CommonObjects {
private static CommonObjects instance = new CommonObjects();
private CommonObjects(){}
public static CommonObjects getInstance() {
return instance;
}
/*
* 共通関数
*/
private View getView(Activity objAct){
return objAct.getWindow().getDecorView();
}
/*
* テキストビュー関連
*/
public void setTextView(Activity objThis, int intTextRID, String
strView){
this.setTextView(getView(objThis), intTextRID, strView);
}
public void setTextView(View objView, int intTextRID, String strView){
TextView txtItem = (TextView)objView.findViewById(intTextRID);
txtItem.setText(strView);
}
public String getTextView(Activity objThis, int intTextRID){
return this.getTextView(getView(objThis), intTextRID);
}
public String getTextView(View objView, int intTextRID){
TextView txtItem = (TextView)objView.findViewById(intTextRID);
return txtItem.getText().toString();
}
}
class AndroidWay extends Activity {
static CommonObjects mclsUser; //共通クラス定義
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
// 共通クラス初期化
mclsUser = CommonObjects.getInstance();
// 書き込み
mclsUser.Object().setTextView(this, R.id.name, "Hello");
}
}
この書き方に問題があるのか、もしかしたらおかしい事をやってるんじゃないか
と思いながらも使っています。
こんどは、DIを混ぜて作って見たいと思います。
Dependency Injection いいですね。判りきった定型文を書くのって無駄に苦痛なんで
こういったプロジェクトには大いに期待するところです
ところで jdk7 あたりに project coin ってのがあって
それは色々な特徴があるんですけど、例えば
Map<String,String> map=new HashMap<String,String>();
って書いてたのが
Map<String,String> map=new HashMap<>();
で OK になります
android (dalvik) の jdk7 対応が待ち遠しいところです
--
// TAO Seiichiroh