Download - Overview of Android Infrastructure
Overview of Android Infrastructure
Alexey Buzdin
Everyone needs an app....
We need an app too!
simple CRUD app
Requirement:
Support as many android devices as you can
(including tablets)
4.04.1–4.2
3.0
2.3
2.22.1
Google data, March 2013
Ain't that good for a developer
Is there is someone who could help us?
nope
Ease our pain
maybe
Layers
Presentation
Application logic
Domain
Presentation
Application logic
Domain
Presentation
Application logic
Domain
Presentation
Application logic
Domain
But Whers the problem?
Missing in Android 2.2
● ActionBar● Support for tablets● Decent ListView support for server communication
Solution?
Compatability libraries
Android Support library
ActionBarSherlock
etc
Support Libraryhttp://developer.android.com/tools/extras/support-library.html
Fragments
Async Stuff
Experimental stuff
Fragments
Example
ActionBar
Refreshing list
Pull to Refresh
https://github.com/chrisbanes/Android-PullToRefresh
Presentation
Application logic
Domain
Presentation
Application logic
Domain
Android Runtime
On Android you develop in Java
... but Android does not run Java Bytecode !
DalvikVM
Dalvik Virtual Machine– Custom VM optimized for mobile devices– Register-based JVM– More efficient and compact– Use memory efficiently – Dalvik Executable Code (.dex)
● 30% fewer instructions● 35% fewer code units● 35% more bytes
– Trace JIT compiler (since 2.2)
36
Android Runtime
Android Java = Java language + Dalvik + Apache Harmony
Android Java API = Java SE – AWT/Swing + Android API
Sun-Java = Java language + JVM + JDK
App lifecycle
Activity
public class MyActivity extends Activity {
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); }
}
Activity
public class MyActivity extends Activity {
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); }
}
Resources
Activity
public class MyActivity extends Activity {
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); }
}
Context● Context of current state of the
application/object
Context● Context of current state of the
application/object● Context is a handle to the system it
provides services like – resolving resources – obtaining access to databases and
preferences
Important
any resource taken from context will leave as long as Context does
Context problempublic class MyActivity extends Activity {
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); String appName = getString(R.string.appName); }
}
Passing Contextpublic class MyStringProvider {
Context context;
public MyStringProvider(Context context) { this.context = context; }
public String getString(){ return context.getString(R.string.app_name); }
}
Passing Context
Context problempublic class MyActivity extends Activity {
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); String appName = getString(R.string.appName); }
}Presentation
Application logic
Domain
Presentation
Application logic
Domain
Injection libraries
Dependency Injection● RoboGuice● Dagger
RoboGuice
● Based on Google Guice● Lightweight● Multifunctional (has resource injection)
RoboGuicepublic class MyActivity extends RoboActivity {
@Inject MyStringProvider stringProvider;
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main);
((TextView) findViewById(R.id.textView)) .setText(stringProvider.getString()); }
}
RoboGuicepublic class MyStringProvider {
Context context;
@Inject public MyStringProvider(Context context) { this.context = context; }
public String getString(){ return context.getString(R.string.app_name); }}
Notable fact
Optimezed context injectionpublic class MyActivity extends RoboActivity {
int i;
@Inject MyStringProvider stringProvider;
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main);
i = 1; ((TextView) findViewById(R.id.textView)) .setText(stringProvider.getString()); }
}
RoboGuicepublic class MyStringProvider {
Context context;
@Inject public MyStringProvider(Context context) { this.context = context; }
public String getString(){ return context.getString(R.string.app_name) + ((MyActivity)context).i; }}
Daggerpublic class DaggerActivity extends DaggerBaseActivity {
@Inject DaggerStringProvider stringProvider;
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main);
((TextView) findViewById(R.id.textView)).setText(stringProvider.getString());
}
}
Daggerpublic class DaggerBaseActivity extends Activity {
@Inject Bus bus;
@Override protected void onCreate(Bundle state) { super.onCreate(state);
DaggerApplication.inject(this); }
@Override protected void onResume() { super.onResume(); bus.register(this); }
@Override protected void onPause() { super.onPause(); bus.unregister(this); }}
Daggerpublic class DaggerApplication extends Application {
private static ObjectGraph objectGraph;
@Override public void onCreate() { super.onCreate();
objectGraph = ObjectGraph.create(new DaggerModule(this)); }
public static <T> void inject(T instance) { if(objectGraph != null) objectGraph.inject(instance); }}
@Module( entryPoints = { DaggerApplication.class, DaggerActivity.class})public class DaggerModule { private final Context appContext;
public DaggerModule(Context appContext) { this.appContext = appContext.getApplicationContext(); }
@Provides @Singleton Bus provideBus() { return new Bus(); }
@Provides Context provideContext() { return appContext; }
}
SummaryDagger
● More customizable● Easy communicates with other libraries● Requires more code
RoboGuice● Simpler● Out of Box functionality
Problem with views
Other “Injection” libraries
Resource and View “Injection”● RoboGuice● ButterKnife● AndroidAnnotations
RoboGuice Views Injectionpublic class RoboGuiceActivity extends RoboActivity {
@Inject RoboGuiceStringProvider stringProvider; @InjectView(R.id.textView) TextView textView;
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main);
textView.setText(stringProvider.getString()); }
}
Butterknifepublic class DaggerActivity extends DaggerBaseActivity {
@Inject DaggerStringProvider stringProvider; @InjectView(R.id.textView) TextView textView;
@Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); Views.inject(this);
textView.setText(stringProvider.getString()); }
}
AndroidAnnotations@EActivity(R.layout.translate) // Sets content view to R.layout.translatepublic class TranslateActivity extends Activity { @ViewById // Injects R.id.textInput EditText textInput; @ViewById(R.id.myTextView) // Injects R.id.myTextView TextView result; @AnimationRes // Injects android.R.anim.fade_in Animation fadeIn; @Click // When R.id.doTranslate button is clicked void doTranslate() { translateInBackground(textInput.getText().toString()); } @Background // Executed in a background thread void translateInBackground(String textToTranslate) { String translatedText = callGoogleTranslate(textToTranslate); showResult(translatedText); } @UiThread // Executed in the ui thread void showResult(String translatedText) { result.setText(translatedText); result.startAnimation(fadeIn); } }
Presentation
Application logic
Domain
Presentation
Application logic
Domain
Data Source
Android has built in SQLite
Data Source
... but lacks ORM
Alternatives:– GreenDAO– ORMLite
ORMLite@DatabaseTable(tableName = "accounts")
public class Account {
@DatabaseField(id = true) private String name;
@DatabaseField(canBeNull = false) private String password;
Account() {
// all persisted classes must define a no-arg constructor with at least package visibility
}
}
// you get the SQLiteOpenHelper from your Android Activity
ConnectionSource connectionSource = new AndroidConnectionSource(sqliteOpenHelper);
// instantiate the DAO to handle Account with String id
Dao<Account,String> accountDao = BaseDaoImpl.createDao(connectionSource, Account.class);
TableUtils.createTable(connectionSource, Account.class);
String name = "Jim Smith";
Account account = new Account(name, "_secret");
accountDao.create(account)
Account account2 = accountDao.queryForId(name);
connectionSource.close();
ORMLite
Testing
Testing
● DVM or JVM● Automation or Unit Tests
DVM
● Requires a separate Test Project● android.test or Robotium
Android.testpublic class SimpleActivityTestStandard extends ActivityUnitTestCase<SimpleActivity> { public SimpleActivityTestStandard() { super(SimpleActivity.class); }
public void setUp() throws Exception { startActivity(new Intent(getInstrumentation().getTargetContext(), SimpleActivity.class), null, null); }
public void testLayout() { SimpleActivity activity = getActivity(); assertNotNull(activity.findViewById(R.id.button1)); Button view = (Button) activity .findViewById(com.example.test.target.R.id.button1); assertEquals("My Button 1", view.getText()); }}
Robotium public void testPreferenceIsSaved() throws Exception { Solo solo = new Solo(getInstrumentation(), getActivity()); solo.sendKey(Solo.MENU); solo.clickOnText("More"); solo.clickOnText("Preferences"); solo.clickOnText("Edit File Extensions"); assertTrue(solo.searchText("rtf")); solo.clickOnText("txt"); solo.clearEditText(2); solo.enterText(2, "robotium"); solo.clickOnButton("Save"); solo.goBack(); solo.clickOnText("Edit File Extensions");
assertTrue(solo.searchText("application/robotium")solo.finishOpenedActivities();
);
JVMpublic class RoboGuiceActivityTest {
@Test public void shouldHaveISet() throws Exception { RoboGuiceActivity activity = new RoboGuiceActivity(); assertThat(activity.getI(), equalTo(1)); }}
JVMpublic class RoboGuiceActivityTest {
@Test public void shouldHaveISet() throws Exception { RoboGuiceActivity activity = new RoboGuiceActivity(); assertThat(activity.getI(), equalTo(1)); }}
We have Mockito! lets mock something
in our Activity ...
Activity source code
Robolectric to the rescue
Allows you to run
you android code
on JVM
Robolectric
@RunWith(RobolectricRoboTestRunner.class)public class RoboGuiceActivityTest {
@Test public void shouldHaveISet() throws Exception { RoboGuiceActivity activity = new RoboGuiceActivity(); activity.onCreate(null); assertThat(activity.getI(), equalTo(1)); }}
Robolectric + Mockito
Testing● DVM or JVM● Automation or Unit Tests● Robotium or Robolectric● Or both
Conclusion
More libraries?
More libraries
Solution?
Android Bootstrap● Fragments,Fragment Pager● android-maven-plugin, Dagger● ActionBarSherlock ● ViewPagerIndicator● http-request, GSON ● Robotium
http://www.androidbootstrap.com/
or customs scripts
Build Systems● Gradle● Maven
https://github.com/LArchaon/android_mvn_template/
Questions?