I am building an Android app, which starts a service that keeps running in the background. When the user uses the Home button to close one of the activities (which communicate with the service), and then navigates to the app again, they get the last activity. This is correct behaviour.
However, when I explicitly stop the service (via an option in the menu), the app should "Quit". Currently, that works like this:
stopService(new Intent(this, MyService.class));
finish();
// just go to to the home screen, as it is intended in Android
Intent intent = new Intent(Intent.ACTION_MAIN);
intent.addCategory(Intent.CATEGORY_HOME);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
and that works fine. But when I now navigate to the app again, it starts the previously opened Activity. What I want is that it starts the starting activity again (the launcher).
How could I accomplish that?
System.exit(0);
But you should have only one Activity in stack.
If you look at the description of android:excludeFromRecents it says:
Whether or not the task initiated by this activity should be excluded from the list of recently used applications ("recent apps").
isn't this what you are looking for ? Once the user hits exit, this app won't be in the recently used apps and hence will be completely removed from memory ? :)
I think that removing 'the app completely from memory on exit' is not the issue. Even if you stop your service the process is likely to remain in memory - that is the systems' decision.
You want an explicit, custom behaviour - user chooses your 'exit' option from menu --> next app launch starts at main activity - so you will need to handle this explicitly.
The default behaviour is that the user returns to their last activity when they re-launch. So they only return to the main activity if they exit by 'backing out' through your activities. Your use of an 'exit' menu option is non-standard (not to say it is bad).
One option would be to do the backing out through your activities yourself. Perhaps now you are just finishing the current activity and you should instead finish all the activities in the back stack.
Another option is that you could save a flag, and when the UI is launched again you could read that flag and launch the appropriate activity (but again be careful with the backstack). The easiest way to set that flag is probably by overriding onSaveInstanceState(Bundle) and then reading the bundle in onCreate (or use sharedpreferences).
Have you tried setting the clearTaskOnLaunch to true for your main activity (in your manifest).
From the documentation:
When the value is "true", every time users start the task again, they are brought to its root activity regardless of what they were last doing in the task and regardless of whether they used the Back or Home button to leave it.
This seems to describe what you want to do. I have never tried this personally, but it seems worth investigating for your purpose.
Related
I've written an android application.
So, this is what happens:
I've got a listview and if the user taps on a specific row the following code in invoked to create an activity:
Intent intent = new Intent();
intent.setClassName( getPackageName(), getPackageName() + ".matchView.MatchViewActivity" );
intent.putExtra("leagueId", leagueId );
startActivity( intent );
Then the activity is started and let's suppose the user return back to the list view by tapping the back button
Now he is again in the Listview and can tap the same cell again such that the same activity is started again.
However, the problem is that when I start the activity and I return back with the back button the (now old) activity is not deallocated. It still runs in the background and if the user again taps on the same cell the same acitvity is started again resulting in the same activity running two, three, four and so on times (depending on how often the user taps).
So if the user taps the back button how do I make sure that the activity I started is properly deleted or ended?
Activity will be deleted automatically (when you return back) by system if you are not holding any reference to it.
Better read about activities and back stack
Answering to your question, if you don't intend anymore to use an Activity, the correct way of ending it is by calling finish().
This tells the Android SO you don't want to use it again, but don't expect it to be finished immediately. Android keeps the references to both instances and Activities (this ones are instances too) in memory a certain time after finished so if the user reopens that Activity within a short amount of time, it's recovered much faster.
If you are worried about the state in which the Activity is reopened, you can force it to be restarted every time it's reopened. You might find more references in the Intent reference page, especially the FLAG_ACTIVITY_CLEAR_TOP flag.
You can define in the manifest how an activity is launched based on the "launchMode", and you can choose from one of four launch modes:
"standard"
"singleTop"
"singleTask"
"singleInstance"
It sounds like you want to use, "singleTask" or "singleInstance", which you can read more about under the "android:launchMode" section here:
http://developer.android.com/guide/topics/manifest/activity-element.html
Add finish(); after starting the new activity to delete the current one.
I'm encountering the following scenario in my application:
Installing it and immediately opening it (using the open button
after the installation, instead of the icon in the applications
list).
Navigating through a few activities.
Clicking the home button.
Clicking the application icon to load it again.
Instead of returning to the activity I was in, the initial activity
is loaded. The previous activity is still there and can be accessed by clicking the back button, but there isn't really a way to know that and it looks like the app was completely restarted.
This may be an issue in this app, because in some cases it might require a registration after performing a few actions, and losing the focus on the activity could be very annoying
Is there anything that can be done to avoid that?
There's a couple of flags under Intent that might be helpful. You use them when an Activity is launched:
"FLAG_ACTIVITY_TASK_ON_HOME: If set in an Intent passed to Context.startActivity(), this flag will cause a newly launching task to be placed on top of the current home activity task (if there is one).
FLAG_ACTIVITY_REORDER_TO_FRONT: If set in an Intent passed to Context.startActivity(), this flag will cause the launched activity to be brought to the front of its task's history stack if it is already running."
http://developer.android.com/reference/android/content/Intent.html
I am trying to close a whole stack of activities using the way described here:
How to kill an application with all its activities?
Namely, each activity starts the other one with startActivityForResult, and in onActivityResult calls finish() to close itself together with the activity it opened.
The problem is that the activities in the task still seem to repaint themselves at least once before they close, and this doesn't look good. After closing the topmost activity one sees all previously opened activities like in a very fast slideshow.
How can one avoid this graphical issue?
EDIT: I need that if the user presses HOME button and then presses the app's icon in launcher, he returns to the current state of the stack, not to the very first activity again. So, from what I understand, with such a requirement I can't finish() activities before starting next ones.
That's native behaviour, intended to aid in user Experience. When an Activity is started with startActivityForResult and then finishes, it will (on devices that allow fancy animations) automatically slide away. That helps people not get surprised by the screen suddenly changing.
You could try starting the Activities without startActivityForResult and handling the passing of data to and from Activities manually, then handle how/when Activities finish() and which Activity they pass back to. You might find you implement something where Activities actually pass forward to the appropriate Activity all the time, rather than back to an Activity on the stack.
Intent intent = new Intent();
intent.setClass(getApplicationContext(),
PhoneListCheckboxAES.class);
intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
If u give like this when u are starting the next activity then the graphical problems won't occur
I have multiple activities in my application .
The flow for activities is
A->B->C...
A->D->E...
A->F->G..
....
And each has a back button to go back to previous activity and home to go back to A.
My question is when i launch each of these as singletask, i can visible feel fast switching between activities when i click back or home. I dont see any issues if i keep them as singletask.
BUt are there any issues that i am verlooking if i keep the activities as singletask in my application. Thanks a lot for your time and help
Yes there are issues in changing the behaviour mode of activity from mainfest.xml, When you will press the home button for android home screen and get back to the application the previous activity will be gone and will finish the application, then better is to use intent instead using single task mode, you can use flags with intent to cleat the activity stacks..and by launching the mode in single task you are changing the systems settings, why dont you keep the launch mode and give it to system for handling the activities..!
Intent intent = new Intent(getApplicationContext(),A.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
startActivity(intent);
finish();
A "standard" or "singleTop" activity can be instantiated many
times. They can belong to multiple tasks, and a given task can
have multiple instances of the same activity.
In contrast, "singleTask" and "singleInstance" activities are
limited to just one instance. Since these activities are at the
root of a task, this limitation means that there is never more
than a single instance of the task on the device at one time.
The clearTaskOnLaunch attribute If this attribute is set to
"true" in the root activity of a task, the stack is cleared down
to the root activity whenever the user leaves the task and
returns to it. In other words, it's the polar opposite of
alwaysRetainTaskState(which u can use if u want to retain all activities in a stsck). The user always returns to the task in
its initial state, even after a momentary absence or even after pressing home in ur case.
The problem is somewhat odd and after having trying to figure it out for about a day now, I am posting it here.
I have an application where an activity A(main activity) launches other activities(B,C or D).
The issue here happens when activity A has started Activity B and 'home' button is pressed.
Case 1 - When I test my application in debug mode on my device (HTC Desire) after pressing the 'home' button, I again click the application icon, it returns to the same activity (activity B), which is what is should do. No issues here.
Case 2 - When I export the signed package, and then install the application on the same device, then if I click the application icon after pressing the 'home' button, then a new instance of activity A (main activity) is launched ON TOP of activity B. I got to know this because when I press 'back' from that activity, it returns to activity B and pressing 'back' again shown activity A.
The behavior ceases to exist if the application is quit in the same order it was started, that is, if I press 'back' from activity B, then 'back' from activity A (exit).
After this everything runs fine.
I have tested it many times with different settings but I can't seem to figure out why the behavior is like this.
Any help is appreciated.
I think giving Activity A the 'single top' flag in your manifest should fix this.
Regarding Case 1:
When launching your intent from Activity A to start Activity B, add the flag FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET
This will ensure that when you go home and launch the the app again, Activity A will be shown.
Regarding Case 2:
I'm not exactly sure how this would occur. It seems like it thinks you have two versions of the app, the signed one and the unsigned one but keeps them both in the same task stack. You may want to consider using singleTask or singleInstance for your Activity if you only want one instance. See the doc on tasks and back stack for more details.
I would agree with Noel regarding the likely cause of Case 2. Without task reparenting or it being set to a launchmode preventing multiple instances of an activity, there is a chance that launching it from Home isn't deemed the same stack as launching it from Eclipse (assuming this to be the case).
In my talent calculator app I have the whole application set allowTaskReparenting=true to ensure nothing is left in other stacks (primarily email as it can email launch urls). I then have my main activity set to launchMode="singleTask" as I only ever want one instance of this to exist no matter what launches it or with whatever intent.
My only other activity is for loading and saving and that has noHistory="true" to make sure it is removed and never returned to. That basically means it only exists while you're in it, and can never return to it.
clearTaskOnLaunch="true" will also ensure only the main Activity remains in the stack when it's launched from Home, but this isn't always the case if you have other ways to get into your activity. If it's only ever launched from Home then set this.
Hope that all helps.
Do you start you application manually or using Eclipse or another IDE? When starting from Intellij IDEA I had exactly the same problems. Then I stopped and ran it manually and behaviour was as expected.