Reputation: 1658
I have a Fragment
that does some communication with the internet trough some helper Class
that requires an interface to handle asynchronous callbacks like this:
SomeInternetCommunicator.getResource(theResourceToGet, retrieverInterfaceInstance);
The interface looks like this:
public interface SomeInternetCommunicator {
void onResourceRetrieveSuccess(SomeResource resource);
void onResourceRetrieveFailed(CommunicatorException e);
}
The problem is that, sometimes the calls take too long, the user already navigated elsewhere and the Fragment
that did the call to getResource
is not part of the currently running Activity
anymore (not showing, not on backstack). This causes many problems because this orphan Fragment
is still attempting to react to the callbacks even if it is not part of the Activity
anymore. For example, getContext()
returns null.
Now my workaround on the Fragment
looks like this:
SomeInternetCommunicator flocktrackerTrackerRetrieverInterface = new SomeInternetCommunicator() {
@Override
public void onResourceRetrieveSuccess(SomeResource resource) {
if(isVisible()){
doRetrievalPostProcessing(resource);
}
}
@Override
void onResourceRetrieveFailed(CommunicatorException e) {
if(isVisible()){
doExceptionHandling();
}
}
};
Using the isVisible()
works because this ensures that the fragment is still on the foreground, part of the Activity
and ready to do the handling. This, however, doesn't help me to cover the case for when the Fragment
is not visible, but still part of the current Activity
, limiting my possibilities for loading the Fragment
before showing it. (Activity
is in the background, Fragment
is on the Backstack
, Fragment
loaded by a ViewPager
).
Is there a better way to ensure that the Fragment
is still on the current Activity
's scope before I do the postprocessing? Maybe checking isAdded()
?
This question seems to explain a broader but related situation, but it has no answers.
Thank you!
Upvotes: 2
Views: 390
Reputation: 39856
there're two usual approaches to this case:
SomeInternetCommunicator
. Something like:.
@Override public void onDestroyView(){
SomeInternetCommunicator.removeMe(this);
}
SomeInternetCommunicator
is a poorly coded library, you force option 1 to be possible by making a separate class to implement the interface..
public class SomeInternetCommunicatorInterceptor implements SomeInternetCommunicatorInterface {
private SomeInternetCommunicatorInterface listener;
public void setListener(SomeInternetCommunicatorInterface listener){
this.listener=listener;
}
@Override
public void onResourceRetrieveSuccess(SomeResource resource){
if(listener != null){
listener.onResourceRetrieveSuccess(resource);
}
}
@Override
public void onResourceRetrieveFailed(CommunicatorException e){
if(listener != null){
listener.onResourceRetrieveFailed(e);
}
}
}
then on your fragment you use this new class as:
private SomeInternetCommunicatorInterceptor interceptor;
public void onCreateView(....){
... your code
interceptor = new SomeInternetCommunicatorInterceptor();
}
onStart(){
interceptor.setListener(this);
}
onStop(){
interceptor.setListener(null);
}
public void onDestroyView(){
interceptor = null;
super.onDestroyView();
}
VERY IMPORTANT:
if you make SomeInternetCommunicatorInterceptor
an internal class of the fragment you HAVE TO make it as static class
Upvotes: 2