Help with request Cancelation and Recover Pending Request

93 views
Skip to first unread message

Joao Ferreira

unread,
Jan 19, 2015, 3:59:53 AM1/19/15
to robo...@googlegroups.com

Hi guys, I'm having some troubles doing some things and I need your help.

I have an Activity that have an instance of the SpiceManager() to be used in view pager fragments.

1 - The first problem is when I try to cancel a request, I call SpiceManager.cancel(RequestObject.class, Cache_KEY) and after that i call the getPendingRequestCount() and it returns 1 although I had cancelled the request before.

2 - The second problem is that I want that when the user tries to refresh the data, if there is other request pending, it will not call the service again and waits for the pending request response.
I added in the refreshFunction() a listener

addListenerIfPending(
ResponseObject.class, Cache_KEY
new PendingRequestListener());

in the PendingRequestListener I have a function:

public void onRequestNotFound() that calls the execute() function in case not having any pending requests.

The problem is that it enters always on that function even if I have made a request previously.

Thanks in advance for your help and congrats for the fantastic work you develop here.

Nikola Keskinov

unread,
Jan 21, 2015, 4:47:37 AM1/21/15
to robo...@googlegroups.com
Hi,

1. It is probably the case that the request has started network loading. RoboSpice is not actually cancelling the network request (if it had started), but it completely detaches itself from it. Meaning that if the network load has started, it will still proceed normally, but you will see no effect of it. Therefore the getPendingRequestCount() does not return 0 yet. Although I can agree that this behavior needs a revisiting.
2. This should not happen in general. Could you provide some code, including creation of the original request, starting/stopping the SpiceManager and any other details you deem relevant?

Cheers,
Nikola

Joao Ferreira

unread,
Jan 21, 2015, 5:21:52 AM1/21/15
to robo...@googlegroups.com
Hi Nikola, thanks for your response.

1 - So the best way to control if we have a pending request is to track in our side each call and response right?

2 - I will try to explain how I implemented this:

In my activity Base class I have the following methods:
        @Override
protected void onStart() {
spiceManager.start(this);
super.onStart();
}

@Override
protected void onStop() {
spiceManager.shouldStop();
super.onStop();
}

public SpiceManager getSpiceManager() {
return spiceManager;
}


The original request is made in the callRefresh function (the listener is the activity where the fragment is attached), I use DurationInMillis.ALWAYS_EXPIRED because i don't want the responses to be cached:

       private void callRefresh() {
           GetDevicesRequest getDevicesRequest = new GetDevicesRequest(
                filters.getFilters());
            listener.getSpiceManager().execute(getDevicesRequest,
                BaseCommon.GET_DEVICES_REQUEST,
                DurationInMillis.ALWAYS_EXPIRED,
                new GetDevicesRequestListener());
    }

When the user presses the refresh button in the fragment I call the refreshFragment() function where I add the following listener to check if there is any pending request, if not (onRequestNotFound:) I will make a new request.

   public void refreshFragment() {
        ...
        listener.getSpiceManager().addListenerIfPending(
                GetDevicesResponseObject.class, BaseCommon.GET_DEVICES_REQUEST,
                new PendingGetDevicesRequestListener());
        ...
    }

Then I have the PendingRequestListener

public final class PendingGetDevicesRequestListener implements
            PendingRequestListener<GetDevicesResponseObject> {

        @Override
        public void onRequestFailure(SpiceException spiceException) {
            ...
        }

        @Override
        public void onRequestSuccess(GetDevicesResponseObject result) {
            ....
        }

        @Override
        public void onRequestNotFound() {
             callRefresh();
        }
    }

The problem is that it always enter in the onRequestNotFound even if I have any request with this cachekey running.

I'm not sure this is the correct way to implement this.

Thanks again for your help.

Nikola Keskinov

unread,
Jan 21, 2015, 5:42:26 AM1/21/15
to robo...@googlegroups.com
Hi Joao,

1. Why would you need that control? Using RoboSpice ensures that you don't need to cancel manually any pending or running request. If the user navigates away from an Activity or Fragment, it usually means that he is not interested in that data and stopping the SpiceManager will handle that cancellation gracefully. 
But to answer your question directly, yes, if you want to have a count of pending requests excluding your manually cancelled ones (which may still be "pending" in RoboSpice's terms), you need to implement that control yourself.

2. Everything seems in order. Are you sure the request has not finished yet when you try to join PendingRequestListener? If you want to test RoboSpice's addListenerIfPending behavior, easiest would be to call refreshFragment() immediately after callRefresh(). With a fairly performant server, you will hardly be able to reproduce that manually by clicking a refresh button. Although the code for refreshFragment() is handy when that performant server is under heavy load :)

Nikola

--
Vous recevez ce message, car vous êtes abonné à un sujet dans le groupe Google Groupes "RoboSpice".
Pour vous désabonner de ce sujet, visitez le site https://groups.google.com/d/topic/robospice/VDkPX5XcQqE/unsubscribe.
Pour vous désabonner de ce groupe et de tous ses sujets, envoyez un e-mail à l'adresse robospice+...@googlegroups.com.
Pour obtenir davantage d'options, consultez la page https://groups.google.com/d/optout.

Joao Ferreira

unread,
Jan 21, 2015, 5:59:43 AM1/21/15
to robo...@googlegroups.com
Hi Nikola,

1. I'm using a viewpager to show the fragments and the SpiceManager is stopped in the Activity. I want to control when to show the loading indicator in some fragment, for example:
If I'm at FRAG_1 and I call the refresh data of that fragment the loading indicator should be shown, when the user swipe to FRAG_2 the loading indicator should be hidden if no request is made in the FRAG_2, but if the user returns to the FRAG_1 and there's a pending request I want to show the loading indicator, recover that request and not make a new one.

2. I will try what you suggested.

Thanks

Nikola Keskinov

unread,
Jan 21, 2015, 6:28:28 AM1/21/15
to robo...@googlegroups.com
For 1., when using ViewPager, you should play a bit with the offscreenPageLimit property. If you specifically have 2 fragments at all times, just going with the default offscreen page limit (1) would make your FRAG_1 active at all times and you wouldn't need any additional logic for handling the loading indicator state.

Handling activity recreation, however, would require tracking the request state and you should be well off by using addListenerIfPending. See http://stackoverflow.com/a/19314505/754439 for more technical details.

Joao Ferreira

unread,
Jan 21, 2015, 6:41:50 AM1/21/15
to robo...@googlegroups.com
I know that when using the ViewPager I have always at least 2 fragments at all the time. The problem is that when I change between them, I only want to show the loading indicator if there's a running request to get data to the visible fragment:

- I'm in FRAG_1 and I have a request running
- I swipe to FRAG_2 and I have no need to do any request on FRAG_2 so the loading indicator disappears
- I return to FRAG_1 and the request is still running, I want to show the loading indicator again

This is what I want to archive. That's why I need to control if there's any request pending in each fragment when it's the visible fragment.

Nikola Keskinov

unread,
Jan 21, 2015, 7:09:47 AM1/21/15
to robo...@googlegroups.com
I see. You probably have a loading indicator inside the Action Bar. 

Of course, using addListenerIfPending() there will help you achieve it as well. You should probably show/start it onStart() and hide/stop it on all PendingRequestListener's callbacks (onRequestSuccess, onRequestFailed, onRequestNotFound). If your FRAG_1 is active at all times, implementing a ViewPager.OnPageChangeListener and controlling when the user has changed back to FRAG_1 may also be a point where you would want to addListenerIfPending(), I think.

Joao Ferreira

unread,
Jan 21, 2015, 7:55:56 AM1/21/15
to robo...@googlegroups.com
That's it, I have the loading indicator inside the Action Bar.

I think I will need to set the PendingRequestListener in the setUserVisibleHint() instead of the onStart(), because the onStart() is only called when the fragment is created and not every time the fragments is visible.

In relation to the 2nd point I have test to call the refreshFragment() in the callRefresh() and it worked. The only issue I had was that the onSuccess() function was called in both listeners the one of the original request and the PendingRequestListener, but this should be the expected behaviour right?

Thanks again

Nikola Keskinov

unread,
Jan 21, 2015, 8:01:12 AM1/21/15
to robo...@googlegroups.com
I wouldn't recommend setUserVisibleHint(), as it may be called before onCreateView(). But that is unrelated to RoboSpice.

If the first request is neither finished nor cancelled, it is still running, so yes, executing onSuccess() twice is perfectly normal.

Nikola
Reply all
Reply to author
Forward
0 new messages