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. 1
    © OCTO 2012
    © OCTO 2012
    Download RoboSpice Demo app

    View Slide

  2. 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

    View Slide

  3. 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

    View Slide

  4. 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

    View Slide

  5. 5
    © OCTO 2012
    WHY ASYNCTASK ARE FLAWED

    View Slide

  6. 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

    View Slide

  7. 7
    © OCTO 2012
     
     
     
     
     
    private  class  GetAllPersonTask  extends  AsyncTask>  {  
     
     @Override  
     protected  List  doInBackground(String...  urls)  {  
       //long  running  computation  here  
       return  dataSourceOrDomainModel.getListPerson(  progressHandler  );  
     }  
                     
     @Override  
     protected  void  onPostExecute(List  result)  {  
       //update  your  UI  here  
       listPerson.clear();  
             listPerson.addAll(result);  
             personListAdapter.notifyDataSetChanged();  
     }  
    }  

    View Slide

  8. 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

    View Slide

  9. 9
    © OCTO 2012
    WHY LOADERS DON’T FIT NETWORKING

    View Slide

  10. 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

    View Slide

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

    View Slide

  12. 12
    © OCTO 2012
    Public  class  PersonLoader  extends  AsyncTaskLoader>  {  
     
           public  PersonLoader(Context  context)  {  
                   super(context);  
           }  
     
           @Override  
           public  List  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...

    View Slide

  13. 13
    © OCTO 2012
    THERE IS A BETTER WAY : RoboSpice

    View Slide

  14. 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

    View Slide

  15. 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

    View Slide

  16. 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

    View Slide

  17. 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

    View Slide

  18. 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

    View Slide

  19. 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  );  
     }  

    View Slide

  20. 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  );  
           }  
     
     
     
     
     
     

    View Slide

  21. 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  );  
           }  
    }  

    View Slide

  22. 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  );  
     }  
    }  

    View Slide

  23. 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

    View Slide

  24. 24
    © OCTO 2012
    Any questions ??
    Or comments !!

    View Slide

  25. 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;  
           }  
    }  

    View Slide