I have an Activity that starts an AsyncTask. The activity is allowed to show in Portrait or Landscape orientation. When the orientation is
If your app targets API level 13 or higher, you should set this config in the manifest.xml
<activity
android:configChanges="orientation|screenSize"
...
/>
In general, you don't want to define onConfigurationChanged() because it's so hard to get everything right. The best approach is to let the app be killed and recreated when the orientation changes.
To make the transition easier, you can implement onRetainNonConfigurationInstance(). This method will be called by the system when it knows that your app will be restarted almost immediately. In onRetainNonConfigurationInstance(), you pass any arbitrary object back to the system ('this' is a reasonable choice). Then, in your onCreate()
method, you call getLastNonConfigurationInstance() to get the previously-saved object. This allows you to very quickly and easily restore your state from the previous invocation. I believe even running threads and open sockets can be passed across this way.
See Save cache when rotate device for more info.
Take a look here for a better understanding of the Android lifecycle: http://developer.android.com/reference/android/app/Activity.html#ActivityLifecycle
You can use onConfigurationChanged() to detect orientation changes in your Activity. You can use the onDestroy() method to determine when your Activity is about to be killed.
I found a somewhat satisfying solution, which I want to share.
The method onRetainNonConfigurationInstance() is called only when the Activity is being recreated. More specifically: Called by the system, as part of destroying an activity due to a configuration change, when it is known that a new instance will immediately be created for the new configuration.
I override this method and store a flag (stating whether it has been called or not). Then in onDestroy (called shortly after) I check this flag and if it's false I cancel the background task, because the Activity is being destroyed for good. If it's true this means that onRetainNonConfigurationInstance() has been called, which means that the Activity is being recreated, so I leave the task running.
I would have liked a better solution, but could not find such. The problems with this solution are two: the method is deprecated; there is no guarantee that the method will be called (according to the documentation). In practice the solution works for me, so I'll use it...
The best way I found after some research was to create an application class and rely on onTrimMemory() method. A problem with this approach - onTrimMemory() does not get called if screen times out or screen gets locked by pressing power button so I had to implement that logic separately.
/**
* When your app's process resides in the background LRU list:
* TRIM_MEMORY_BACKGROUND
* TRIM_MEMORY_MODERATE
* TRIM_MEMORY_COMPLETE
*
* When your app's visibility changes:
* TRIM_MEMORY_UI_HIDDEN
*/
@Override
public void onTrimMemory(final int level) {
super.onTrimMemory(level);
if (level == ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN
|| level == ComponentCallbacks2.TRIM_MEMORY_BACKGROUND
|| level == ComponentCallbacks2.TRIM_MEMORY_COMPLETE
|| level == ComponentCallbacks2.TRIM_MEMORY_MODERATE) {
// App went in background
}
}
Following code is to detect screen lock. I implemented this code in one of the ActivityLifecycleCallbacks method - onActivityStopped()
final PowerManager powerManager = (PowerManager) getAppContext().getSystemService(Context.POWER_SERVICE);
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.KITKAT) {
if (!powerManager.isScreenOn()) {
// Screen locked
}
} else {
if (!powerManager.isInteractive()) {
// Screen locked
}
}
you can use isFinishing()
method , to check if the activity is going to be killed or onDestroy()
method just called due to change in orientation
@Override
protected void onDestroy() {
super.onDestroy();
if(isFinishing()){
Log.i("DEBUG", "App will Terminate ");
}else{
Log.i("DEBUG", "Orientation changed");
}
}