Either you like it or not, application development today is more like playing with building blocks than writing advanced algorithms. Probably 90% of anything you could want to achieve code-wise is already there, and the smartest ones in the room will be those who use that inventory rather than reinvent the wheel. The real adventure nowadays is to use existing pieces to create something innovating and attractive. The real engineering is the ability to combine available libraries and frameworks into something that works flawlessly in every conditions.
In one of my previous posts I showed you how easy it can be to write and read Android code thanks to AndroidAnnotations (AA). I pointed out that writing less (boilerplate) code means actually spending more time on ideas and focusing on your creativity. Having said that, AA is not an all-encompassing tool. Especially when it comes to the networking — the core feature of most successful apps these days — Android’s own libraries are not that helpful to say the least and AA’s annotations are not the strongest horses in the race. If you want to communicate with the back-end server or just reliably fetch online images, not to mention caching them, you will have to pick one of the third-party libraries, like Volley, Spring for Android or RoboSpice.
RoboSpice — networking on steroids
As I like things that both work out-of-the-box and are flexible to customize to my own particular needs, for the time being RoboSpice is my winner. It covers reliable background network communication and caching with just minimal configuration. You may say „don’t you know about AA’s @Background
annotation?”. Well, one thing, as convenient as it is, behind the scenes it still resorts to inherently flawed AsyncTask
s dating back to the first days of Android. You can also implement your own caching engine using Jackson and files, like I did not that long ago, but — again — people out there have done that thousands of times, so why reinvent the wheel? One strength of RoboSpice is its modularity and extensibility: if you like caching in the DB, there’s ORM Lite module; if you prefer structured files, there’s Jackson and XML; if there are just simple strings to memorize, you can go for the good old plain text files. Everything just works with as little as maybe two dozen lines of code.
Background processing is implemented using a dedicated Android service that seamlessly binds to a started activity and reliably unlinks from it when it gets destroyed, continuing to work behind the scenes, caching and serving the results as soon as the activity is bound back again. No memory leaks, no need to write tedious code handling things as common as device orientation changes.
A marriage of two giants
So here’s my dilemma: I like caching and background processing features of RoboSpice, but I’m also pretty addicted to my heroin — AndroidAnnotations. When your REST calls look as neat and natural as this:
@Get("/{name}") FacebookPage getPage(String name);
you don’t want to go all the way back to this:
String baseUrl = "https://graph.facebook.com"; String url = String.format(baseUrl + "/%s", name); return getRestTemplate().getForObject(url, FacebookPage.class);
REST is about remote methods, so let REST calls finally look like methods with clean arguments and return types!
So I combined my two loveable, helpful friends. RoboSpice implementation is based on two definitions: a request and a service. The request contains the „meat”, in this case a network call:
@EBean public class FacebookPageRequest extends SpiceRequest<FacebookPage> { @RestService FacebookPageRestClient restClient; private CharSequence pageName = ""; public FacebookPageRequest() { super(FacebookPage.class); } public void setPageName(CharSequence pageName) { this.pageName = pageName; } @Override public FacebookPage loadDataFromNetwork() throws Exception { return restClient.getPage(pageName); } }
As you may have noticed, I defined it as an AA bean so that inside it I could refer to my REST methods using @RestService
.
The service class defines cache „persister(s)”, I used Jackson persister from the robospice-spring-android
module:
public class MySpiceService extends SpiceService { @Override public CacheManager createCacheManager(Application application) throws CacheCreationException { CacheManager manager = new CacheManager(); Jackson2ObjectPersister<FacebookPage> persister = new Jackson2ObjectPersister<FacebookPage>(getApplication(), FacebookPage.class); manager.addPersister(persister); return manager; } }
Then, in my activity, I brought all the pieces together:
@EActivity(R.layout.activity_main) @WindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS) public class MainActivity extends Activity implements RequestListener<FacebookPage> { @Bean FacebookPageRequest facebookPageRequest; private SpiceManager spiceManager = new SpiceManager(MySpiceService.class); // ... @Override public void onStart() { spiceManager.start(this); super.onStart(); } @Override public void onStop() { spiceManager.shouldStop(); super.onStop(); } @Click void getPageDetails() { CharSequence pageName = pageNameInput.getText(); facebookPageRequest.setPageName(pageName); spiceManager.execute(facebookPageRequest, pageName, DurationInMillis.ALWAYS_RETURNED, MainActivity.this); } @Override public void onRequestSuccess(FacebookPage facebookPage) { // ... } @Override public void onRequestFailure(SpiceException spiceException) { // ... } }
In the above code I skipped everything irrelevant to RoboSpice for the sake of brevity. As you can see, the RoboSpice-related code combines nicely with the annotated activity, e.g. being invoked on a @Click
.
The result
To illustrate my little success and help other developers get the big picture, I’ve created a sample app that displays the details of a given Facebook page from the FB’s Graph API:
You can find the app code on GitHub:
https://github.com/ddekanski/SpiceAnnotations
Conclusion
There’s still a lot that can be done to further simplify the use of RoboSpice with AndroidAnnotations, like creating a generic service class and — most preferably — implementing a @SpiceService
annotation that will eliminate the need to explicitly override onStart()
and onStop()
and will make things as neat as with @Background
. But the aim of this article and the accompanying code was to show that the marriage of two useful frameworks is possible with little effort. There’s still one thing missing from RoboSpice: out-of-the-box image loading. But with all the guts in hand, it’s an easy feature to incorporate and I hope the RoboSpice team will fill that gap.
All in all, my conclusion is: go for it and make use of unique features both frameworks provide. In one of my next posts I will take a closer look at Google’s Volley, another promising networking/caching library, so stay tuned.
This is a nice idea, but each kind of request needs each class, so there are still repeating boilerplate code if you have more than one kind of request. Do you have an idea to simplify it?
i cant use the @Ebean in my robospice request because of the constructor made by reobo spice request.. how can i fix?