androidrobospice

Robospice - addListenerIfPending - how do I know if request WAS found?


I am trying to implement a very simple case using robospice: a login screen. When login button is clicked, loading animation is shown and request is made using SpiceManager.execute(..) (without caching, of course. Since it's a login request, I need to do actual call to the server every time).

So, to handle screen rotations, etc., in Activity.onStart() I should use SpiceManager.addListenerIfPending(..), and if request is actually pending, I should show loading animation without doing any real request.

The problem is: PendingRequestListener does not have onRequestExists() method. It only has onRequestNotFound().

One possible (but unsatisfactory) solution, is to draw loading screen always, then call addListenerIfPending(..), and then remove loading animation in onRequestNotFound(). This creates "flickering" loading screen if there was no real request, which looks really bad. What is the proper way of implementing desired behavior?


Solution

  • Ok, in case google leads anyone here. Proper solution: in reality, this functionality is already in the library. There is a method which gets called when pending request WAS found, it just does... nothing.

    You need to:

    1. Create your own interface extending PendingRequestListener:

      public interface MyPendingRequestListener<T> extends PendingRequestListener<T> {
          void onRequestAggregated();
      }
      

      Note: you will need to use request listeneres implementing this interface when doing requests through Robospice.

    2. Create your own class implementing RequestListenerNotifier. I did this by copy-pasting DefaultRequestListenerNotifier (I was not able to extend it because method post(..) is private) because it contains porper notification implementation for other cases. For example, MyRequestListenerNotifier.

    3. Override method notifyListenersOfRequestAggregated:

      @Override
      public <T> void notifyListenersOfRequestAggregated(final CachedSpiceRequest<T> request, Set<RequestListener<?>> listeners) {
          post(new AggregatedRunnable(listeners), request.getRequestCacheKey());
      }
      
      private static class AggregatedRunnable implements Runnable {
          private final Set<RequestListener<?>> listeners;
      
          public AggregatedRunnable(final Set<RequestListener<?>> listeners) {
              this.listeners = listeners;
          }
      
          @Override
          public void run() {
      
              if (listeners == null) {
                  return;
              }
      
              Ln.v("Notifying " + listeners.size() + " listeners of request aggregated");
              synchronized (listeners) {
                  for (final RequestListener<?> listener : listeners) {
                      if (listener != null && listener instanceof MyPendingRequestListener) {
                          Ln.v("Notifying %s", listener.getClass().getSimpleName());
                          ((MyPendingRequestListener<?>) listener).onRequestAggregated();
                      }
                  }
              }
          }
      }
      
    4. Extend SpiceService and override the following method (you will need to use this customized service instead of standard robospice service):

      protected RequestListenerNotifier createRequestRequestListenerNotifier() {
          return new MyRequestListenerNotifier();
      }
      

    That's it. Now, when you use addListenerIfPending, onRequestAggregated() will be called when pending request IS found.

    IMPORTANT NOTE: This will only work when you use Cache key when doing request. For example, you can use empty string (but NOT null) as cache key.

    Example:

    //doing request for the first time
    spiceManager.execute(request, "", DurationInMillis.ALWAYS_EXPIRED, requestListener);
    //...     
    //checking if request is pending e.g. when activity is restarted
    spiceManager.addListenerIfPending(responseClass, "", requestListener);