Upgrade to Pro — share decks privately, control downloads, hide ads and more …

RoboSpice presentation

RoboSpice presentation

RoboSpice is an Android Library that makes it easier to write asynchronous network requests. It is production-ready, open sourced and includes a large range of features.

https://github.com/octo-online/robospice

stephanenicolas

June 18, 2013
Tweet

More Decks by stephanenicolas

Other Decks in Programming

Transcript

  1. 2 © OCTO 2012 © OCTO 2012 Asynchronous Network Requests

    Made Easy Co-authors : •  Stéphane Nicolas •  Jérôme Van Der Linden •  Riccardo Ciovatti •  Maxence Walbrou •  Matthieu Hausherr
  2. 3 © OCTO 2012 © OCTO 2012 Presentation plan :

    u  Why AsyncTasks are flawed u  Why loaders don't fit for networking u  What RoboSpice has to offer
  3. 4 © OCTO 2012 © OCTO 2012 Server Side Many

    Mobile Apps are content driven : They basically display content delivered through Web services. RoboSpice eases writing those network requests. Web Services Network Requests Data Base
  4. 6 © OCTO 2012 AsyncTask LifeCycle AsyncTasks offer : • 

    An asynchronous way to execute code. •  A clean encapsulated way to group asynchronous code and callback code. •  The ability to execute callback code in the UI thread (allow to manipulate widgets). onPreExecute onPostExecute onProgressUpdate doInBackground
  5. 7 © OCTO 2012           private

     class  GetAllPersonTask  extends  AsyncTask<String,  Void,  List<Person>>  {      @Override    protected  List<Person>  doInBackground(String...  urls)  {      //long  running  computation  here      return  dataSourceOrDomainModel.getListPerson(  progressHandler  );    }                      @Override    protected  void  onPostExecute(List<Person>  result)  {      //update  your  UI  here      listPerson.clear();            listPerson.addAll(result);            personListAdapter.notifyDataSetChanged();    }   }  
  6. 8 © OCTO 2012 Recipe for a memory leak !

    Async Task Activity New Activity Async Task AsyncTasks have one BIG trouble : They are poorly tied to the activity life cycle ! u  An activity can die during asynchronous code execution. u  Callback will be executed even if activity is not showing up anymore and any attempt to manipulate widgets will crash the app or fail, at best. → AsyncTask create memory leaks ! u  It is possible to improve the link between AsyncTask and Activities, but you need a lot of code and caution to achieve this. → Loaders to the rescue Process
  7. 10 © OCTO 2012 Activity Loader Api Loaders : • 

    handle activities lifecycles •  monitor data changes update UI config changes create reset Loaders to the rescue Loader Manager Loader Callbacks Loader
  8. 11 © OCTO 2012 public  class  LoaderTestActivity2  extends  ListActivity  

       implements  LoaderManager.LoaderCallbacks<List<Person>>  {      private  Loader<List<Person>>  personLoader;      @Override    public  Loader<List<Person>>  onCreateLoader(int  arg0,  Bundle  arg1)  {            return  personLoader;    }      @Override    public  void  onLoadFinished(Loader<List<Person>>  personLoader,                      List<Person>  result)  {            listPerson.clear();            listPerson.addAll(result);            personListAdapter.notifyDataSetChanged();    }      @Override    public  void  onLoaderReset(Loader<List<Person>>  loader)  {            listPerson.clear();            personListAdapter.notifyDataSetChanged();    }   //..  loader  follows,  as  an  inner  class  
  9. 12 © OCTO 2012 Public  class  PersonLoader  extends  AsyncTaskLoader<List<Person>>  {

               public  PersonLoader(Context  context)  {                  super(context);          }            @Override          public  List<Person>  loadInBackground()  {                  return  dataSourceOrDomainModel.getListPerson(  progressHandler  );          }   }   Loaders have been designed for cursors, they don't fit when it comes to networking : Asynchronous code is too tied to Activity life cycle. •  Request's result is lost when you leave the Activity. •  If you leave the Activity, request dies : users MUST wait for result •  (they can go to other apps but not to other activities within the app). •  Exception management is left to the dev without any support. •  And code is a bit bloated by generics...
  10. 14 © OCTO 2012 RoboSpice Api RoboSpice uses an Android

    Service to process network requests. RoboSpice is designed for asynchronous networking. Activity Spice Manager Spice Service Request Listener Request notify listeners update UI execute process
  11. 15 © OCTO 2012 RoboSpice Api RoboSpice causes no memory

    leaks, it handles Activities life cycles. Activity Spice Manager Spice Service Request Listener Request process execute RoboSpice takes caution of objects’ life cycles and cleans up memory. config changes Activity 2 Spice Manager 2 Request Listener 2 notify listeners update UI
  12. 16 © OCTO 2012 RoboSpice's Service can be bound from

    any Android Context : requests and results can be accessed from all of them. Application Service Activity Activity Fragment Spice Manager Spice Manager Spice Manager Spice Manager Spice Manager Spice Service
  13. 17 © OCTO 2012 RoboSpice provides automatic caching of request

    results. RoboSpice’s request processing. Spice Service Request Already in cache ? è Yes ! è No ! process request save to cache notify listeners of request’s success Request Listener Request Listener Request Listener Request Listener Request Complete notify listeners of request’s success
  14. 18 © OCTO 2012 RoboSpice provides robust asynchronous error handling.

    RoboSpice’s request errors management. Spice Service Request Listener Request Already in cache ? è Yes ! è No ! process request notify listeners of request’s failure Request Listener Request Listener Request Listener Request Complete notify listeners of request’s success
  15. 19 © OCTO 2012 public  class  TweeterSpiceActivity  extends  Activity  {

         private  SpiceManager  spiceManager  =              new  SpiceManager  (  TweeterSpiceService.class  );      private  TweetRequestListener  listener  =  new  TweetRequestListener();      @Override    protected  void  onStart()  {                  super.onStart();                  spiceManager.start(  this  );    }      @Override    protected  void  onStop()  {                  spiceManager.shouldStop();                  super.onStop();    }      public  void  startDemo()  {                  spiceManager.execute(new  TweetRequest(),  "tweets",        DurationInMillis.ONE_MINUTE  *  10,  listener  );    }  
  16. 20 © OCTO 2012            

           @Override          protected  void  onStart()  {                  super.onStart();                  spiceManager.start(  this  );                  spiceManager.addListenerIfPending(  ListTweets.class,                          "tweets",                          listener  );                  spiceManager.getFromCache(  ListTweets.class,                      "tweets“,                            DurationInMillis.ALWAYS  ,                      listener  );          }              
  17. 21 © OCTO 2012 public  class  TweetRequest  extends  RestSpiceRequest<  ListTweets

     >  {            public  TweetRequest()  {                  super(  ListTweets.class  );          }            @Override          public  ListTweets  loadDataFromNetwork()  throws  Exception  {                  return  getRestTemplate().getForObject(                                  "http://search.twitter.com/search.json?q=android&rpp=20",                ListTweets.class  );          }   }  
  18. 22 © OCTO 2012   private  class  TweetRequestListener  implements  RequestListener<

     ListTweets  >,   RequestProgressListener  {      @Override    public  void  onRequestFailure(  SpiceException  exception)  {    Toast.makeText(  TweeterSpiceActivity.this,  "Failed  to  load  Twitter  data.",                  Toast.LENGTH_SHORT  ).show();    }      @Override    public  void  onRequestSuccess(  ListTweets  listTweets  )  {      mAdapter.clear();      for  (  Tweet  tweet  :  listTweets.getResults()  )  {        mAdapter.add(  tweet.getText()  );      }      mAdapter.notifyDataSetChanged();    }      @Override    public  void  onRequestProgressUpdate(  RequestProgress  progress  )  {      String  status  =  convertProgressToString(  progress  );      textViewProgress.setText(  status  );    }   }  
  19. 23 © OCTO 2012 RoboSpice is an Open Source Library

    that eases writing asynchronous network requests. It executes requests inside an Android Service. It provides transparent caching. It supports REST out of the box, using Spring Android. RoboSpice features A FULLY OBJECT ORIENTED API POJOs are used to send requests parameters POJOs are used to receive request results There is no restriction on POJO classes used There is no need to implement Serializable or Parcelable. NO MEMORY LEAK, OPTIMAL RESOURCE USAGE Activity / Service life cycles are fully managed There is no memory leak at all Requests are not lost when sender dies Requests results are never lost when sender dies AUTOMATIC CACHING OF REQUESTS RESULTS Caching is fully automatic Supports various formats : XML, JSON, ORM Lite, Text Strings, Binary data EASY TO USE Listeners’ methods are invoked on UI Thread Intuitive API Ease writing integration tests Documentated Available on Maven Central Available on GitHub : http://goo.gl/lw5C7
  20. 25 © OCTO 2012   public  class  TweeterSpiceService  extends  SpringAndroidSpiceService

     {            @Override          public  int  getThreadCount()  {                  return  3;          }            @Override          public  CacheManager  createCacheManager(  Application  application  )  {                  CacheManager  cacheManager  =  new  CacheManager();            //  customize  your  cache  manager  here      return  cacheManager;          }            @Override          public  RestTemplate  createRestTemplate()  {                  RestTemplate  restTemplate  =  new  RestTemplate();                  //  customize  your  rest  template  here                          restTemplate.setMessageConverters(  listHttpMessageConverters  );                  return  restTemplate;          }   }