43
Android development Best Prac*ces Ivan Gavran, Calyx d.o.o.

Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

  • Upload
    vutruc

  • View
    213

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

Android  development  Best  Prac*ces  

Ivan  Gavran,  Calyx  d.o.o.  

Page 2: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

Overview  

•  Android  101  •  Adap:ve  UI  •  Offline  support  •  Networking  :ps  •  Handling  bitmaps  efficiently  •  Conclusion  

Page 3: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

Android  101  

•  Applica:on  Components  – Ac:vi:es/Fragments  – Service  – Content  Providers  – Broadcast  Receivers  

•  Component  Ac:va:on  –  Intents  –  Intent  Filters  

Page 4: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

Android  101  

•  The  Manifest  File  – Component  declara:on  – Component  capabili:es  – Applica:on  Requirements  

•  Applica:on  Resources  –  Images,  audios,  videos  – Layouts  – Strings,  dimensions...  

Page 5: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

The  Good  Parts  

•  Separa:on  of  concerns  – Sources  – Resources  – App  configura:on  

•  Inter-­‐process  communica:on  –  Intents,  Content  Providers  

•  Built  in  services  – Loca:on,  No:fica:on,  Connec:vity...  

Page 6: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

Case  study  

•  Android  app  backed  by  a  REST  Service  •  Requirements:  – Adap:ve  UI  – Offline  support  – Efficiency  

Page 7: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

Lesson  1:  Define  adap:ve  UI  

Page 8: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

Adap:ve  Ac:onbar  

Adap:ve  GridView  

Page 9: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

Adap:ve  Ac:onbar  

Adap:ve  Layout  

Page 10: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

Power  of  resources  <resources>! <item name="restaurant_layout" type="layout"> ! @layout/restaurant_details! </item>!

<bool name="has_two_panes">false</bool>!</resources>!

res/values/layouts.xml  

<resources>! <item name="restaurant_layout" type="layout"> ! @layout/restaurant_details_land! </item>!

<bool name="has_two_panes">true</bool>!</resources>!

res/values-­‐land/layouts.xml  

Page 11: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

!public class MyActivity extends FragmentActivity {!!

@Override!public void onCreate(Bundle savedInstanceState) {!

!super.onCreate(savedInstanceState);!!

!//Set content view based on layout defined !!// for current screen configuration !!

!setContentView(R.layout.activity_restaurant_layout);!!!!// or read any other value...!!if(getResources().getBoolean(R.bool.has_two_panes)){!! !//... we are in landscape!!!}!

}!

Ac:vity  ini:aliza:on  

Page 12: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

Lesson  2:  Use  Loaders  for  loading  data  in  an  

ac:vity  or  fragment  

Page 13: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

The  naive  approach  MyAc:vity  

AsyncTask   REST  client  

class MyActivity extends Activity {!! @Override! public void onCreate(...) {! new MyAsyncTask().execute(...);! }!!}!

class MyAsyncTask extends !!AsyncTask<Pars, Progress, Res>{!

! void onPreExecute(Pars...){! // executed on UI thread! }! Res doInBackground(){! // executed on background thread! }! void onPostExecute(Res){! // executed on UI thread! }!}!

Page 14: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

Problems  with  AsyncTasks  

•  Ac:vity  life  cycle  •  Memory  Leaks  

Page 15: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

MyAc:vity  implements  

LoaderCallbacks  Loader   REST  

client  LoaderManager  

android.app.LoaderManager!!android.app.LoaderManager.LoaderCallbacks!!android.content.Loader<D>!! ↳ android.content.AsyncTaskLoader<D>!

! ! ↳ android.content.CursorLoader!

Loader  API  

Page 16: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

!public class MyActivity extends FragmentActivity !implements LoaderManager.LoaderCallbacks<DomainModel> {!

!@Override!public void onCreate(Bundle savedInstanceState) {!

!super.onCreate(savedInstanceState);!!//... activity setup code!!!

!getLoaderManager().initLoader (0, null, this);!}!

Loader  ini:aliza:on  

Page 17: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

!public class MyActivity extends FragmentActivity !implements LoaderManager.LoaderCallbacks<DomainModel> {!

!//....!public Loader<DomainModel> onCreateLoader(int id, Bundle args) {!

!return new MyCursorLoader(this);!}!!

public void onLoadFinished(Loader<DomainModel> loader,!!DomainModel data) {!!!!mAdapter.swapCursor(data);!

}!!

public void onLoaderReset(Loader<DomainModel> loader) {!!mAdapter.swapCursor(null);!

}!

LoaderCallbacks  interface  implementa:on  

Page 18: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

!public class MyLoader extends AsyncTaskLoader<DomainModel> {!!

!public MyCursorLoader (Context context) {!! !super(context);!!}!!@Override!!protected void onStartLoading() {!! !forceLoad();!

!}!!@Override!!public DomainModel loadInBackground() {!! !return RestClient.get().getDomainModel();!!}!!@Override!

!protected void onReset() {!! !super.onReset();!!}!

Loader  implementa:on  

Page 19: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

Goals  

Adap:ve  UI  

Offline  support  

Efficiency  

Page 20: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

Lesson  3:  Local  Database  and  Sync  Service  

Page 21: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

REST  Client  SyncService  

SqLite  DB  

Ac:vity  Ac:vity  Ac:vity  

Loader  Loader  Loader  

Applica:on  architecture  

Page 22: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

!public class SyncService extends IntentService {!!

!public SyncService() {!! !super("DataSyncService");!!}!!!!@Override!!protected void onHandleIntent(Intent intent) {!! !String action = intent.getAction();!

!! !// get optional sync parameters from the intent!

!! !doSync(...);!!}!

Synchroniza:on  IntentService  

Page 23: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

How  to  refresh  data  in  the  applica:on  

•  Start  sync  service  –  Just  start  service  from  any  part  of  the  applica:on  

•  Restart  Loaders  –  implement  BroadcastReceiver  in  each  Loader  

•  Refresh  UI  –  triggered  by  Loaders!  

Page 24: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

!public class MyCursorLoader extends AsyncTaskLoader<Cursor> {!!

!//...!!

!private static class SyncIntentReceiver extends BroadcastReceiver {!! !final MyReservationsCursorLoader mLoader;!! !public SyncIntentReceiver(MyReservationsCursorLoader loader) {!! ! !mLoader = loader;!

! ! !IntentFilter filter = new IntentFilter(!! ! ! ! !MyAppConstants.ACTION_SYNC_FINISHED);!! ! !mLoader.getContext().registerReceiver(this, filter);!! !}!

!! !@Override!

! !public void onReceive(Context context, Intent intent) {!! ! !mLoader.onContentChanged();!! !}!!}!

!

SyncIntentReciever  

Page 25: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

public class MyCursorLoader extends AsyncTaskLoader<Cursor> {!!private SyncIntentReceiver mObserver; !!@Override!

!protected void onStartLoading() {!! !if (mObserver == null) {!! ! !mObserver = new SyncIntentReceiver(this);!! !}!! !forceLoad();!!}!

!@Override!!protected void onReset() {!! !super.onReset();!! !if (mObserver != null) {!! ! !getContext().unregisterReceiver(mObserver);!! ! !mObserver = null;!

! !}!!}!!private static class SyncIntentReceiver extends BroadcastReceiver {!! !//...!!}!

}!!

SyncIntentReceiver  

Page 26: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

Result  •  Loose  coupling  of  applica:on  and  synchroniza:on  logic  •  Easy  implementa:on  of  applica:on  specific  sync  strategies  

–  Update  triggered  by  app  user  

–  Updates  based  on  changes  on  the  applica:on  server  

–  Loca:on  based  updates  

–  ...  just  start  the  Sync  Service...  

 

Page 27: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

Goals  

Adap:ve  UI  

Offline  support  

Efficiency  

Page 28: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

Lesson  4:  Keep  mobile  data  in  sync  with  the  

applica:on  server  

Page 29: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

Objec:ves  •  Be  efficient:  

–  Data  traffic  costs  

–  Ba`ery  life  

•  Be  invisible  –  Don't  keep  user  wait  

–  Give  users  what  they  want  before  they  have  to  ask  for  it  

Applica:on  Server  

Mobile  device  

Mobile  device  

Web  app  

Page 30: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

Networking  :ps  •  Detect  ac:ve  network  type  

–  WIFI  vs.  cellular  data  

–  Mobile  radio  state  machine  

•  Networking  over  3G  networks  –  Avoid  periodical  data  transfer  –  don't  pull  for  updates  

–  Use  greedy  loading  but  don't  be  too  greedy  

–  Prefetching,  bundling  

•  Google  Cloud  Messaging  –  Push  data  to  mobile  device  

Page 31: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

The  mobile  radio  state  machine  

Radio  Standby   Radio  Low  Power  

Radio  Full  Power  

2s  latency  

1.5s  latency  

Radio  idle  for  ~5-­‐10  seconds  

Radio  idle  for  ~10-­‐60  seconds  

Page 32: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

Google  Cloud  Messaging  

Applica:on  Server  

Mobile  device  

GCM  service  

1  

2  

3  

Register  device  

registra:on  Id  

registra:on  Id  

A

registra:onId  +  Message  

B   Message  

Page 33: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

Lesson  5:  Displaying  Bitmaps  Efficiently  

Page 34: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

Resize  your  images  on  the  server.  

Page 35: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

Load  Large  Bitmaps  Efficiently  

Image  resolu?on   Bitmap  size  (ARGB_8888)  

2048*1536   12  MB  

512*384   0.75  MB  

128*96   0.05  

Page 36: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

public static Bitmap decodeSampledBitmap(InputStream is, int reqWidth, int reqHeight) {!! // First decode with inJustDecodeBounds=true to check dimensions! final BitmapFactory.Options options = new BitmapFactory.Options();!

options.inJustDecodeBounds = true;! BitmapFactory.decodeStream(is, null, options);!! // Calculate inSampleSize! options.inSampleSize = calculateInSampleSize(!

! !options.outWidth, options.outHeight, reqWidth, reqHeight);!

! // Decode bitmap with inSampleSize set! options.inJustDecodeBounds = false;! return BitmapFactory.decodeStream(is, null, options);!}!

Decode  Large  Bitmaps  

Page 37: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

Process  Bitmaps  off  the  UI  thread.  

Page 38: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

class BitmapLoaderTask extends AsyncTask<String, Void, Bitmap> {! private final WeakReference<ImageView> imageViewReference;! public BitmapWorkerTask(ImageView imageView) {!

! !imageViewReference = new WeakReference<ImageView>(imageView);! }!

!@Override!!protected Bitmap doInBackground(String... params) {!! !String url = params[0];!! !InputStream is = ImageLoader.load(url);!

! !return decodeSampledBitmap(is, 100, 100));! }!

!@Override!!protected void onPostExecute(Bitmap bitmap) {!

if (imageViewReference != null && bitmap != null) {! final ImageView imageView = imageViewReference.get();!

if (imageView != null) {! imageView.setImageBitmap(bitmap);! }! }! }!}!

Processing  Bitmaps  Off  the  UI  Thread  

Page 39: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

Caching  Bitmaps  

Page 40: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

private LruCache<String, Bitmap> mMemoryCache;!!@Override!

protected void onCreate(Bundle savedInstanceState) {!!

!final int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);!!

!// Use 1/8th of the available memory for this memory cache.! !final int cacheSize = maxMemory / 8;!

! !mMemoryCache = new LruCache<String, Bitmap>(cacheSize) {! @Override! protected int sizeOf(String key, Bitmap bitmap) {! // The cache size will be measured in kilobytes rather than! // number of items.!

return bitmap.getByteCount() / 1024;! }! };! ...!}!

Caching  Bitmaps  using  LruCache  

Page 41: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

class RetFragment extends Fragment {! !

!private static final String TAG = "RetFragment";!

!public LruCache<String, Bitmap> mRetainedCache;!!

!public static RetFragment getInstance(FragmentManager fm) {! RetFragment fragment = (RetFragment) fm.findFragmentByTag(TAG);! if (fragment == null) {! fragment = new RetFragment();!

}! return fragment;! }!! @Override! public void onCreate(Bundle savedInstanceState) {!

super.onCreate(savedInstanceState);! setRetainInstance(true);! }!}!

Retaining  Cached  Bitmaps  between  orienta:on  changes  

Page 42: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

Goals  

Adap:ve  UI  

Offline  support  

Efficiency  

Page 43: Android’development BestPracces% - · PDF fileAndroid’101 • The’ManifestFile’ – Componentdeclaraon’ – Componentcapabili:es’ – Applicaon’Requirements’ • Applicaon’Resources’

Conclusion  

•  Support  different  devices    

•  Be  invisible  

•  Be  efficient  

•  Be  reliable