Maher4Ever
Maher4Ever

Reputation: 1280

Loader not being called when screen orientation change

I facing a bit of trouble when using AsyncTaskLoader and the screen orientation changes. Let me give you some context on how my app is structured: I have a very simple app which fetches results from a url and displays it. The app consists of one FragmentActivity and three Fragments. My three fragment are as follows:

The AsyncTaskLoader is used to load data from either a content provider (if it is cached) or from the network.

Everything works great until the screen oreintaion changes! I looked at the output of LoaderManager.enableDebugLogging(true) and it seems the source of the problem is that LoaderCallbacks.onLoadFinished doesn't get called in my activity.

Here is a piece of the code that launches the loader:

/* This function is defined in the "first" fragment in an interface and
 * implemented in the activity */ 
@Override
public void onFormSubmission(String word) {                     

    showLoadingFragment();

    if ( mWord == null || mWord.equals(word) ) {
        getSupportLoaderManager().initLoader(0, word, this);
    } else {
        getSupportLoaderManager().restartLoader(0, word, this);
    }

    // Store the word
    mWord = word;
}

The code that displays the result:

@Override
public void onLoadFinished(Loader<Bundle> loader, Bundle data) {
    // Validation and other stuff

      ResultFragment fragment = new ResultFragment();

      // Add the fragment to the 'result_fragment_container' FrameLayout
      getSupportFragmentManager()
            .beginTransaction()
            .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN)
            .setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out)
            // Replace loading fragment with the result
            .replace(R.id.result_fragment_container, fragment)
            .commitAllowingStateLoss(); 
}

Approaches I tried but failed:

I'm out of ideas, so any help would be appreciated.

Upvotes: 8

Views: 1478

Answers (2)

wired00
wired00

Reputation: 14438

Hi I can suggest 2 possible solutions:

1) From your question I'm not entirely sure what process your performing which is never calling OnLoadFinished() in the AsyncTask. I'll assume is a Async DB call or Web server call etc?

Regardless the onLoadFinished() probably doesn't get called because your Activity is Destroyed on rotation. you need to save the state you updated before rotation and onDestroy() is called

You can try keep a class variable status flag. This is set in your "update" Async task which flags whether your Async task is still running ie "updating" or not.

So:

  • bUpdating = true when your update async task starts. Ie within onPreExecute()
  • bUpdating = false when its finished. Ie within onPostExecute()

Then when onDestroy() is called (always called before the screen rotate) you could check bUpdating. IF TRUE then you could save all details on screen, which would have been saved in the Async task, to SharePreferences

Within onResume() check your specific SharePreferences variables and if they exist then kickoff the Async update again.

So in short this will:

  • save details to SharedPreferences BEFORE screen rotation - onDestroy() - if boolean says Async task running.
  • onResume() AFTER screen rotation check SharedPreferences and save details via Async.
  • Following this you should be guaranteed that your onLoadFinished() method is called.

There is probably a more reliable way also to check for Screen Rotation, i haven't done much with it.

2) Of course another alternative is to actually block screen rotation entirely on your particular Activity (because really, do you NEED rotation on that screen?).

I have an application which records video in background and uploads 10second segments. It was causing large headaches with screen rotation and my Async tasks, so I blocked rotation entirely as it was completely unnecessary. Here is code for the AndroidManifest.xml file to lock Screen orientation as Portrait:

     <activity 
        android:name="com.blah.YourActivity"
        android:label="Register"
        android:screenOrientation="portrait">
    </activity>

I hope that can help you out

Edit: Also, could be better more categorical ways to know that screen is rotating:

ie this sort of code:

public void onConfigurationChanged(Configuration newConfig) {
    super.onConfigurationChanged(newConfig);

    if (newConfig.orientation == Configuration.ORIENTATION_LANDSCAPE) {
        Log.e(TAG, "ORIENTATION_LANDSCAPE");
    } else if (newConfig.orientation == Configuration.ORIENTATION_PORTRAIT) {
        Log.e(TAG, "ORIENTATION_PORTRAIT");
    }
}

Example taken from this post

you could just put your SharePreferences save in there. but onResume() will still be used to grab your details back from.

Also a link to SharePreferences incase you've not used it before

Edit2!: One other thing. I just re-read your question, and you mention "Loader" for some reason i had it in my head this was saving data, not loading. Have you tried simply re-calling AsyncTaskLoader() when onResume() is called?? If your not saving then you can ignore everything i said about retaining your data to SharePreferences because you can just kickoff the load Async task again at onResume() (which runs after Rotation)

Upvotes: 1

Quanturium
Quanturium

Reputation: 5696

You should put getSupportLoaderManager().initLoader(0, null, this); in the onActivityCreated method. The initLoader will create or reconnect with a loader if it already exists

Upvotes: 1

Related Questions