Share
Embed
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
Transcript
25 slides
-
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 -
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 -
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 -
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 -
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(); } } -
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 -
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 -
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 -
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... -
13 © OCTO 2012 THERE IS A BETTER WAY :
RoboSpice -
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 -
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 -
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 -
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 -
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 -
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 ); } -
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 ); } -
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 ); } } -
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 ); } } -
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 -
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; } }