Skip to content
This repository has been archived by the owner on Jan 14, 2018. It is now read-only.

Advanced RoboSpice Usages and FAQ

maciejpigulski edited this page Oct 28, 2014 · 10 revisions

This page is dedicated to explain advanced RoboSpice usages and answer frequently asked questions

Which Android SDK is RoboSpice compatible with ?

Since 1.4.13, RS is officially compatible from SDK 10+. We drop support for SDK 8 & 9. Though a "best effort" help will be provided to/by the community. The main cause is that Android emulator < 10 is not available anymore, thus we lost CI testing capacity and can't guarantee test passing anymore.

Before 1.4.13, RS is compatible with your granpa's phone : SDK 8+.

Is request processing multi-threaded ?

Yes, override SpiceService.getThreadCount() to change the number of threads used to process requests. Defaults to 1.

Is request processing using priority ?

This question may have 2 meanings :

  1. if you are talking about the Thread priority of threads used to process requests, you can override SpiceService.getThreadPriority() to change the priority of threads used to process requests. Defaults to Thread.MIN_PRIORITY.
  2. if you are talking about requests themselves, you can assign each request a priority inside RoboSpice by invoking spiceRequest.setPriority(). RS will do its best to execute first all high priority requests.

How can I setup a retry policy for failed requests ?

Use spiceRequest.setRetryPolicy(). By default, requests have a DefaultRetryPolicy. It will be activated when a network request fails.

How to cancel a request ?

You can cancel a pending request by either

  1. using the request object itself and cancelling it by invoking cancel()
  2. cancelling a request using its cache key and result type via the spiceManager.cancel()method. This is preferred as the cache key can be saved in the onSaveInstanceState bundle.

The first mechanism is hard to put it place on Android as you can loose a request object very easily (during a rotation for instance) but can still be considered in some simple cases (where rotation is blocked for instance).

How to add a listener to a pending requests ?

The SpiceManager will let you add a listener to a request if such a request exists by using :

  1. spiceManager.addListenerToPendingRequest

This will not execute any request, just add a listener to a potentially pending request. If no such request exists, it won't do anything, but if you use PendingRequestListener, then you will be notified of this "miss".

How to get request's results from cache without triggering any network processing ?

Use spiceManager.getDataFromCache() using the result type and the cache key as a compound key to identify request's result in the cache.

How can I sanitize CacheKeys so that I can use them to safely create cache files ?

InFileObjectPersister.setKeySanitizer() can be used to provide a bijective key sanitation. We provide a default implementation : DefaultKeySanitizer class can be used out of the box.

How can I access HTTP headers using RoboSpice ?

The core of RoboSpice is dedicated to networking but no to HTTP. It is protocol-agnostic and that provides the ability to use RoboSpice for HTTP/SPDY/FTP/etc. networking.

If you decide to use a more specific technology in conjunction with RoboSpice for handling an HTTP scenario, such as Spring Android, Google Http Java Client, etc. they will provide you, or not, with the headers of the response.

For instance [http://static.springsource.org/spring-android/docs/1.0.x/reference/html/rest-template.html](Spring Android RESTTemplate) does have "entity*" versions of its methods that can give you back the headers. But again, this is not the responsibility of RoboSpice.

Can we get HTTP headers to determine cache duration for a given request's result ?

When you execute a request using the SpiceManager, you can provide a duration of expiry. This duration indicates whether or not to use any data in the cache, if there are some. It doesn't indicate any expiry duration of the data that the current request will fetch from the network.

Report to question above to get the HTTP headers and use the returned value for data expiration to give an expiry duration to your next request.

Can I use RoboSpice for a non-network related task like a long-running computation ?

Yes, you can, and that should be the best option around. RoboSpice has been designed for networking requests but we acknowledge that it addresses a more general problem : syncing long running background tasks and activities.

To perform such a task using RoboSpice there are 2 steps to follow :

  • build you request as usual but don't use any networking in the method loadDataFromNetwork
  • provide your SpiceService with a custom NetworkStateChecker that will always declare the network to be available. This way, RoboSpice will always execute your requests (usually, requests are simply discarded if network is not on).

How can I turn off RoboSpice debug logging ?

RoboSpice ships with debug logging enabled to help you during development phase. If you want to turn it off just put this line of code in your SpiceManager subclass's constructor:

Ln.getConfig().setLoggingLevel(Log.ERROR);

I get a ConcurrentModificationException in RequestProcessor !

This is not an issue and has been investigated a lot via issue #91.

If you get this exception, it is highly probable that you are either :

  • cancelling a request
  • stopping the SpiceManager

from within a request listener's callback method. And you simply can't do this. That's not an RS design problem but more a limitation of java language itself : while iterating through the synchronized set of listeners associated to a request, this set of listeners can't be modified.

A workaround could have been to use an CopyOnWriteArray but it comes with performance penalty. Moreover, there is no reason to stop the SpiceManager after a request is complete: RS does it automatically for you, it will shutdown once there are no requests to execute and restart if a new request is executed.

In case I use an Activity managed SpiceManager, how does RoboSpice handle Fragment lifecycle?

The simple answer is - it doesn't. RoboSpice is working along with Android lifecycle because of using guidelines provided by Google, that means SpiceManager is started in Activity.onStart() and stopped it in Activity.onStop(). SpiceManager drops requests only when SpiceManager.shouldStop() is called, and it is called in Activitiy.onStop() and this call is executed before Fragment.onDetach() according to the Android lifecycle docs located here: http://developer.android.com/guide/components/fragments.html#Lifecycle. This means RoboSpice in the solution when Activity controls the SpiceManager is relying on Activity lifecycle and Activity lifecycle determines Fragment lifecycle in most of the cases as Fragment is attached to the hosting Activity. Fragment doesn't live on it's own. But! Fragment lifecycle can be different at times when using FragmentTransaction. This means that RoboSpice may try to deliver a response to a Fragment that was detached while an Activity was still operating (i.e. it is not in Paused/Stopped state). This is possible when using transactions and FragmentTransaction.add/replace/remove(...) for example. To avoid crashes caused by getActivity() being null you can check Fragment.isAdded() method before processing the response and updating Fragment UI. This solution however drops the response if Fragment got detached before receiving the response (after 'Fragment.onDetach()' finishes - 'Fragment.isAdded()returnsfalse`) and you need to make this request again if required.

Other solution is to use second approach which is getting own SpiceManager in Fragment.onAttach(...) and releasing the SpiceManager in Fragment.onDetach() so you don't have to call for Fragment.isAdded() and you can attach to the pending request again in Fragment.onAttach() with SpiceManager.addListenerIfPending(...). It will just create another client for the SpiceService and will fall in nicely with Fragment lifecycle.

Clone this wiki locally