RoboGuiceは、Androidでアプリケーションを開発する際にコンテキストと依存関係の注入を最大限に活用できるライブラリです。
ご想像のとおり、RoboGuiceは
Google Guiceに基づいてい
ます 。
私は、「注入」という言葉の翻訳として、「注入」という言葉を使用するとすぐに言わなければなりません。
なぜ注入するのですか?
多くの読者がすぐに質問をするだろうと思います。「モバイルプラットフォームでのCDIの問題はなぜですか? 確かにすべてが多くのスペースを占有し、ゆっくりと動作します。」
そのような読者に、モバイルプラットフォームでのCDIは非常に実行可能であり、開発者の生活を楽にするという反対を納得させようとします。

叙情的な余談
熱意とXMLの普及の時代の後、誰もがXMLファイルの「フットバッグ」にうんざりしたとき、冷静になりました。 構成コードの量を減らし、開発をスピードアップする新しいアプローチの検索が始まりました。 そのような出力の1つは、注釈ベースのCDIでした。 2つ目は
、構成または
コーディングの慣習によるコーディングを 超えるコンベンションと呼ば
れます 。 開発者はそれが好きで、アイデアが開発され、いくつかのCDI実装が登場し、多くの大規模なライブラリが注釈を通じてCDIを使用し始めました。
その結果、CDIは、Java EE 6に正式に含まれている(
JSR-299 )と同様に、
JSR-330の形でJava用に標準化されました。
個人的に、私は最初にSeamライブラリでCDIを見ました。 そして彼はアプローチのシンプルさと優雅さに喜んで驚いた。 開発時間の節約、構成の簡素化、総量の削減、それに応じて発生する可能性のあるエラーの削減。
時間が経つにつれて、注釈はほぼすべての場所に浸透しました。 XMLマニアの後、注釈の時代が来ました。 そして、彼らがAndroidに到達しなければ、非常に奇妙になります。
では、なぜモバイルプラットフォーム上にあるのでしょうか?
答えは簡単です。開発をより速く簡単にすること、そしてコードはよりクリーンで信頼性が高いことです。
根拠がないようにするために、
Roboguice Get Startedの例を
見てみましょう。
通常のActivityクラスは次のようになります。
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 ); } }
コードは19行です。
onCreate()
メソッドの5行のコードはクラスフィールドの通常の初期化であり、最後の1行のみがセマンティックロードを実行します:name.setText()。 Activityクラスのより複雑な実装には、オブジェクトを初期化するためのさらに多くのコードが含まれる場合があります。
次に、RoboGuiceが許可するものと比較します。
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 ); } }
onCreate()
はるかに簡潔で
onCreate()
やすくなりました。 最小テンプレートコード、アプリケーションロジックに関する最大コード。
最初の注入
「最初のインジェクション」をより実行可能にするために、
developer.android.comからインジェクションに関するよく知られた例を注入します:
Notepad Tutorial 。 それは棚で完全に分類され、そのソースコードが利用可能であり、CDIのアイデアを修正して実装するのに十分です。
プロジェクトでRoboGuiceの使用を開始するには、クラスパスに
RoboGuiceと
guice-2.0-no_aop.jar (guice-3.0ではない)の2つのライブラリを追加する必要があります。
Mavenに依存関係として追加することもできます(はい、AndoirdプロジェクトとMavenはまったく互換性がありますが、これは別の記事のトピックです)。
<dependency> <groupId>org.roboguice</groupId> <artifactId>roboguice</artifactId> <version>1.1</version> </dependency>
次に、
RoboApplication
を継承するクラスを作成する必要があります。
public class NotepadApplication extends RoboApplication { }
AndroidManifest.xml
登録します:
<application android:name="com.android.demo.notepad3.NotepadApplication">
ここで、小さな
NoteEdit
クラスを書き直します。
NotesDbAdapter
から継承したリソースインジェクションと
NotesDbAdapter
を追加し
RoboActivity
。
それは:
public class NoteEdit extends RoboActivity { private NotesDbAdapter mDbHelper; private EditText mTitleText; private EditText mBodyText; private Long mRowId; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.note_edit); setTitle(R.string.edit_note); mDbHelper = new NotesDbAdapter(this); mDbHelper.open(); mTitleText = (EditText) findViewById(R.id.title); mBodyText = (EditText) findViewById(R.id.body); Button confirmButton = (Button) findViewById(R.id.confirm); ... } ... }
次のようになりました:
public class NoteEdit extends RoboActivity { @Inject NotesDbAdapter mDbHelper; @InjectView(R.id.title) EditText mTitleText; @InjectView(R.id.title) EditText mBodyText; @InjectView(R.id.confirm) Button confirmButton; @InjectResource(R.string.edit_note) String title; private Long mRowId; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.note_edit); setTitle(title); mDbHelper.open(); ... } ... }
Notepadv3
も
Notepadv3
変更し
Notepadv3
。
RoboListActivity
、
RoboListActivity
の注入を追加し、この
NotesDbAdapter
の初期化を
onCreate()
から削除します。
public class Notepadv3 extends RoboListActivity { ... @Inject private NotesDbAdapter mDbHelper; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.notes_list); mDbHelper.open(); fillData(); registerForContextMenu(getListView()); } ... }
また、
NotesDbAdapter
コンストラクターを更新して、
Context
RoboGuiceに自動的に置き換え
NotesDbAdapter
します。
@Inject public NotesDbAdapter(Context ctx) { this.mCtx = ctx; }
実行、確認-動作します!
コードが少なくなり、機能が維持され、読みやすさが向上しました。
RoboGuiceは
Context
クラスだけでなく、他の多くのAndroidサービスオブジェクトもインジェクションできることに注意してください。
Application
、
Activity
、さまざまなサービス。 完全なリストは
こちらから入手でき
ます 。
線量を増やす
RoboGuiceの機能を示すために、
NotesDbAdapter
クラスをリファクタリングします。 私の意見では、それは非常に過負荷であり、
DatabaseHelper
と
NotesDbAdapter
自体の分解が必要です。 プロジェクトが成長するにつれて、
DatabaseHelper
は間違いなくいくつかのクラスで使用されます。 たとえば、
TasksDbAdapter
が表示されます。 特に私は個人的に
mDbHelper.open();
への強制呼び出しが好きではないので
mDbHelper.open();
。 このメソッドは、2つの場所で呼び出す必要があります。 この呼び出しを行い、間違いを犯すことを忘れる大きな誘惑。 それでは始めましょう。
NotesDbAdapter
から始めましょう。 追加のフィールドは次のとおりです。
DatabaseHelper
を初期化するためにのみ使用されるContext mCtx
SQLiteDatabase mDb
のみSQLiteDatabase mDb
実際に使用されるため、 DatabaseHelper mDbHelper
自体はDatabaseHelper mDbHelper
。- 静的フィールド:
DATABASE_CREATE, DATABASE_VERSION, DATABASE_NAME
。データベースとの間でノートを保存および受信するロジックとはほとんど関係ありません。
実際、
SQLiteDatabase mDb
のみを残したいと
SQLiteDatabase mDb
ます。 残りを削除します。
NotesDbAdapter
シングルトンにします。
合計では、次の目標があります。
@Singleton public class NotesDbAdapter { public static final String KEY_TITLE = "title"; public static final String KEY_BODY = "body"; public static final String KEY_ROWID = "_id"; private static final String TAG = "NotesDbAdapter"; private static final String DATABASE_TABLE = "notes"; @Inject private SQLiteDatabase mDb; public NotesDbAdapter() { } ... }
KEY_TITLE, KEY_BODY, KEY_ROWID, DATABASE_TABLE, TAG
残っているため、 これらは
NotesDbAdapter
最も関連してい
NotesDbAdapter
。
新しいクラスには
open()
メソッドはありません。 このメソッドのロジックを
DatabaseHelper
転送しましょう。
ここで
SQLiteDatabase mDb
を取得する必要があります。 明らかに、
DatabaseHelper
はこれを行う必要があります。 彼にこれを行う方法を教えるために、
com.google.inject.Provider
インターフェースを実装します。これは、
get()
メソッドを使用して作成された特定のオブジェクトを返します。
さらに、アプリケーションコンテキストをコンストラクタに注入します。
その結果、
DatabaseHelper
クラスは次のようになります。
@Singleton public class DatabaseHelper extends SQLiteOpenHelper implements Provider<SQLiteDatabase>{ private static final String TAG = "DatabaseHelper"; private static final String DATABASE_CREATE = "create table notes (_id integer primary key autoincrement, " + "title text not null, body text not null);"; private static final String DATABASE_NAME = "data"; private static final int DATABASE_VERSION = 2; private SQLiteDatabase mDb; @Inject public DatabaseHelper(Context context) { super(context, DATABASE_NAME, null, DATABASE_VERSION); } public SQLiteDatabase get() { if (mDb == null || !mDb.isOpen()) { mDb = getWritableDatabase(); } return mDb; } @Override public void onCreate(SQLiteDatabase db) { db.execSQL(DATABASE_CREATE); } @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { ... } }
次に、RoboGuiceに、
SQLiteDatabase
クラス
SQLiteDatabase
プロバイダークラス
DatabaseHelper
によって提供されることを指摘させて
SQLiteDatabase
。 これを行うには、いわゆる構成クラスを作成します モジュール、それをシステムに登録します(
NotepadApplication
)
public class NotepadModule extends AbstractAndroidModule { @Override protected void configure() { bind(SQLiteDatabase.class).toProvider(DatabaseHelper.class); } }
public class NotepadApplication extends RoboApplication { @Override protected void addApplicationModules(List<Module> modules) { modules.add(new NotepadModule()); } }
実行してみてください-動作します!
NotepadModule.configure()
メソッドを拡張して、他のタイプをバインドする
NotepadModule.configure()
ができます。たとえば、特定のインターフェース実装を置き換えます。
protected void configure() { bind(SQLiteDatabase.class).toProvider(DatabaseHelper.class); bind(FilterDao.class).to(FilterDaoHttp.class); bind(ItemDao.class).annotatedWith(Http.class).to(ItemDaoHttp.class); }
つまり、
Google Guiceのあらゆる
種類のバインディングが利用可能です 。
いくつかの単語とテストを追加する価値があります。 RoboGuiceには、単体テストを容易にし、スピードアップするためのいくつかのクラスが含まれています。
RoboUnitTestCase
は、Androidエコシステムに依存しないクラスのテストを提供します。
RoboActivityUnitTestCase
使用
RoboActivityUnitTestCase
と、アクティビティの単体テストを実行でき
RoboActivityUnitTestCase
。 将来、Androidでのテストに関する別の記事を作成し、さまざまなアプローチとライブラリを比較したいと思います。 Androidでのテストは、開発自体ほど分解されていません。
最終診断
したがって、注射の利点について最終診断を行います。
+オブジェクトの初期化とライフサイクルの管理を行うコードの削減
+その他のビジネスロジックコード
+オブジェクトの接続性を減らす
+依存関係の構成とオブジェクトの初期化のための最小スペース
+使いやすさとシステムオブジェクトとリソースの置換(コンテキスト、アプリケーション、SharedPreferences、リソースなど)
+結果として、開発を加速し、エラーを減らします
-ライブラリを追加すると、アプリケーションのサイズが大きくなります。
物議を醸すマイナス。
guice-2.0-no_aop.jar
と
roboguice-1.1.1.jar
のサイズは合わせて約545 Kbであり、単純なアプリケーションではかなり多くなりますが、大きくて複雑なアプリケーションではかなり許容できます。
-生産性の低下
また、論争点。 間違いなく、注射には時間がかかります。 ただし、これに費やされる時間は短く、主にアプリケーションの起動時です。 ループやアニメーションでインジェクションを使用しない場合、ユーザーはパフォーマンスの変化に気付かないでしょう。 さらに、スマートフォンとDalvikVMのパフォーマンスは常に成長しています。
私の個人的な診断:RoboGuiceは彼らのプロジェクトで使用されるべきです。 プロは間違いなく短所を上回ります。