i have an application that has "login" and "logoff" actions. after the user logs in, there could ne an arbitrary number of activities left on the stack at the point when they log off.
when the user logs off, i want all application state to be reset. i clear my disk caches and preferences, but there's still state left in running (paused) activities. in fact, when the user logs in again, i find that the old activities from the previous login session are still there with their old state (i understand why this is of course). how can i cause the entire app to reset / close / restart?
i've seen a few posts about using startActivityForResult(), onActivityResult() to bubble up a "logoff" result code causing each activity to close itself in turn. this looks painful and i'm hoping there's a better way.
EDIT: i've tried starting the "log in" activity with various flags to no avail,
loginIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_CLEAR_TASK|Intent.FLAG_ACTIVITY_CLEAR_TOP|Intent.FLAG_ACTIVITY_SINGLE_TOP);
on your manifest you can put the following attribute to your activity:
android:clearTaskOnLaunch="true"
so you would end up with something like:
<activity android:name=".ui.Activity" android:clearTaskOnLaunch="true" android:theme="#style/MyTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
Related
I have a launcher app which has a singleTask activity as the main entry point. When the user navigates away to another activity or to a 3rd party app and then hits the home button, then this activity should be brought to the front. However what I experience is that for the first home button press only, another instance is created instead (a new task is created, onCreate() is called). In the meantime the old task is still alive, containing the original instance of this activity, but it is impossible to navigate back to that task/activity or to bring it to the foreground.
After the first home button press, the next home button press brings the 2nd instance of this activity to the foreground. Not sure why not the very first instance's onNewIntent() method is called for the first time... So this only happens once, after that always the 2nd instance's onNewIntent() method is called. This means that the original activity will be not accessible..
I tried to bring the task to the foreground, nothing was happening... Like if it never existed (but the task is there with the activity, it is not killed at any point). I can find the task from code and also using a shell script. It contains the original activity
This is happening on Android TV (Os: Pie). Any idea what can be the reason for this? I do not really understand how this is happening... BTW the result is the same if I set the activity to singleInstance.
The activity looks like this:
<activity
android:name=".activities.MainActivity"
android:excludeFromRecents="true"
android:launchMode="singleTask"
android:theme="#style/AppTheme">
<intent-filter android:priority="2">
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.HOME"/>
<category android:name="android.intent.category.DEFAULT"/>
<category android:name="android.intent.category.LEANBACK_LAUNCHER"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.ALL_APPS"/>
<category android:name="android.intent.category.DEFAULT"/>
</intent-filter>
</activity>
I tried alternating the above attributes (priority, excludeFromRecents, taskAffinity), also removed them completely, they had no effect...
The home button press sends the following intent:
action: "android.intent.action.MAIN"
category:
"android.intent.category.HOME"
component: the above activity
it has also some extras but I do not think it is relevant
You are experiencing this nasty long-standing Android bug:
Re-launch of Activity on Home button, but...only the first time
You say in a comment that it doesn't happen with real users. That is not actually true. If a real user would install your app from the Play store and then launch it immediately (click the OPEN APP button after installation) then the problem would be reproduced exactly as you describe it.
I was struggling with the exactly same issue for the last couple of hours and I've read many similar Q&A about this topic/bug on StackOverflow. No solution really worked for me until, out of mere curiosity, I did the following.
If you're building a launcher and using onNewIntent() in your MainActivity (although OP doesn't mention that he's using this method), then simply comment out this line:
super.onNewIntent(intent);
Uninstall your app and install it again.
I don't know how this works, but EVEN when you then uncomment the very same line, it still behaves in a proper manner, that is: the app has really only single instance of its main activity all the time. And how I know that? My MainActivity is doing some database operations, and previously I saw in my Logcat that these operations were done twice every time, but now they are done only once.
And BTW my MainActivity tag in AndroidManifest.xml is nothing special:
<activity
android:name=".activities.MainActivity"
android:exported="true"
android:excludeFromRecents="true"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.HOME" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
In my application I have three activities:
<activity
android:name="com.example.myapp.SplashScreenActivity"
android:exported="true"
android:launchMode="singleInstance"
android:noHistory="true"
android:screenOrientation="sensorLandscape" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.example.myapp.MainActivity"
android:exported="false"
android:launchMode="singleInstance"
android:screenOrientation="sensorLandscape" >
</activity>
<activity
android:name="com.example.myapp.ListActivity"
android:exported="false"
android:launchMode="singleTop"
android:screenOrientation="sensorLandscape" >
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value="com.example.myapp.MainActivity" />
</activity>
The first one is the LAUNCHER, SplashScreenActivity, which is a splash screen that disappears quite soon and it's not shown in recent activities, it starts MainActivity. In MainActivity users can select a category and ListActivity shows the items belonging to the given category. This is done with the following code:
Intent i = new Intent(getActivity(),ListActivity.class);
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
i.putExtra("category",mCategory);
startActivity(i);
In ListActivity the onResume method checks for the "category" extra and shows data accordingly. Since Activity launchMode is singleTop, I've also overridden the onNewIntent method to set the new Intent of the Activity.
This works properly if the app doesn't go in background: in this case, when I restart MainActivity and select a category, ListActivity resumes the old Activity showing data belonging to the previously chosen category.
How should I fix flags/launchMode in such way that my app doesn't resume ListActivity with the old data loaded?
You should not use the special launch modes. These are rarely required and only in very specific circumstances. Remove all the launchMode specifiers from your manifest. You also don't need to use these flags when launching ListActivity from MainActivity:
i.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK|Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
Your use of singleInstance launch mode is causing you all these problems.
Assuming you would ditch all the launchModes and Flags, then activity lifecycle gives you all the information needed to implement application as you have described - maybe there is somethings you have not added?
Once application goes to background, then ListActivity will be allowed to save its state, even if system will kill your process (lack of memory etc.), then still - launching back your app will first bring back ListActivity with previously saved instance state. So you will not have behaviour as you describe : when I restart MainActivity and select a category, ListActivity resumes the old Activity showing data belonging to the previously chosen category.
Still, if you need to keep to your current design, then you should somehow inform ListActivity of new data changes, question is if ListActivity.onNewIntent is being called at all in the case your describe? Have you tried adding Intent.FLAG_ACTIVITY_SINGLE_TOP : as per this blog entry: http://www.acnenomor.com/1094151p2/bug-onnewintent-not-called-for-singletop-activity-with-intentflagactivitynewtask ?
I want to know what is the differences between the back and up actions.
I've already found online how they work, but I didn't find what different happens when I trigger them.
When I intent another activity and go back with up action, it seems to just show again my last activity without executing any method (my images show like it was cached).
When I intent another activity and go back with back action, it seems to reconstruct the entire layout (my images reloads).
What really happens?
Thanks.
First you must understand the concept of Up and Back navigation, you should read this link about Navigation with UP and Back
When pressed back button the actual screen is removed but when pressed up button relaunch the parent-activity.
In your manifest need to add propert launchMode of activity, something like this
<activity
android:name="com.example.client.app.MainActivity"
android:label="#string/app_name"
android:launchMode="singleInstance"
android:screenOrientation="portrait" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
I hope you serve.
I am experiencing a little pain on Android. I have two activities, one is a Splash Screen, launched when you click on the app icon, and an other one which can wake up when a specific event occurred (a NFC event, but it is not the problem).
There is the declaration in the manifest :
<activity android:label="#string/general.appName" android:name=".activity.SplashActivity" android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<activity android:excludeFromRecents="true" android:label="#string/general.appName" android:name=".EventReceiver" android:noHistory="true" android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.nfc.action.TRANSACTION_DETECTED">
</action>
<category android:name="android.intent.category.DEFAULT">
</category>
<data android:host="secure" android:path="/aXXXXX" android:port="0" android:scheme="nfc"/>
</intent-filter>
</activity>
All works fine, it means that the EventReceiver is launched when it received a specific event, the Splash Screen is functional etc...
But, when the application is launched by an event, so it is the EventReceiver which is launched first. If I pause the app by clicking on the home button of the phone, and by long clicking on it again, it makes appear the multitask table, with all the recent opened apps. There, is I click on my application, it resumed the application on the EventReceiver, just like if an event had occurred. So do you know a way to resume an application on one selected activity only (in my case the SplashScreen).
Or do you know a way to recognize that the application was resumed by a multitask function ? (I could open the good activity at the onCreate of my EventReceiver too if I get this information).
For the moment, the only solution I found is to put a android:excludeFromRecents="true" flag on my EventReceiver activity. This will result that the application will not appear in the multitask table if the application was launched by an event. But this is a little bit tricky and I do not like that very much.
Do you have any ideas ?
Thank you very much beforehand for your answers ! (and sorry for my scholar English ^^)
If you really have to detect when the application is lauched from the "recents" you can use intent flags.
if (getIntent().getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) {
// Lauched from recent apps.
}
Do NOT use a splash screen. It only slows down your app experience and has no value what so ever.
In addition... Android apps are a lose set of activities... There is no concrete entry point that would need a splash screen.
That said... the app switcher returns you to the previously active activity. In your case the .EventReceiver. You could change your structure by using a second activity that shows your ui so that the EventReceiver lets you forward to that.
Correct me if i am mistaken... But can't you intercept the nfc event with an receiver? From there you should open your ui activity.
Hello
My application works like this.
StartUpActivity is called first, which does a lot of the init stuff
Then it launches TvbTabActivity (TabActivity) that has other Activities as its tabs (e.g. BrowseActivity).
The problem that I am seeing is this - when a task-killer app is used to terminate my app on TvbTabActivity/Browse tab, and the app is relaunched again, the system forgoes the normal flow (StartUpActivity is not spawned), but instead restores the last visible activity directly (TvbTabActivity).
How can i force Android to ALWAYS run StartUpActivity first, so that it initializes the app?
Obviously, I dont have this problem when my app crashes on its own, lol, due to an exception, and is then relaunched again.
<application android:icon="#drawable/appicon"
android:label="#string/app_name" android:name="com.xyz.QPApplication"
android:debuggable="true">
<activity android:name=".activity.StartUpActivity" android:configChanges="locale|orientation"
android:label="#string/app_name"
android:screenOrientation="portrait">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name=".catalogue.BrowseActivity" android:configChanges="locale|orientation"
android:label="#string/app_name" android:screenOrientation="portrait"
android:launchMode="singleTop">
<intent-filter>
<action android:name="com.xyz.android.intent.action.BROWSE" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
<activity android:name=".activity.TvbTabActivity" android:configChanges="locale|orientation"
android:screenOrientation="portrait" android:launchMode="singleTask">
</activity>
You can't. Android will try to restore the app where it left off. The correct way to handle this is to ensure that you understand the Activity life-cycle and put the appropriate initialization in the appropriate place.
There are a couple of ways to solve your issue, the best would be to check the Android Life-cycle diagram http://code.google.com/android/images/activity_lifecycle.png and try to figure out a way to make the app work within that context.
Of course if you really want to you can kill your own app by calling Activity.finish() when it hits the onPause() or onStop() states, but that is quite an ugly solution.
You can't do anything about this -- what is happening to you is what the force stop API does and is intended to do.
Task killers are abusing that API.
They can no longer use it in 2.2 and later.
If you really want to avoid it, you could limit your app to only 2.2 or later. Or if the problem is users are complaining about them, tell them to stop using task killers. Or if the problem is just that you don't like this happening when you use a task killer, then don't use a task killer.
Also this is the same behavior that happens when the user presses "Force stop" in the manage application's UI. That is generally fine though since the user must explicitly do that, instead of what these task killer apps have been increasingly doing where they just whack stuff in the background without the user being directly involved.