86
ASYNCHRONOUS TECHNIQUES FOR ANDROID: PROGRAMMING SIDEWAYS Emanuele Di Saverio AND02 Senior Design Technologist [email protected] hazam emanueledisaverio

Programming Sideways: Asynchronous Techniques for Android

Embed Size (px)

DESCRIPTION

Android apps need to respond fast, support highly parallel execution and multi component architecture. Learn some tricks of the trade for these problems! as presented at www.mobileconference.it (2013 edition)

Citation preview

Page 1: Programming Sideways: Asynchronous Techniques for Android

ASYNCHRONOUS TECHNIQUES FOR ANDROID: PROGRAMMING SIDEWAYS

Emanuele  Di  Saverio  

AND02

                   Senior  Design  Technologist  

[email protected]  hazam  emanueledisaverio  

Page 2: Programming Sideways: Asynchronous Techniques for Android

Who?

"Agilist  in  a  Mobile  world"  •  Mobile  Java  Developer  (2007)  •  Android  (2009)  •  h@p://www.androidavanzato.it  (2012)  

Emanuele  Di  Saverio  Senior  Design  Technologist  @  

Page 3: Programming Sideways: Asynchronous Techniques for Android

TWO RECURRING PROBLEMS, WITH SIMILAR SYMPTOMS

Page 4: Programming Sideways: Asynchronous Techniques for Android

1ST PROBLEM

Page 5: Programming Sideways: Asynchronous Techniques for Android

A (biased) TALE ABOUT SERVERS

Page 6: Programming Sideways: Asynchronous Techniques for Android

The S in C/S

•  a  server  program  in  (connected)  network  compuKng  

while (true) {connect();read();parseRequest();process();sendResponse();disconnect();

}

Page 7: Programming Sideways: Asynchronous Techniques for Android

MPM Prefork (Apache)

•  let's   fork() and  spawn  more  processes!  

full  address  space  copied  around  

Page 8: Programming Sideways: Asynchronous Techniques for Android

MPM Worker (Apache)

•  handful  processes  spawn  a  set  of  threads  

context  switch  +  shared  memory  

Page 9: Programming Sideways: Asynchronous Techniques for Android

Multi Threaded Programming

•  Memory  is  shared,  threads  spawn  faster  •  Problem  of  synchronizaKon  –  solvable  only  with  low-­‐level  OS  primiKves  

Page 10: Programming Sideways: Asynchronous Techniques for Android

Multi Threaded Programming

•  Memory  is  shared,  threads  spawn  faster  •  Problem  of  synchronizaKon  –  solvable  only  with  low-­‐level  OS  primiKves  

"…  non-­‐trivial  mul/-­‐threaded  programs  are  incomprehensible  to  humans.  It  is  true  that  the  programming  model  can  be  improved:  design  pa;erns,  atomicity,  improved  languages,  and  formal  methods.  However,  these  techniques  merely  chip  away  at  the  unnecessarily  enormous  non-­‐determinism  of  the  threading  model.  The  model  remains  intrinsically  intractable."  

Edward  A.  Lee  –  The  Problem  with  Threads  

Page 11: Programming Sideways: Asynchronous Techniques for Android

CONTEXT SWITCH has  fixed  cost.  

Page 12: Programming Sideways: Asynchronous Techniques for Android

Context Switch

Page 13: Programming Sideways: Asynchronous Techniques for Android

Context Switch

hint:  human  mind  work  same  way  

Page 14: Programming Sideways: Asynchronous Techniques for Android

Single Thread Event

Old  technique  –  New  Trend  

Nginx / NodeJS / Jetty

•  User  Code  is  executed  by  single  thread  

•  I/O  is  on  separate  thread  

Page 15: Programming Sideways: Asynchronous Techniques for Android

MOBILE UI ARCHITECTURE a.k.a.  looked  from  a  high  enough  level,  they're  all  the  same.    

Page 16: Programming Sideways: Asynchronous Techniques for Android

The Loop

while (true) {processInputEvents();processSysEvents();measure();layout();draw();

}

input  

sys  

measure  

layout  

draw  

thread  

Page 17: Programming Sideways: Asynchronous Techniques for Android
Page 18: Programming Sideways: Asynchronous Techniques for Android

Ok, when it is my turn?

HOLLYWOOD  PRINCIPLE  

"don't  call  me,  I'll  call  you"  managed  execuKon  

LISTENERS  

Button a;[...]a.setOnClickListener(new View.OnClickListener() {

public void onClick(View v) {//do stuff}

});

object  that  receives  callback  through  define  interface  

class MyActivity extends Activity {protected void onCreate(Bundle b) {

//create my UI}onStop() {...}onStart(){...}}

Page 19: Programming Sideways: Asynchronous Techniques for Android

The Android Loop

All  callbacks  are  executed  in  Main  Thread!  •  AcKvity  •  Service  •  Fragment  •  animaKons  •  OnClicks  •  OnTouch  •  OnWhatever...      

Page 20: Programming Sideways: Asynchronous Techniques for Android

android.os.Looper

Make  every  thread  an  event-­‐based  message  queue  

public void run() {Looper.prepare();this.handler = new Handler() handleMessage(int what) if (what == 0x666) //do stuff};Looper.loop();}

handler.sendMessage(Message.obtain(0x666));

Page 21: Programming Sideways: Asynchronous Techniques for Android

60 FPS -> 16 ms per frame ALL YOUR CODE NEEDS TO FIT IN 16ms

Page 22: Programming Sideways: Asynchronous Techniques for Android

The Loop

while (true) {processInputEvents();processSysEvents();measure();layout();draw();

}

input  

sys  

measure  

layout  

draw  

thread  16ms  

Page 23: Programming Sideways: Asynchronous Techniques for Android

DON'T BLOCK UI THREAD no  network  calls  -­‐  no  file  I/O  -­‐  no  intensive  computaKon  

Page 24: Programming Sideways: Asynchronous Techniques for Android

DON'T BLOCK UI THREAD no  network  calls  -­‐  no  file  I/O  -­‐  no  intensive  computaKon  

USE OTHER THREADS!

Page 25: Programming Sideways: Asynchronous Techniques for Android

Asynchronous Java

Java was designed with multithreaded programming in mind (thread ,synchronized, volatile, memory model). Don't rely on that – probabilities you really understand what they do are small. java.util.concurrent.* full of goodies to handle concurrency

Page 26: Programming Sideways: Asynchronous Techniques for Android

Asynchronous Java

You don't really create Threads that much Executors – Thread pool implemented for you

ExecutorService executor = Executors.newFixedThreadPool(10);executor.execute(new Runnable() {

run() { //do stuff}

});

Page 27: Programming Sideways: Asynchronous Techniques for Android

Future – a computation Stock Option

Want  to  have  result  of  an  async  execuKon?  

Future<String> f1 = executor.submit(new Callable<String> {String call() { return fetchNetworkContent();}

});

f1.get(); //locks current thread

Page 28: Programming Sideways: Asynchronous Techniques for Android

Future – combining? Future<String> f1 = executor.submit(...);Future<Integer> f2 = executor.submit(...); Future<Integer> f3 = executor.submit(new [CALLABLE](f1.get()));Future<Integer> f4 = executor.submit(new [CALLABLE]f2.get()));

Page 29: Programming Sideways: Asynchronous Techniques for Android

Future – combining? Future<String> f1 = executor.submit(...);Future<Integer> f2 = executor.submit(...); Future<Integer> f3 = executor.submit(new [CALLABLE](f1.get()));Future<Integer> f4 = executor.submit(new [CALLABLE]f2.get()));Future<String> f3 = executor.submit(new Callable<String>() {call() {return new CallToRemoteServiceC(f1.get()).call();

}});

Page 30: Programming Sideways: Asynchronous Techniques for Android

Future – Other Approaches List<Future> futures = new ArrayList<Future>();Iterator<Future<?>> i = futures.iterator();while (i.hasNext()) { Future<?> f = i.next(); if (f.isDone()) { doMoreWork(f.get());

i.remove();} }

Page 31: Programming Sideways: Asynchronous Techniques for Android

GET() BLOCKS COMBINATION IS A PAIN

Page 32: Programming Sideways: Asynchronous Techniques for Android

Callback

Gets  around  the  early  blocking  problem  by  pre-­‐declaring  the  funcKon  that  will  be  executed  

public interface Callback<T> { public void done(T result, Exception error);

}

Page 33: Programming Sideways: Asynchronous Techniques for Android

Callback fetchNetworkContentAsync(Callback<Response> cb) {mExecutor.execute(new Runnable(){...try { Response r = fetchNetworkContent(); cb.done(r, null);} catch(Exception exc) { cb.done(null, exc);});

}

Page 34: Programming Sideways: Asynchronous Techniques for Android

WAIT, WE NEED TO BE IN MAIN THREAD

Page 35: Programming Sideways: Asynchronous Techniques for Android

Callback fetchNetworkContentAsync(Callback<Response> cb) {mExecutor.execute(new Runnable(){...try { Response r = fetchNetworkContent(); mHandler.post(new Runnable() { cb.done(r, null); });} catch(Exception exc) { cb.done(null, exc);});

}

Page 36: Programming Sideways: Asynchronous Techniques for Android

Callback fetchNetworkContentAsync(Callback<Response> cb) {mExecutor.execute(new Runnable(){...try { Response r = fetchNetworkContent(); mExecutor.execute(new Runnable() { try { Response r2 = fetchNetworkContent2(r); mHandler.post(new Runnable() { cb.done(r2, null); });

} catch(Exception exc) { cb.done(null, exc);});

});} catch(Exception exc) { cb.done(null, exc);});

}

Page 37: Programming Sideways: Asynchronous Techniques for Android

Callback fetchNetworkContentAsync(Callback<Response> cb) {CountDownLatch cd = new CountDownLatch(2);Response r1, r2;mExecutor.execute(new Runnable(){ Response r1 = fetchNetworkContent(); cd.countDown();});mExecutor.execute(new Runnable(){ Response r2 = fetchNetworkContent(); cd.countDown();});mExecutor.execute(new Runnable(){ cd.await(); Response r = new Response(r1,r2); mHandler.post(new Runnable() { cb.done(r, null); });});

}

Page 38: Programming Sideways: Asynchronous Techniques for Android

ANDROID SDK HELP

Page 39: Programming Sideways: Asynchronous Techniques for Android

Loader & AsyncTask

They  help  in  the  field  of  gedng  the  asynchronous  task  happen  in  a  way  that  is  compaKble  with  Android  threading  model,  but  fall  short  in:  •  Combining  •  ManipulaKng  •  Error  Handling  •  Streaming  Data  Handling  

Page 40: Programming Sideways: Asynchronous Techniques for Android

AsyncTask

Page 41: Programming Sideways: Asynchronous Techniques for Android

NEED MORE ASYNC EXPRESSIVENESS a.k.a.  my  head  is  hurKng  

Page 42: Programming Sideways: Asynchronous Techniques for Android

ENTER REACTIVE EXTENSIONS

Page 43: Programming Sideways: Asynchronous Techniques for Android
Page 44: Programming Sideways: Asynchronous Techniques for Android

Reactive Extensions (Rx)

Developed  by  Microsof  for  .NET  (C#)  2009  –  Erik  Meijer  -­‐  to  support  distributed  cloud  applicaEons    Open  Source  port  of  the  semanKcs  to  •  Rx.ObjC,  RxJava,  Rx.JS,  Scala  

•  JavaVM  based  version  is  developed  by  Nejlix  –  Ben  Christensen  

Page 45: Programming Sideways: Asynchronous Techniques for Android

Rx (Java): Concepts

Observable  EnKty  that  can  fetch  a  stream  of  events  asyncronously,  if  you  subscribe  an  observer  to  it    Observer  You  can  imperaKvely  noKfy  an  observer  about  an  event          

Page 46: Programming Sideways: Asynchronous Techniques for Android

Rx (Java): Sample Observable<Employee> loadEmployeeWithName(String name) { Observable<Employee> observable = Observable.create(

new Func1<Observer<Employee>, Subscription>() { public Subscription call(final Observer<Employee> observer) {

List<Employee> employee = loadEmployeeFromDB(name); for (Employee emp : employees) { try {

observer.onNext(emp); } catch (Exception e) { observer.onException(e); }}

observer.onCompleted(); return Subscriptions.empty(); } });return observable;}

loadEmployeeWithName("Aldo").subscribe(new Observer<Employee>() {

public void onNext(Employee emp) { showEmployeeDataOnScreen(emp); } public void onError(Exception e) { handleException(e); }

public void onCompleted() { doneLoadingEmployees();

}});

Page 47: Programming Sideways: Asynchronous Techniques for Android

"Async" expressed for collections

IMPERATIVE  

•  T  next()  •  throws  ExcepKon  •  return  

REACTIVE  

•  onNext(T)  •  onError(ExcepKon)  •  onCompleted()  

Page 48: Programming Sideways: Asynchronous Techniques for Android

Rx (Java): Sample Observable<Employee> loadEmployeeWithName(String name) { Observable<Employee> observable = Observable.create(

new Func1<Observer<Employee>, Subscription>() { public Subscription call(final Observer<Employee> observer) {

List<Employee> employee = loadEmployeeFromDB(name); for (Employee emp : employees) { try {

observer.onNext(emp); } catch (Exception e) { observer.onException(e); }}

observer.onCompleted(); return Subscriptions.empty(); } });return observable;}

loadEmployeeWithName("Aldo").subscribe(new Observer<Employee>() {

public void onNext(Employee emp) { showEmployeeDataOnScreen(emp); } public void onError(Exception e) { handleException(e); }

public void onCompleted() { doneLoadingEmployees();

}});

STILL  SYNC  

Page 49: Programming Sideways: Asynchronous Techniques for Android

Rx (Java): Sample Observable<Employee> loadEmployeeWithName(String name) { Observable<Employee> observable = Observable.create(

new Func1<Observer<Employee>, Subscription>() { public Subscription call(final Observer<Employee> observer) { executor.postRunnable(new Runnable() {...

List<Employee> employee = loadEmployeeFromDB(name);

for (Employee emp : employees) { try { mHandler.post(new Runnable() { ...

observer.onNext(emp); ... } } catch (Exception e) {

mHandler.post(new Runnable() { ...

observer.onException(e); }) }}

mHandler.post(new Runnable() { observer.onCompleted(); });

return Subscriptions.empty(); } }); });return observable;}

Page 50: Programming Sideways: Asynchronous Techniques for Android

So what is Rx really doing?

Rx  is  man-­‐in-­‐the  middle  between  method  calling  and  callback  execuKon    

onNext() != onNext()

We  have  control  over  scheduling  of  methods    

Page 51: Programming Sideways: Asynchronous Techniques for Android

Rx (Java): Sample Observable<Employee> loadEmployeeWithName(String name) { Observable<Employee> observable = Observable.create(

new Func1<Observer<Employee>, Subscription>() { public Subscription call(final Observer<Employee> observer)

{ List<Employee> employee = loadEmployeeFromDB(name);

for (Employee emp : employees) { try {

observer.onNext(emp); } catch (Exception e) { observer.onException(e); }}

observer.onCompleted(); return Subscriptions.empty(); } });observable = observable.subscribeOn(Schedulers.executor(mExecutor));observable = observable.observeOn(AndroidScheduler.getInstance());return observable;}

Page 52: Programming Sideways: Asynchronous Techniques for Android

Rx (Java): Sample Observable<Employee> loadEmployeeWithName(String name) { Observable<Employee> observable = Observable.create(

new Func1<Observer<Employee>, Subscription>() { public Subscription call(final Observer<Employee> observer)

{ List<Employee> employee = loadEmployeeFromDB(name);

for (Employee emp : employees) { try {

observer.onNext(emp); } catch (Exception e) { observer.onException(e); }}

observer.onCompleted(); return Subscriptions.empty(); } });observable = observable.subscribeOn(Schedulers.executor(mExecutor));observable = observable.observeOn(AndroidScheduler.getInstance());return observable;}

loadEmployeeWithName("Aldo").subscribe(new Observer<Employee>() {

public void onNext(Employee emp) { showEmployeeDataOnScreen(emp); } public void onError(Exception e) { handleException(e); }

public void onCompleted() { doneLoadingEmployees();

}});

Page 53: Programming Sideways: Asynchronous Techniques for Android

Rx (Java): Features

Observer  is  executed  afer  someone  subscribed    Since  we  are  decoupling  method  call  and  callback  execuKon,  we  can  easily  manipulate  and  combine.  

Page 54: Programming Sideways: Asynchronous Techniques for Android

Chain Observables

Observable.concat(obs1,  obs2);  

Page 55: Programming Sideways: Asynchronous Techniques for Android

Filter Observables

Observable.filter(obs1,  new  Func1<>()  {});  

Page 56: Programming Sideways: Asynchronous Techniques for Android

Zip Observables

Observable.zip(obs1,  obs2,  new  Func1<a,b>()  {});  

Page 57: Programming Sideways: Asynchronous Techniques for Android

Rx (Java): Features

Each  observer  can  be  scheduled  to  have  his  subscribe  happen  on  any  thread,  and  all  observaKon  happen  on  any  other  thread!  Observable<Image> getImage(URL url) {

AtomicBoolean found = new AtomicBoolean(false);obs1 = //get image from in memory cacheobs2 = //get image from disc cacheobs2 = obs2.subscribeOn(Schedulers.executor(highprioexecutor)) .observeOn(AndroidScheduler.getInstance());obs3 = //get image from networkobs3 = obs3.subscribeOn(Schedulers.executor(lowprioexecutor)) .observeOn(AndroidScheduler.getInstance()); return Observable.concat(obs1, obs2, obs3);

}

Page 58: Programming Sideways: Asynchronous Techniques for Android

Rx (Java): Features

Connectable  version  of  Observable  can  be  subscribed  mulKple  Kmes,  doesn't  restart  but  goes  on,  can  even  replay  past  events!  Observable<Tweet> obs = createObservableThatStreamTweet();void initObs() {

obs.replay();obs = obs.connect();

}Observable<Tweet> getPopularTweets() {

return obs;}

Page 59: Programming Sideways: Asynchronous Techniques for Android

Reactive the world

•  We  could  wrap  all  applicaKon  in  reacKves:    click  events  could  generate  events  that  can  route  to  DB  calls.  View  could  subscribe  to  DB  observable  and...    

Yes.  Maybe.  

Page 60: Programming Sideways: Asynchronous Techniques for Android
Page 61: Programming Sideways: Asynchronous Techniques for Android

Reactive Over Services

<<sync>>  Employee  DAO  

<<sync>>  Paypal  API  

<<async>>  Android  NFC  Intents  

RX  Layer  

UI  /  Controllers  

FragmentA   FragmentA  AcKvity   Views  

Page 62: Programming Sideways: Asynchronous Techniques for Android

2ND PROBLEM

Page 63: Programming Sideways: Asynchronous Techniques for Android

Fragments

Page 64: Programming Sideways: Asynchronous Techniques for Android

Fragments

NOT A UI but a LIFECYCLE ABSTRACTION!

Page 65: Programming Sideways: Asynchronous Techniques for Android

Fragments

•  OS  can  create  new  instances  you  don't  know  about  

•  Retrieve  with  findByTag()  

•  Can  be  a@ached  to  one  of  many  AcKviKes  subclass  

Page 66: Programming Sideways: Asynchronous Techniques for Android

Fragments / Communication public class MasterFragment extends Fragment { private Listener listener; public interface Listener { void onItemSelected(int position){} onAttach(Activity a) { super.onAttach(a); listener = (Listener) a;

}}

public class HomeActivity extends Activity implements MasterFragment.Listener {onItemSelected(int position) {

}}

Page 67: Programming Sideways: Asynchronous Techniques for Android

Fragments / Communication

AcKvity1  

FragmentA   FragmentB  

AcKvity2  

FragmentC  

AcKvity3  

FragmentA   FragmentD  

FragmentC  

Page 68: Programming Sideways: Asynchronous Techniques for Android

Fragments / Communication public class HomeActivity extends Activity implements MasterFragment.Listener,DetailFragment.Listener,PopupFragment.Listener {...}}

ListFragment lf = getFragmentManager().findFragmentByTag("LIST");if (lf == null) {getActivity().onItemSelected();

}

Page 69: Programming Sideways: Asynchronous Techniques for Android

Need a Bus

Page 70: Programming Sideways: Asynchronous Techniques for Android

Event Bus

AcKvity1  

FragmentA  

FragmentB  

BUS  

AcKvity2  

FragmentQ  

AcKvity1  

Service  

Page 71: Programming Sideways: Asynchronous Techniques for Android

Event Bus

AcKvity1  

FragmentA  

FragmentB  

BUS  

AcKvity2  

FragmentQ  

AcKvity1  

Service  

Page 72: Programming Sideways: Asynchronous Techniques for Android

Excellent  library  by                                  :  OMo  

Event Bus

•  Also  called  Publish  /  Subscribe  in  distributed  systems  

•  An  agent  posts  a  message  on  an  event  (topic)  •  All  objects  registered  on  that  topic,  receive  event  

•  Decouple  caller  by  receiver  +  synchronous  delivery  

Page 73: Programming Sideways: Asynchronous Techniques for Android

Otto

bus.post(new AnswerAvailableEvent(42));

bus.register(this);...@Subscribe public void answerAvailable(AnswerAvailableEvent event) { // TODO: React to the event somehow!}...bus.unregister(this);

static Bus bus = new Bus();

Page 74: Programming Sideways: Asynchronous Techniques for Android

Otto

•  Event  delivered!  •  O@o  is  not  rocket  science:  

•  ReflecKon  to  spot  methods  that  declare  to  handle  some  object  as  event  

•  search  for  method  that  accept  some  event  and  deliver  the  event  

•  More  features...  

Page 75: Programming Sideways: Asynchronous Techniques for Android

Otto

•  Event  delivered!  •  O@o  is  not  rocket  science:  

•  ReflecKon  to  spot  methods  that  declare  to  handle  some  object  as  event  

•  search  for  method  that  accept  some  event  and  deliver  the  event  

•  More  features...  

Remember  to  call  unregister()!    Memory  (acKvity)  leak  danger  

Page 76: Programming Sideways: Asynchronous Techniques for Android

DIY BUS

Page 77: Programming Sideways: Asynchronous Techniques for Android

DIY Bus

events  =  integers    parameters  =  object  or  integers    MyObject obj = createMyObject();Bus.i().publish(0x2324, obj);

Bus.i().subscribe(new Invokable() {invoke(int event, Object param) { MyObject obj = (MyObject) param;}

}, 0x2324);

Page 78: Programming Sideways: Asynchronous Techniques for Android

DIY Bus

events  =  integers    parameters  =  object  or  integers    MyObject obj = createMyObject();Bus.i().publish(0x2324, obj);

Bus.i().subscribe(new Invokable() {invoke(int event, Object param) { MyObject obj = (MyObject) param;}

}, 0x2324);

Bus.java  is  90  lines  of  code!    

Page 79: Programming Sideways: Asynchronous Techniques for Android

WRAPPING UP!

Page 80: Programming Sideways: Asynchronous Techniques for Android

BOOST JAVA OBJ-C C# JS you  need  to  work  your  way  towards  asynchronous  expressiveness  

Page 81: Programming Sideways: Asynchronous Techniques for Android

SIMPLE ABSTRACTIONS CAN TURN YOUR WORLD Rx  is  a  simple  abstracKon  that  enables  a  truckload  of  features  Event  Bus  is  so  old,  is  so  simple,  and  works  so  well.  

Page 82: Programming Sideways: Asynchronous Techniques for Android

SERVER & CLIENT scale  is  orders  of  magnitude  smaller,    different  problems,  same  techniques.  

Page 83: Programming Sideways: Asynchronous Techniques for Android

:)

Page 84: Programming Sideways: Asynchronous Techniques for Android

QUESTIONS &

ANSWERS

Page 85: Programming Sideways: Asynchronous Techniques for Android

Links

•  RxJava  by  Nejlix  hMps://github.com/NePlix/RxJava/wiki  

•  O@o  by  Square  hMp://square.github.io/oMo  

•  DIY  Bus  hMps://gist.github.com/hazam/8ac4abd927588d0bd04b  

•  EPFL  ReacKve  on  Coursera  hMps://www.coursera.org/course/reacEve  

Page 86: Programming Sideways: Asynchronous Techniques for Android

Grazie. Non  dimenKcare  di  riempire  il  modulo  di  feedback  

AND02 [email protected]  hazam  emanueledisaverio