Android Survival Guide - Two years of software development

3,546 views

Published on

During the session, I'll explore lot of useful tricks I use during my everyday life as Android developer. Testing, background tasks, smartphone and tablet optimization, avoid memory leaks, UI view management, good external libraries to take into account, mobile design patterns and some best practices I found.

Published in: Technology, Education
0 Comments
4 Likes
Statistics
Notes
  • Be the first to comment

No Downloads
Views
Total views
3,546
On SlideShare
0
From Embeds
0
Number of Embeds
176
Actions
Shares
0
Downloads
84
Comments
0
Likes
4
Embeds 0
No embeds

No notes for slide

Android Survival Guide - Two years of software development

  1. 1. Who I amBorn in the past millenium and still an happy software developer Mobile addicted Android enthusiastic Free software fan Proud rider … and Tiramisu lover rainbowbreeze Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 1
  2. 2. Overview Online learnig resources Paintless rotation with threads Easy IoC/DI framework Testing, from unit to automation Honeycomb and backward compatibility Libraries and frameworks Q&A sessionAndroid Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 2
  3. 3. Chocolate Interaction modelDont be scare: interact, collaborate, share your fun! Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 3
  4. 4. Useful online material – Patterns Designing and Implementing Android UIshttp://www.google.com/events/io/2011/sessions/designing-and-implementing-android-uis- for-phones-and-tablets.html http://code.google.com/p/iosched/ Advanced Topics for Expert Android App Devshttp://www.google.com/events/io/2011/sessions/android-protips-advanced-topics-for-expert- android-app-developers.html Developing Android REST client applicationshttp://www.google.com/events/io/2010/sessions/developing-RESTful-android-apps.html Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 4
  5. 5. Useful online material - ListView The world of ListView http://www.google.com/events/io/2010/sessions/world-of-listview-android.html Lazy-loading of remote thumbnailshttp://android-developers.blogspot.com/2010/07/multithreading-for-performance.html Drag and Drop capable ListView https://github.com/commonsguy/cwac-touchlist Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 5
  6. 6. Background thread, progress bar and rotation Your application have to be smooth, dont use UI thread for long operation (> 200ms)Yuo cannot update UI Thread from external threads Use Activity.runOnUiThread(Runnable),View.post(Runnable), View.postDelayed(Runnable, long), Handler to bypass the problem Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 6
  7. 7. Background thread, progress bar and rotation public void onClick(View v) { //background thread new Thread(new Runnable() { public void run() { final Bitmap b = loadImageFromNetwork(); //update ui thread mImageView.post(new Runnable() { public void run() { mImageView.setImageBitmap(b); } }); } }).start(); } Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 7
  8. 8. Background thread, progress bar and rotation The simplest way AsyncTask Can access to UI Thread from separate thread http://android-developers.blogspot.com/2009/05/painless-threading.html Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 8
  9. 9. Background thread, progress bar and rotation protected void onCreate(Bundle savedInstanceState) { ... mLblResult = (TextView) findViewById(R.id.lblResult); LongTask longTask = new LongTask(); longTask.execute(); … } private class LongTask extends AsyncTask<Void, Void, String> ... protected void onPostExecute(String result) { mLblResult.setText(result); } Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 9
  10. 10. Background thread, progress bar and rotation But if the screen is rotated while the backgroud thread is still in execution? UI not updated, dialogs disappear, NullPointerException, memory leaks... OMG! Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 10
  11. 11. Background thread, progress bar and rotation The clean way - Define an Handler inside the Activity that process thread tasks (update/result) - Create background thread passing the handler - Call the handler from the thread when a progress must be published or the thread finish - Update activity reference inside thread using OnPause() and OnResume()- Pay attention to OnStart and other Activity lifecycle eventshttp://code.google.com/p/rainbowlibs/source/browse/android/trunk/rainbowlibs/src/it/rainb owbreeze/libs/logic/RainbowBaseBackgroundThread.javahttp://code.google.com/p/rainbowlibs/source/browse/android/trunk/rainbowlibs/src/it/rainb owbreeze/libs/ui/RainbowSplashScreenActivity.java Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 11
  12. 12. Background thread, progress bar and rotation public class WebcamActivity extends Activity() { private Handler mActivityHandler = new Handler() { public void handleMessage(Message msg) { Log.debug("Message from external thread" + msg.what); switch (msg.what) { case RotationThread.OPERATION_STARTS: //create progress dialog + other UI operations break; case RotationThread.OPERATION_COMPLETED: //remove the dialog + additional logic break; case RotationThread.OPERATION_ERROR: //remove the dialog + additional error logic Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 12
  13. 13. Background thread, progress bar and rotation public class WebcamActivity extends Activity() { private RotatingThread mRotatingThread; private void showWebcam() { //show a progress dialog showDialog(DIALOG_PREPARE_FOR_FULLSCREEN); mRotatingThread = new RotatingThread( mActivityHandler, webcamToShowId); mRotatingThread.start(); } Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 13
  14. 14. Background thread, progress bar and rotation public class RotatingThread() extends Thread { private WeakReference<Handler> mCallerHandler; public RotatingThread(Handler handler, int webcamId) { registerCallerHandler(handler); … } public void registerCallerHandler(Handler newHandler { mCallerHandler = new WeakReference<Handler>(newHandler); } public void unregisterCallerHandler() { mCallerHandler = null; } Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 14
  15. 15. Background thread, progress bar and rotation public class RotatingThread() extends Thread { ... public void run() { callHandlerAndRetry(OPERATION_STARTS); //your long operation here callHandlerAndRetry(OPERATION_COMPLETED); } Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 15
  16. 16. Background thread, progress bar and rotation protected void callHandlerAndRetry(int messageCode) { for (int retries = 0; retries < TOTAL_RETRIES; retries++) { if (null != mCallerHandler && null != mCallerHandler.get()) { Message message = mCallerHandler.get().obtainMessage(messageCode); message.arg1 = arg1; mCallerHandler.get().sendMessage(message); break; } try { //what some times, maybe next time activity is ready Thread.sleep(INTERVAL_BETWEEN_RETRIES); } catch (InterruptedException ignoreExcepition) {} } } Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 16
  17. 17. Background thread, progress bar and rotation public class WebcamActivity extends Activity() { @Override protected void onPause() { mRotatingThread.unregisterCallerHandler(); super.onPause(); } @Override protected void onResume() { mRotatingThread.registerCallerHandler(mActivityHandler); super.onResume(); } Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 17
  18. 18. Background thread, progress bar and rotation public class WebcamActivity extends Activity() { @Override public Object onRetainNonConfigurationInstance() { return mRotatingThread; } @Override protected void onStart() { super.onStart(); mRotatingThread = (RotatinThread)getLastNonConfigurationInstance(); //nothing saved, first run of the activity if (null == mRotatingThread) showWebcam(); } Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 18
  19. 19. Background thread, progress bar and rotation The short (but no totally complete) way Use a Fragment and setRetainInstance(true)http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/ app/FragmentRetainInstance.html Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 19
  20. 20. Lazy loading singleton Singleton PatternEnsure that only one instance of a class is created and provide a global point of access to the object. Create your own singleton or extend android.app.Application and modify its onCreate() method.Base class for those who need to maintain global application state.You can provide your own implementation by specifying its name in your AndroidManifest.xml’s <application> tag, which will cause that class to be instantiated for you when the process for your application/package is created. Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 20
  21. 21. Lazy loading singletonpublic class App extends Application { public static int myGlobalStaticValue; public int myGlobalValue; @Override public void onCreate() { super.onCreate(); myGlobalStaticValue = 10; myGlobalValue = 20; }<application android:name="it.rainbowbreeze.singleton.App">int value = App.myGlobalStaticValue;int value = ((App)context.getApplication()).myGlobalValue; Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 21
  22. 22. Lazy loading singleton Drawbacks Singleton is a pattern or an anti-pattern?http://stackoverflow.com/questions/3826905/singletons-vs-application-context-in-android OS may kill your application process, including the Application subclass instance. As a result the state is lost. When you later return to the application, then the OS will restore its activitystack and Application subclass instance, but its fields will be null. If you really need singleton, at least use lazy- loading singleton and avoid static fields to store application lifecycle data Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 22
  23. 23. Lazy loading singletonpublic class MySingleton() { private MySingleton mInstance;public synchronized MySingleton getInstance(Context c) { if (null == mInstance) { mInstance = new MySingleton(context); } return mInstance;}private MySingleton(Context appContext) { //initializes the object //reload SharedPreferences data} Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 23
  24. 24. Inversion of Control / Dependency Injection Dependency Injection PatternThe object does not need to know in advance about how the other part of the system works. Instead, the programmerprovides (injects) the relevant system component in advance along with a contract that it will behave in a certain way. http://en.wikipedia.org/wiki/Dependency_injectionReduce the coupling among software components: better code testability, useful in libraries, clean code. Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 24
  25. 25. Inversion of Control / Dependency Injectionpublic class ItemDao implements ItemDao { public ItemDao(Context appContext) { //performs initialization }}public DataManager implements IDataManager { INetManager mNetManager; IItemDao mItemDao; public DataManager(INetManager netMngr, IItemDao itemDao) { mNetManager = netMngr; mItemDao = itemDao; } Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 25
  26. 26. Inversion of Control / Dependency Injection Drawbacks Complex and less readable code Chain of dependencies More code to write SolutionsIoc/DI frameworks manage all the boring things! Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 26
  27. 27. Inversion of Control / Dependency Injectionpublic class AppEnv() { public static AppEnv i(Context appContext) { … mInstance = new AppEnv(appContext); return mInstance; } private AppEnv(Context appContext) { mItemDao = new ItemDao(appContext); mDataManager = new DataManager(mNetMngr, mItemDao); } ItemsDao mItemDao; public ItemsDao getItemDao(){ return mItemDao; } Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 27
  28. 28. Inversion of Control / Dependency Injection Drawbacks Cannot inject mock for testiong purposes SolutionsSeparate the object factory from the singleton Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 28
  29. 29. Inversion of Control / Dependency Injectionpublic class ObjFactory { public ItemDao createDao(Context appContext) { return new ItemDao(appContext); } public DataManager createDataManager( INetManager netMngr, ItemDao itemDao) { return new DataManager(netManager, itemDao); }} Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 29
  30. 30. Inversion of Control / Dependency Injectionpublic class AppEnv() { private static ObjFactory mObjFactory = new ObjFactory(); public static AppEnv i(Context c) { … mInstance = new AppEnv(c, mObjFactory); return mInstance; } public static AppEnv i(Context c, ObjFactory customFactory) { … mInstance = new AppEnv(c, customFactory); return mInstance; } Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 30
  31. 31. Inversion of Control / Dependency Injectionpublic class AppEnv() { … private AppEnv(Context appContext, ObjFactory objFactory) { mDao = objFactory.createDao(appContext); //... other initialization mDataManager = objFactory.createDataManager( mNetMngr, mDao); } private ItemsDao mDao; public ItemsDao getItemDao(){ return mDao; } Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 31
  32. 32. Inversion of Control / Dependency Injection--- inside your activity / component ---AppEnv appEnv = AppEnv.i(getContext());ItemDao dao = appEnv.getItemDao();--- inside your test class ---MockObjFactory mockFactory = new MockObjFactory() { @Overrides public ItemDao createDao(Context appContext) { return new MockItemDao(appContext); }};AppEnv appEnv = AppEnv.i(getContext(), mockFactory);ItemDao dao = appEnv.getItemDao(); Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 32
  33. 33. Inversion of Control / Dependency Injection RoboGuice Like Google Guice, but for Android http://code.google.com/p/roboguice/ http://stackoverflow.com/questions/5067681/guice-performance-on-android Other solutionshttp://stackoverflow.com/questions/1029696/the-hunt-for-the-j2me-friendly-ioc-container-is-on Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 33
  34. 34. Testing - basic Software testing = reduce risks of software implementation Lot of support Android side http://developer.android.com/guide/topics/testing/testing_android.htmlAndroid Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 34
  35. 35. Testing - first steps Create new “Android Test Project” Create a class that extends TestCase Code first test Red, Green, Refactor!http://developer.android.com/resources/tutorials/testing/helloandroid_test.htmlAndroid Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 35
  36. 36. Testing - first stepspublic class MyFirstTest extends TextCase() { Private MyStringConverter mConverter; public void setUp() { mConverter = new MyStringConverter(); } public testUpperCaseConversion() { String result = mConverter.toUppercase(“ota2011”); assertEquals(“Wrong value”, “OTA2011”, result); }} Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 36
  37. 37. Testing with special Android Mock AndroidTestCase access to a context http://developer.android.com/reference/android/test/AndroidTestCase.html ApplicationTestCase test app lifecycle, inject mock context http://developer.android.com/reference/android/test/ApplicationTestCase.html Activity Testing APItest activity lifecycle, inject mocks, send key or touch events, etc http://developer.android.com/resources/tutorials/testing/activity_test.html http://developer.android.com/guide/topics/testing/activity_testing.html Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 37
  38. 38. Testing with special Android Mockpublic class SpinnerActivityTest extendsActivityInstrumentationTestCase2<SpinnerActivity> {protected void setUp() throws Exception { … mActivity = getActivity(); mSpinner = (Spinner) mActivity.findViewById(R.id.Spinner01); …}public void testSpinnerUI() { this.sendKeys(KeyEvent.KEYCODE_DPAD_CENTER); mPos = mSpinner.getSelectedItemPosition(); mSelection = (String)mSpinner.getItemAtPosition(mPos); assertEquals(resultText, mSelection); Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 38
  39. 39. Testing with special Android Mock ProviderTestCase2 test contentProvicer with isolated contexthttp://developer.android.com/guide/topics/testing/contentprovider_testing.html ServiceTestCase test the service lifecycle, not the logic (detached) http://developer.android.com/guide/topics/testing/service_testing.html ViewAsserts, MoreAsserts extended assertsAndroid Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 39
  40. 40. Test automation with monkey adb shell monkey -p your.package.name -v 500 sends sequences of random events http://developer.android.com/guide/developing/tools/monkey.html monkeyrunnerA Python program that runs an application, sends keystrokes to it, takes screenshots of its user interface, and stores them http://developer.android.com/guide/developing/tools/monkeyrunner_concepts.html Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 40
  41. 41. Testing with external tools RobotiumAutomatic black-box test cases for Android applications, with gesture and actions http://code.google.com/p/robotium/ Robolectric Fast and easy TDD, runs tests in normal JavaVM with mock Android classes, no need to deploy on devicehttp://pivotal.github.com/robolectric/ Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 41
  42. 42. Honeycomb and Backward CompatibilityNowadays Android has two separate branches, but Ice Cream Sandwich will merge themAvoid different versions of same app and prefer one adaptive Use alternative resources AndroidManifest.xml filters for sdk, screen, hw Put some dirty if in code http://code.google.com/p/iosched/ Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 42
  43. 43. Honeycomb and Backward Compatibility Resourcesres/layout/main_activity.xml # For phonesres/layout-xlarge/main_activity.xml # Large screenres/layout-sw600dp/main_activity.xml # For 7” tabletsres/layout-sw720dp/main_activity.xml # For 10” tablets… and much more! http://android-developers.blogspot.com/2011/07/new-tools-for-managing-screen- sizes.html Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 43
  44. 44. Honeycomb and Backward Compatibility<!-- Tablet-only application --><manifest ... > <supports-screens android:smallScreens="false" android:normalScreens="false" android:largeScreens="false" android:xlargeScreens="true" android:requiresSmallestWidthDp="600" /> <application ... > ... </application></manifest> http://android-developers.blogspot.com/2011/09/preparing-for-handsets.html http://android-developers.blogspot.com/2011/07/new-mode-for-apps-on-large- screens.html Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 44
  45. 45. Testing with special Android Mock Dirty ifprivate static boolean fragmentsSupported = false;private static void checkFragmentsSupported()throws NoClassDefFoundError { fragmentsSupported = android.app.Fragment.class != null;}static { try { checkFragmentsSupported(); } catch (NoClassDefFoundError e) { fragmentsSupported = false; } Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 45
  46. 46. Testing with special Android Mock@Overridepublic void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Intent intent = null; if (!fragmentsSupported) intent = new Intent(this, MainNonFragmentActivity.class); else intent = new Intent(this, MainFragmentActivity.class); startActivity(intent); finish(); }}http://blog.radioactiveyak.com/2011/02/strategies-for-honeycomb-and-backwards.html Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 46
  47. 47. Honeycomb and Backward Compatibility Android Compatibility Package Backport some 3.x APIs to 1.6 and 2.x http://developer.android.com/sdk/compatibility-library.html Support for Fragment, Loader, ViewPager Native code on 3.x, library code on 2.xAndroid Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 47
  48. 48. Honeycomb and Backward Compatibility Fragmenthttp://android-developers.blogspot.com/2011/03/fragments-for-all.htmlAndroid Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 48
  49. 49. Honeycomb and Backward Compatibility setRetainInstance(true)activity is rotated but fragment is not destroyed and recreated, lifecycle events are called. Finally! Bug: http://code.google.com/p/android/issues/detail?id=17423 Bug: http://stackoverflow.com/questions/6250580/fragment-already-added- illegalstateexception Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 49
  50. 50. Honeycomb Backward Compatibility ActionBarSherlockLibrary that uses native code for 3.x or its own code for 2.x http://actionbarsherlock.com/ GreenDroid Brand new actionbar implementation http://android.cyrilmottier.com/?p=274 Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 50
  51. 51. Useful libraries and resources Android UI patterns blogs http://www.androiduipatterns.com http://www.androidpatterns.com Android-ui-utils Asset Studio, Pencil stencils, icon templates http://code.google.com/p/android-ui-utils/ Additional Eclipse plugins for Android sorce code, api level analysis http://code.google.com/p/adt-addons/ Maven Android plugin http://code.google.com/p/maven-android-plugin/Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 51
  52. 52. Useful libraries and resources Kernel source to learn, to get inspired and to solve bugs!http://grepcode.com/snapshot/repository.grepcode.com/java/ext/com.google.android/andro id/2.3.4_r1/ Clean code in Android IoC, Binding, Annotation etc http://blog.springsource.com/2011/08/26/clean-code-with-android Crash report http://androidblogger.blogspot.com/2010/03/crash-reporter-for-android-slight.html Android Survival Guide Alfredo Morresi (http://www.rainbowbreeze.it) Slide 52
  53. 53. Useful libraries and resourcesUse Apache HTTP library instead of Java.Net Https bugs, bufferization problems, etc http://code.google.com/p/android/issues/detail?id=3164 http://groups.google.com/group/android-developers/msg/4ddd2e502f195e3a http://stackoverflow.com/questions/2105364/ Be part of communities mailing list, StackOveflow, ... http://developer.android.com/resources/community-groups.htmlAndroid Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 53
  54. 54. Conclusion Q&A (example: “Isnt it lunch time yet?”)Android Survival GuideAlfredo Morresi (http://www.rainbowbreeze.it) Slide 54

×