Slide 1

Slide 1 text

Overview of Android Infrastructure Alexey Buzdin March 2013

Slide 2

Slide 2 text

@AlexeyBuzdin! ! ! [email protected]! ! ! LArchaon!

Slide 3

Slide 3 text

Everyone needs an app....

Slide 4

Slide 4 text

we need an app too!

Slide 5

Slide 5 text

Simple CRUD app

Slide 6

Slide 6 text

Requirement:! ! Support as many android devices as you can! (phones + tablets)

Slide 7

Slide 7 text

4.0 4.1–4.2 3.0 2.3 2.2 2.1 Google data, March 2013

Slide 8

Slide 8 text

No content

Slide 9

Slide 9 text

Ain't that good for a developer

Slide 10

Slide 10 text

No content

Slide 11

Slide 11 text

No content

Slide 12

Slide 12 text

No content

Slide 13

Slide 13 text

Is there is someone who could solve this?

Slide 14

Slide 14 text

nope

Slide 15

Slide 15 text

Ease our pain?

Slide 16

Slide 16 text

maybe

Slide 17

Slide 17 text

No content

Slide 18

Slide 18 text

No content

Slide 19

Slide 19 text

Layers Presentation ! Application logic ! Domain Presentation ! Application logic ! Domain

Slide 20

Slide 20 text

Presentation ! Application logic ! Domain Presentation ! Application logic ! Domain

Slide 21

Slide 21 text

Spot the problem

Slide 22

Slide 22 text

Missing in Android 2.2 ● ActionBar! ● Fragments (used for both tablets and phone support)

Slide 23

Slide 23 text

Solution?

Slide 24

Slide 24 text

Compatibility libraries Android Support library! ActionBarSherlock! etc

Slide 25

Slide 25 text

Support Library http://developer.android.com/tools/extras/ support-library.html ! Fragments! Async Stuff! Experimental stuff

Slide 26

Slide 26 text

Fragments

Slide 27

Slide 27 text

Example

Slide 28

Slide 28 text

ActionBar

Slide 29

Slide 29 text

ActionBarSherlock http://actionbarsherlock.com/

Slide 30

Slide 30 text

Refreshing list

Slide 31

Slide 31 text

Pull to Refresh https://github.com/chrisbanes/ Android-PullToRefresh

Slide 32

Slide 32 text

Presentation ! Application logic ! Domain Presentation ! Application logic ! Domain

Slide 33

Slide 33 text

Android Runtime On Android you develop in Java ... but Android does not run Java bytecode !

Slide 34

Slide 34 text

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)

Slide 35

Slide 35 text

!35 Android Runtime Android Java = Java language + Dalvik + Apache Harmony Android Java API = Java SE – AWT/Swing + Android API Sun-Java = Java language + JVM + JDK

Slide 36

Slide 36 text

App lifecycle

Slide 37

Slide 37 text

Activity public class MyActivity extends Activity { ! @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } ! }

Slide 38

Slide 38 text

No content

Slide 39

Slide 39 text

Activity public class MyActivity extends Activity { ! @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } ! }

Slide 40

Slide 40 text

Resources

Slide 41

Slide 41 text

Activity public class MyActivity extends Activity { ! @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); } ! }

Slide 42

Slide 42 text

Context ● Context of current state of the application/object

Slide 43

Slide 43 text

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

Slide 44

Slide 44 text

Important any resource taken from context will live as long as Context does

Slide 45

Slide 45 text

Context problem public class MyActivity extends Activity { ! @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); String appName = getString(R.string.appName); } ! }

Slide 46

Slide 46 text

Passing Context public class MyStringProvider { ! Context context; ! public MyStringProvider(Context context) { this.context = context; } ! public String getString(){ return context.getString(R.string.app_name); } ! }

Slide 47

Slide 47 text

Passing Context

Slide 48

Slide 48 text

Context problem public 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

Slide 49

Slide 49 text

Injection libraries Dependency Injection! ● RoboGuice! ● Dagger

Slide 50

Slide 50 text

RoboGuice ● Based on Google Guice! ● Lightweight! ● Multifunctional (has resource injection)

Slide 51

Slide 51 text

RoboGuice public 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()); } ! }

Slide 52

Slide 52 text

RoboGuice public class MyStringProvider { ! Context context; ! @Inject public MyStringProvider(Context context) { this.context = context; } ! public String getString(){ return context.getString(R.string.app_name); } }

Slide 53

Slide 53 text

Notable fact

Slide 54

Slide 54 text

Minimal context injection public 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()); } ! }

Slide 55

Slide 55 text

RoboGuice public 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; } }

Slide 56

Slide 56 text

Dagger public 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()); } ! }

Slide 57

Slide 57 text

Dagger public 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); } }

Slide 58

Slide 58 text

Dagger public class DaggerApplication extends Application { ! private static ObjectGraph objectGraph; ! @Override public void onCreate() { super.onCreate(); ! objectGraph = ObjectGraph.create(new DaggerModule(this)); } ! public static void inject(T instance) { if(objectGraph != null) objectGraph.inject(instance); } }

Slide 59

Slide 59 text

@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; } ! }

Slide 60

Slide 60 text

Summary Dagger ! ● More customizable! ● Compile time injection! ● Easy to use with other libraries! ● Requires more code! ! RoboGuice! ● Simpler! ● Runtime injection! ● Out of Box functionality

Slide 61

Slide 61 text

Problem with views

Slide 62

Slide 62 text

No content

Slide 63

Slide 63 text

No content

Slide 64

Slide 64 text

Other “Injection” libraries Resource and View “Injection”! ● RoboGuice! ● ButterKnife! ● AndroidAnnotations

Slide 65

Slide 65 text

RoboGuice Views Injection public 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()); } ! }

Slide 66

Slide 66 text

Butterknife public 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());! }! ! }

Slide 67

Slide 67 text

AndroidAnnotations @EActivity(R.layout.translate) // Sets content view to R.layout.translate! public 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);! } ! }

Slide 68

Slide 68 text

Presentation ! Application logic ! Domain Presentation ! Application logic ! Domain

Slide 69

Slide 69 text

Data Source Android has built in SQLite

Slide 70

Slide 70 text

Data Source ... but lacks ORM! ! Alternatives:! − GreenDAO! − ORMLite

Slide 71

Slide 71 text

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 } }

Slide 72

Slide 72 text

// you get the SQLiteOpenHelper from your Android Activity ConnectionSource connectionSource = new AndroidConnectionSource(sqliteOpenHelper); ! // instantiate the DAO to handle Account with String id Dao 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

Slide 73

Slide 73 text

Testing

Slide 74

Slide 74 text

Testing ● DVM or JVM! ● Automation or Unit Tests

Slide 75

Slide 75 text

DVM ● Requires a separate Test Project! ● android.test or Robotium

Slide 76

Slide 76 text

Android.test public class SimpleActivityTestStandard extends! ActivityUnitTestCase {! 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());! }! }

Slide 77

Slide 77 text

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();! );!

Slide 78

Slide 78 text

JVM public class RoboGuiceActivityTest { ! @Test public void shouldHaveISet() throws Exception { RoboGuiceActivity activity = new RoboGuiceActivity(); assertThat(activity.getI(), equalTo(1)); } }

Slide 79

Slide 79 text

JVM public class RoboGuiceActivityTest { ! @Test public void shouldHaveISet() throws Exception { RoboGuiceActivity activity = new RoboGuiceActivity(); assertThat(activity.getI(), equalTo(1)); } }

Slide 80

Slide 80 text

No content

Slide 81

Slide 81 text

We have Mockito! 
 lets mock something 
 in our Activity ...

Slide 82

Slide 82 text

Activity source code

Slide 83

Slide 83 text

Robolectric to the rescue Allows you to run ! you android code ! on JVM

Slide 84

Slide 84 text

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)); } }

Slide 85

Slide 85 text

Robolectric + Mockito

Slide 86

Slide 86 text

Testing ● DVM or JVM! ● Automation or Unit Tests! ● Robotium or Robolectric! ● Or both

Slide 87

Slide 87 text

Conclusion

Slide 88

Slide 88 text

More libraries?

Slide 89

Slide 89 text

More libraries

Slide 90

Slide 90 text

Solution?

Slide 91

Slide 91 text

Android Bootstrap ● Fragments,Fragment Pager! ● android-maven-plugin, Dagger! ● ActionBarSherlock ! ● ViewPagerIndicator! ● http-request, GSON ! ● Robotium http://www.androidbootstrap.com/

Slide 92

Slide 92 text

Build Systems ● Gradle ● Maven ! https://github.com/LArchaon/ android_mvn_template/

Slide 93

Slide 93 text

Q&A