android:alwaysRetainTaskState = false not being respected, task state always retained - android

I would like my app to exhibit the default behaviour described for android:alwaysRetainTaskState in the Android documentation:
Normally, the system clears a task (removes all activities from the
stack above the root activity) in certain situations when the user
re-selects that task from the home screen. Typically, this is done if
the user hasn't visited the task for a certain amount of time, such as
30 minutes.
This isn't what I'm seeing. Even after >1 day, re-starting my app using the launcher icon returns the user to the place where they left it.
For example, after a fresh install my app displays a home screen activity H when launched. The user then navigates to detail activities: H -> J. On relaunching after a long time, I would like the user to see H, but instead they see J.
These are the flags set on my activity in the AndroidManifest.xml:
<activity
android:name=".AppHomeScreen"
android:label="#string/app_name"
android:alwaysRetainTaskState="false"
android:launchMode="singleTop"
android:windowSoftInputMode="stateUnchanged">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
I am running Android KitKat 4.4.2.
Is there any reason why I might not be seeing the expected behaviour here? I know that I could set android:clearTaskOnLaunch or android:finishOnTaskLaunch to clear the task every time the user leaves the app, but this is too aggressive, I'd like the described behaviour where the state is only forgotten after a long period of inactivity.
(The Android documentation doesn't seem to guarantee the behaviour, only that the task is cleared in "certain situations" and "after a certain amount of time, such 30 minutes". Maybe the default behaviour was changed and the Android docs are out of date?)

This behaviour is manufacturer/vendor-specific. On different devices you will see different behaviour. There are devices that aggressively clear out tasks and others that retain task state for much longer periods of time.

Related

Activity and Flags Intent [duplicate]

I have a Notification which starts an Activity. After a long press on home button and selecting my app, I want to start my main Activity again, and not this Activity started by the Notification. I tried with FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS, but this removed my whole application from the recents, and that's not what I want to achieve. How can I have my app in the recents, but have the main Activity started?
Regards
Okay, I found the solution to my problem. I started an Activity from a Notification with FLAG_ACTIVITY_NEW_TASK. But it seems to me that this Activity only gets started in an own task if affinity is different from the default affinity. So I had to add a different affinity in the manifest.
And it seems that FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS does not (as documented) exlucde the Activity from the recents, rather it excludes the whole task (not the whole application) in which the Activity gets started from the recents. And as I hadn't set a different affinity the Activity which I wanted to exclude was started in the same task (although I had set FLAG_ACTIVITY_NEW_TASK) and so my whole application (as it was running in only one task) was excluded from the recents.
Now I've set a different affinity for the Activity that gets started from the Notification and I start it with FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS. When I leave this Activity and long-press the HOME button I can choose my app and the default task is started or brought to the front.
If it's wrong what I mentioned above, feel free to clear it up ...
It's not clear to me what you want.
"How can I have my app in the recents, but have the main Activity
started?"
If you want to always start one activity using the long home-press, you can define your activity as singleTask in the manifest.
That way, when you select the shortcut in the long press HOME, it will always show the MAIN, singleTask activity. I say this because I used this behavior before once. ;-)
I believe that by using this you can still start an activity from the notification normally, using, say, Intents.
In the activity tag:
android:launchMode="singleTask"
>
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>

Clear an Android application of all Activity's (above/launched by, and including the main launched one)

I have a root activity which of necessity is defined singleTop
<activity
android:name=".MyMainActivity"
android:label="#string/app_name"
android:launchMode="singleTop" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
I have a notification that sends a broadcast to my foreground service telling it, and the Activity if it is bound to MyMainActivity, to stop. A widget can be touched to restore MyMainActivity to its previous state, hence the need for singleTop.
The problem is that since introducing the stop service button on the notification (de rigeur, as I understand) it is killing just MyMainActivity meaning that any Activitys started from it will persist, as I intended it, but fail to return meaningful results since their originating, MyMainActivity has already been destroyed.
I've stuck with a simple finish() to handle the termination broadcast from MyMainActivity, after disconnecting from the service. All the other finish variants had undesired side effects.
System.exit(0); does actually work great. Except that the expected life cycle course towards destruction gets ignored and restarting is a bit of a bother.
finishAffinity is another candidate, except it is described:
Finish this activity as well as all activities immediately below it
when I need to finish the activities above it, according to the android dev terminology.
How to do this?
The answer is very simple, and has been since API 1. Call finishActivity(int intent_id) with the same intent_id that was supplied to startActivityForResult(Intent, int).

Lollipop: making my activity stay in the task that launched the share intent

“My First App” has an activity that handles a “share” intent. Its activity in AndroidManifest.xml looks like this:
<activity
android:name="com.example.foo.myfirstapp.MainActivity"
android:label="#string/app_name">
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="image/jpeg"/>
</intent-filter>
</activity>
In KitKat, sharing an image from the album to “My First App” causes MainActivity to be part of the album’s task. This is the desired behavior.
In Lollipop, sharing an image from the album to “My First App” causes a new instance of “My First App” to be launched. If I look at the overview screen, the album task is there...and then there's a separate entry for "My First App". If I share another image, I wind up with two instances of "My First App"...etc.
Question: How do I make Lollipop process the share intent in the same way as KitKat?
Here's what I've done:
I notice that the intents sent from the Album have different flags set depending on the OS. (I got these using getIntent() and looking at mFlags.)
Kitkat: 0x80001 (524289): FLAG_GRANT_READ_URI_PERMISSION, FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
Lollipop: 0x18080001 (403177473): FLAG_GRANT_READ_URI_PERMISSION, FLAG_ACTIVITY_MULTIPLE_TASK, FLAG_ACTIVITY_NEW_DOCUMENT, FLAG_ACTIVITY_NEW_TASK
From reading http://developer.android.com/reference/android/content/Intent.html, it seems that these last three flags are causing the problem. Specifically
When paired with FLAG_ACTIVITY_MULTIPLE_TASK both of these behaviors (FLAG_ACTIVITY_NEW_DOCUMENT or FLAG_ACTIVITY_NEW_TASK) are modified to skip the search for a matching task and unconditionally start a new task.
I’ve been attempting to “override” these flags by specifying android:launchMode and android:documentLaunchMode in the activity in AndroidManifest.xml without success.
From http://developer.android.com/reference/android/R.attr.html#documentLaunchMode, using documentLaunchMode “never” seems promising, since
This activity will not be launched into a new document even if the Intent contains Intent.FLAG_ACTIVITY_NEW_DOCUMENT. This gives the activity writer ultimate control over how their activity is used.
but this didn't work.
I also considered android:taskAffinity, but there doesn’t seem to be a way to say “please prefer whatever task launched you”.
Afraid you can't do anything about this. It isn't under your control. This is a change in the way the "Album" app is launching its "share" Intent. If it doesn't want your Activity in its task, you can't force it in there.
If you have issues with having multiple instances of your "share" activity, you could declare your "share" activity as launchMode="singleTask" or launchMode="singleInstance" (depending on your needs. This may, however, break other things.

Fail to resume the activity stack during 1st launching after installation

Our application has a splash activity (main activity for launcher) and many other activities. In most cases, when the user switches the application into background and resumes it from launcher, the old activity stack is resumed and top activity in that stack is shown as expected.
However, when the apk is just installed on the phone, or a new apk (with higher version) of the same application is installed, its behavior is strange. When the application is switched to background and resumed from launcher, the previous activity stack is not resumed and the splash activity is always shown. If we resume the application from recent applications list, the activity stack is resumed as expected. Only after killing the task from recent applications list, everything becomes normal again. The previous activity stack will always be resumed correctly until it is replaced by another apk installation again.
My Android version is 4.1.2 and I am using its default launcher.
Following is configuration of the splash activity.
<activity android:name=".welcome.activity.SplashActivity" android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Who has any idea about the strange behavior? Thanks in advance!
Finally I have found this is an issue of Android system. It has already been discussed in Activity history stack wrong upon first install on device?.
I have adopted a workaround stated in https://code.google.com/p/android/issues/detail?id=2373#c40 and it works well, i.e. adding the following code in SplashActivity.onCreate():
if (!isTaskRoot()) {
Intent intent = getIntent();
String action = intent.getAction();
if (intent.hasCategory(Intent.CATEGORY_LAUNCHER) && action != null && action.equals(Intent.ACTION_MAIN)) {
finish();
return;
}
}
I'm not really able to tell what's going on without knowing more about your app. I would look into:
The launchMode manifest element: android:launchMode
Check your activities are not being destroyed and recreated by the system: Recreating an Activity
If you are doing anything with fragments and if these are maintaining state correctly
Sorry, bit of a guess!
Since you only want to show your Splash Activity once, you can use finish() after you launched the Main Activity, that should solve your problem.

Why won't my Activity start?

I have an industrial app which is remotely controlled from a PC. The app has 2 slightly different versions - one for a Honeycomb tablet and the other for a Gingerbread phone. The differences are to take advantage of unique features in the hardware (e.g., the phone has a better camera, the tablet can display bigger graphics) but the Activity-starting code is the same.
A thread in the app receives commands from the PC and displays different screens (i.e., starts different Activities). It works fine on the phone but on the tablet one activity won't start, but throws no exceptions. Breakpoints and logging in that activity's onResume() are never hit, even though they are on the phone. Here's how I try to start the activity . . .
try {
Intent svc = new Intent(ctx, RemoteControlActivity.class);
ctx.startActivity(svc);
}
catch (Exception e) { // or ActivityNotFoundException e
Log.d("ShowButtons(normal)", "startActivity failed");
}
(ctx is a Context - in the debugger the Context is the same for both the working on non-working cases)
The activity which is failing to start on the tablet is defined like this in the manifest . . .
<activity
android:launchMode="singleTask"
android:label="#string/app_name"
android:windowNoTitle="false"
android:configChanges="orientation"
android:screenOrientation="landscape"
android:name="RemoteControlActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
This is driving me batty - thanks in advance for any help!
Try this
Intent svc = new Intent(ctx, RemoteControlActivity.class);
svc.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
ctx.startActivity(svc);
According to the docs
When using this flag, if a task is already running for the activity you are now starting, then a new activity will not be started; instead, the current task will simply be brought to the front of the screen with the state it was last in
I found a solution. I'm posting it this way so I can mark it as "answered" incase anyone else runs into this and is searching for a workaround. But I admit I don't understand why it works.
The breakthrough was discovering that it mattered what activity was currently on the screen when I was trying to start RemoteControlActivity. The failure was happening when I had an activity that displayed some graphics on the screen. I substituted a different activity that displayed some buttons and the problem went away.
Looking at the Manifest I noticed that the "good" activity was set to:
Android:launchMode="singleTask"
and the "bad" one was set to:
Android:launchMode="singleInstance"
When I changed the graphics activity to "singleTask" the problem went away.

Categories

Resources