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 ); } }
onCreate()
method is a trivial initialization of class fields, and only one, the last line carries the meaning: name.setText (). More complex implementations of the Activity classes can contain even more code for initializing objects. 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()
much more concise and easier to onCreate()
; minimum template code, maximum code relating to the application logic. <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
class. Add resource injections and NotesDbAdapter
, inherit from 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
. Inherit from RoboListActivity
, add an injection for the NotesDbAdapter
and remove the initialization of this NotesDbAdapter
from 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
constructor NotesDbAdapter
that the Context
automatically substituted with RoboGuice. @Inject public NotesDbAdapter(Context ctx) { this.mCtx = ctx; }
Context
class, but also of many other service objects of Android, including Application
, Activity
and various services. A full list is available here .NotesDbAdapter
class. In my opinion, it is heavily overloaded and requires the decomposition of the DatabaseHelper
and the NotesDbAdapter
itself. As the project grows, DatabaseHelper
will definitely be used by several classes. For example, a TasksDbAdapter
appears. Moreover, I personally do not like the violent challenge mDbHelper.open();
. This method should be called in two places. It is tempting to forget to make this call and get an error. So let's get started.NotesDbAdapter
. Here are a bunch of extra fields:Context mCtx
, which is used only to initialize DatabaseHelper
DatabaseHelper mDbHelper
, because only SQLiteDatabase mDb
actually usedDATABASE_CREATE, DATABASE_VERSION, DATABASE_NAME
, which have little to do with the logic of saving and receiving notes to / from the database.SQLiteDatabase mDb
. The rest is removed. In addition, we will make NotesDbAdapter
“singleton”. @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
left, because they are most relevant to the NotesDbAdapter
.open()
method in the new class. Let's transfer logic of this method to DatabaseHelper
.SQLiteDatabase mDb
. Obviously, DatabaseHelper
should do this. To teach him to do this, we implement the com.google.inject.Provider
interface, which, using the get()
method, returns one or another created object.DatabaseHelper
class will look like this: @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) { ... } }
SQLiteDatabase
class SQLiteDatabase
provided by the provider class DatabaseHelper
. To do this, create a configuration class, the so-called. module, and register it in the system (in 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()
method can be extended to bind other types, for example, substitutions for specific interface implementations: protected void configure() { bind(SQLiteDatabase.class).toProvider(DatabaseHelper.class); bind(FilterDao.class).to(FilterDaoHttp.class); bind(ItemDao.class).annotatedWith(Http.class).to(ItemDaoHttp.class); }
RoboUnitTestCase
provides testing for classes that are not dependent on the Android ecosystem. RoboActivityUnitTestCase
allows RoboActivityUnitTestCase
to run unit tests for Activities. In the future I would like to write a separate article about testing under Android, with a comparison of different approaches and libraries. Testing under Android is still not as well disassembled on Habré as the development itself.guice-2.0-no_aop.jar
and roboguice-1.1.1.jar
together is about 545 Kb, which is quite a lot for simple applications, but it is quite acceptable for large and complex applications.Source: https://habr.com/ru/post/116945/
All Articles