My problem involves an activity hosting three support fragments. One is a normal programmatic fragment (let's call it a home fragment). One is a portrait fragment added on top of the home fragment when the device is orientated, and one is 'headless', to continue an async task regardless of configuration changes. Very simple, I was working off this nice example.
public class HeadlessCustomerDetailFetchFragment extends Fragment{
private RequestCustomerDetails mRequest;
private AsyncFetchCustomerDetails mAsyncFetchCustomerDetails;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setRetainInstance(true);
mRequest = (RequestCustomerDetails)getActivity();
}
public void startFetching(String scannedBarcode) {
if(mAsyncFetchCustomerDetails != null && mAsyncFetchCustomerDetails.getStatus() == AsyncTask.Status.RUNNING) return;
if(mAsyncFetchCustomerDetails == null || mAsyncFetchCustomerDetails.getStatus() == AsyncTask.Status.FINISHED)
mAsyncFetchCustomerDetails = new AsyncFetchCustomerDetails(getActivity(), mRequest, mPartner, scannedBarcode);
}
public void stopFetching() {
if(mAsyncFetchCustomerDetails != null && mAsyncFetchCustomerDetails.getStatus() != AsyncTask.Status.RUNNING) return;
mAsyncFetchCustomerDetails.cancel(true);
}
}
In my activity's onCreate() I create and add the headless fragment if necessary.
mHeadlessCustomerDetailFetchFragment = (HeadlessCustomerDetailFetchFragment)getSupportFragmentManager()
.findFragmentByTag(HeadlessCustomerDetailFetchFragment.class.getSimpleName());
if(mHeadlessCustomerDetailFetchFragment == null) {
mHeadlessCustomerDetailFetchFragment = HeadlessCustomerDetailFetchFragment.instantiate(this, HeadlessCustomerDetailFetchFragment.class.getName());
getSupportFragmentManager().beginTransaction()
.add(mHeadlessCustomerDetailFetchFragment, mHeadlessCustomerDetailFetchFragment.getClass().getSimpleName())
.commit();
getSupportFragmentManager().executePendingTransactions();
id = null;
}
I then launch an async task (via my startFetching() function) after a 6 second delay (for testing) kicked off in the onCreateView() of the portrait fragment that is added when the orientation changes to portrait. The orientation change is detected in the activity's onCreate():
if (savedInstanceState == null) {
// Do some initial stuff for the home fragment
}
else {
getSupportFragmentManager().popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
//Launch portrait fragment
FragmentLauncher.launchPortraitFragment(this);
}
When the task is finished, I return to the activity and attempt to update the UI of the active portrait fragment, but the fragment manager cannot find it, findFragmentByTag() returns null.
To be clear:
- The tag is correct
- The fragment is found if I do not orientate the device, and instead kick off the async task somewhere else, during the activity's onResume() for example.
- If I do not tell the headless fragment to retain itself - thereby losing the benefit of not recreating it, the portrait fragment is also correctly found.
- Debugging I can see all 3 fragments in the manager if the headless one is not set to retain itself. If it is, I can only see the headless fragment.
Maybe retaining a fragment aggressively kills other fragments that are not retained or something to that effect?
setRetained
changes the waypopBackStackImmediate(name, flags)
works? I might try removing or modifyinggetSupportFragmentManager().popBackStackImmediate(null, FragmentManager.POP_BACK_STACK_INCLUSIVE);
– Phenocryst