Transcript
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  


Recommended