I want to know what are the pro and cons when you try to open a new activity with android and destroy the previous one straight away by calling finish.
People think that is a bad idea because Android can take care of the activity and drop them when there is too much memory used, but what about if I get inside that activity once and probably the user will never come back? Is this a bad option?
Also by finishing the activity, the history with the back button is "clear", so it wont get back to that activity ( only if your user flow needed to go back I think you should not call finish ).
And in terms of memory, is better to kill the activity with finish or leave android to have this activity in the background for who knows for how long time?
I feel like, that you kind of help the system to GC the activity that you closed and make sure that the user wont need to tap the back button 100 times before getting out of the application.
So what do you think? Better call Finish or not
I want to know what are the pro and cons when you try to open a new activity with android and destroy the previous one straight away by calling finish.
Either you want the user to return to the previous activity via the BACK button, or you do not.
If you want the user to return to the previous activity via BACK, do not call finish()
If you do not want the user to return to the previous activity via BACK, there are a multitude of options, depending upon where you do want the user to go when the user presses BACK
People think that is a bad idea because Android can take care of the activity and drop them when there is too much memory used
No, Android does not do this.
is better to kill the activity with finish or leave android to have this activity in the background for who knows for how long time?
It is "better" to have the activity implement onTrimMemory() and reduce its memory footprint as needed. Do not harm the user expectations of the BACK button.
that you kind of help the system to GC the activity that you closed and make sure that the user wont need to tap the back button 100 times before getting out of the application
Few users will "tap the back button 100 times". They will press HOME, or bring up the overview screen (a.k.a., recent-tasks list), or navigate to another app by other means.
Now, that being said, there will be times when you want to clear the task (back stack), again with an eye towards providing a logical flow for the user. For example, in an email app:
The user launches the app, and a fresh task is created, with the user going to the app's launcher activity, which shows the messages in the user's inbox (A)
The user taps on a "search" action bar item, bringing up a search activity, where they can search by various criteria (B)
The user fills in search criteria and clicks the "Go!" button, which does the search and shows matching email messages (C)
The user taps on an email message, bringing up an email-viewing activity (D)
The user taps a "delete" action bar item, which should delete the message and return the user... somewhere
If you believe that the user should return to the search results (C), you could call finish() in D. If, however, you believe that the user should return to the inbox (A), you would call startActivity() on A with appropriate flags (e.g., Intent.FLAG_ACTIVITY_CLEAR_TASK), to clear out the back stack and return the user to A.
In sum: do NOT call finish() to deal with heap space; implement onTrimMemory() instead. However, if navigation calls for finish(), then use it.
Related
I know that in Android, if stuff is idle for a while, the operating system will devour things to free up memory.
So if I have a first Activity, and I invoke a second Activity by using an Intent, and then invoke a third Activity using yet another Intent, I can use the back button to go back to the previous Activities.
But let's say I stay on the third Activity, and let the phone idle for a while until the OS decides to devour my app for memory. If I open the app again, will I have lost the stack I have formed from my Intents? Will I still be in the third Activity with the ability to press Back and go to Activity 2, then Activity 1?
The OS will handle how long a particular Activity stays "active" in memory. However, the "stack" shouldn't change, regardless of whether an activity is "active" or not. This is where the Bundle comes in handy and the methods: "onSaveInstanceState()" and "onRestoreInstanceState()".
Implementing these methods properly is the difference of the activity reappearing on the screen in an empty state vs. with its previous state maintained.
Some documentation on Recreating an Activity
The backstack stays intact for the task in hand. It will always stay in task and whenever the user presses the back button, it will go through the back stack like popping the last item. However, not all the activities in the stack are in the foreground. Usually, only the last item put into the back stack (the top of the stack) is in the foreground and if there are multiple apps/tasks open this may not even be true. Here is a great diagram to show this.
Now, lets say a user opens a task with a couple of activities in its back stack. The top activity is in the foreground and is running normally, but to preserve memory the other activities were destroyed. So now when the user presses the back button, the task knows what activity was in the back stack and knows it is now destroyed. So, it will recreate it following the Activities lifecycle and any data that was in it will be lost. One way to preserve it (mentioned by original answer) is using the onSaveInstanceState() and onRestoreInstanceState(), which save things in a bundle that Android preserves for the user so data can be saved. All of this information can be found in the docs. To answer your question more clearly, yes you will be in the activity you think you would be in, but you can treat it as a new instance of that activity and to recover the data from before to display it in the same way, you should use bundle and implement the methods aforementioned.
I'm working on an Android app that will show college fitness professors how their students are doing in their classes. Since this data is fairly sensitive (biometrics are shown, including weight, something many college students are self-conscious about) I don't want the data to be available to anyone who picks up the tablet. While I have a proper login screen created, complete with authentication for the database, etc. I have an issue when the home button is pressed. Since Android doesn't close a program immediately on leaving the app, it's possible to reopen it and return to where you were. I would like to force the app to return to the login screen each time (I've altered onBackPressed so you can't just return to the previous view from the login screen) so that you have to re-enter your credentials to get back into the app. However, I can't seem to do this. An answer I found on here said to use the following line:
android:clearTaskOnLaunch="true"
However, no matter what XML file I put it in, be it the Manifest or the individual Activity XMLs, it appears to do nothing. So, how do I ensure the login screen comes up each time the app is launched, regardless of whether it is starting from scratch or not?
Try to play around with onUserLeaveHint() method. If you read its documentation, it says:
Its Called as part of the activity lifecycle when an activity is about to go into the background as the result of user choice. For example, when the user presses the Home key, onUserLeaveHint() will be called, but when an incoming phone call causes the in-call Activity to be automatically brought to the foreground, onUserLeaveHint() will not be called
So, when ever you detected home button pressed, you can finish the running activity/activities. So next time user click the app, it will start from the first login screen.
Hope this helps.
You should override onUserLeaveHint()
#Override
protected void onUserLeaveHint() {
// do your logic
//finish() or start login activity
}
You could set a flag when onPause() is initiated within the activity. And then when you return you could check the flag from within onResume() and then request a login from that point. This will be sure to request it each time; in a simple case of course.
Edit:
With multiple activities, you could check against a saved context to see if they are the same when you start a new activity. If the contexts differ then you can discard the context previous activities context and start a new activity.
If they are the same, then you have come back to the activity from itself (you have lowered and brought the screen back). You would have to use some form of saved state such as that to do it in this manner with multiple activities when outside the case of a simple application.
I found out how to do it in my case. For any others with the same problem, try following the example here:
Android detecting if an application entered the background
This is pretty elaborate, so I'll try and be as clear as possible. Currently, my application needs to reload some data when it is launched. I am loading this data in the onCreate/onRestart methods of my main activity. However, I need to be careful to not reload the data if the user never leaves the current task.
For instance, if I need to start the in-built Contacts application from my main activity to select a contact, then my main activity will pause/stop while I am selecting a new contact. When I return to my main activity, onRestart will be called. In this case, because I have never left the Application's task, I do not want to reload the data. This means some check needs to be included here to determine if the user has come straight back from the Contacts app without ever leaving it.
Otherwise, if the user exits the Contacts app while it was open and re-launched the app from the launcher menu (or recent apps list, etc) - I want to close the Contacts app and reload the data when the Main activity's onRestart method is called.
Is there a way to do this without using any user-frightening permissions (e.g. GET_TASKS). I have been stuck on this problem for a long time now so any help would be GREATLY appreciated :)
Tyvm,
B. Campbell
I learned a lot from the Android docs:
Tasks and Back Stack
Navigation with Back and Up
Application Structure
Here is some highlight:
A task is a collection of activities that users interact with when
performing a certain job. The activities are arranged in a stack (the
"back stack"), in the order in which each activity is opened.
When the current activity starts another, the new activity is pushed
on the top of the stack and takes focus. The previous activity remains
in the stack, but is stopped. When an activity stops, the system
retains the current state of its user interface. When the user presses
the Back button, the current activity is popped from the top of the
stack (the activity is destroyed) and the previous activity resumes
(the previous state of its UI is restored). Activities in the stack
are never rearranged, only pushed and popped from the stack—pushed
onto the stack when started by the current activity and popped off
when the user leaves it using the Back button.
It means when your application pick up a contact, the activity stack in the task might be:
| Activity A in Contacts |
| Activity B in Your App |
| Activity C in other app|
When the user leaves a task by pressing the Home button, the current
activity is stopped and its task goes into the background. The system
retains the state of every activity in the task. If the user later
resumes the task by selecting the launcher icon that began the task,
the task comes to the foreground and resumes the activity at the top
of the stack.
Even if the user exits the Contacts app while it was open and re-launched the app from the launcher menu or recent app list, the activity stack is still like the one we see above. The only possibility that may make your acitity start from another task is another app(might be a launcher app) that start the main activity in a new task by startActivity flags, which is a rare case. In this rare case, you can simply check the uid of the app who start your activity by Binder.getCallinguid() to differentiate it.
EDIT based on comments:
You may check if activity was opened from history by FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY:
if ((getIntent().getFlags() & Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY) != 0){
}else{
}
You can also look into:
android:excludeFromRecents if you don't want your app start from recent apps
android:finishOnTaskLaunch
android:stateNotNeeded
If the data you are loading related to the application life-cycle not to a specific activity, you can load it in application class, so it will not be reloaded again unless your application task is killed.
if a user tapped the home button and open the app after that, how to not allow back? eg don't allow users to go back to screens that they seen before tapping the home button. It should be treated as a new session
This sounds like a bad idea, as it blatantly goes against the Android task/navigation guidelines.
The user expects to be able to back out to the previous screen after resuming a task... and preventing it will potentially piss off a lot of users.
Please, please, please read these documents before you risk destroying the user experience.
App structure
Navigation
Tasks and back stack
The home button cannot be overridden nore should it, if you dont want the user to go back to the activity they left when the home button was clicked then on the on pause of the activity just pop the backstack to where you want to be.
see this answer
If you want to end your Activity once it is no longer visible then finish your activity in your Activities call to onStop().
#Override
protected void onStop() {
super.onStop();
this.finish();
}
This will finish your Activity with no chance of onRestart() being called. Be careful with this method because users expect to resume the app instead of having to start over, but there are cases where this would be the accepted protocol. See more on Navigation and the Activity LifeCycle.
Edit:
Also see the question Android-Quittings an application - is that frowned upon? specifically this answer.
I'm ware of androids life cycle and that it's not needed to add a "exit" button in the application.
But still, this back button stuff isn't really working out well.
You maybe know this issue from the default SMS-App that android comes with: you open it when you get a new message and exit it using the menu button or something else.
After like 20 times doing this, you then decide to exit the app using the back button, what happens? you have to go back though 20 views. every time you press back you return to the "all messages (by sender)" listview and when you press back there again you return to the message opend 20-1 (message 19). again you press back and return to the listview and again you press back and end up at message 18. till, after40 times pressing back, you finally exit the messanger app.
same happens when for example you got a action bar with a "home" icon which opens the main screen of your app. the user picks a action and the new activity starts. than the user clicks the home button and returns to the main screen. when pressing the back button - no matter if you call finish() in the onButtonBack listener or not, you the user would expect the app to exit, but in fact the app returns to the previous activity which is wrong.
such cycleing may happen for various reasons, thats why - even thought i'm aware of the supposed to be lifecycle of android - i wan't to EXIT (& destroy) the app when pressing back within a defined activity.
calling finish() dosn't help. if there's a previous activity it will re-open it. calling system.exit(0) isn't nice to do.
so: whats the right way to prevent such back-press-cycles and/or exit a application (WITH destruction)?
for better illustration of what i want to achieve: consider A, B, C being activities. a arrow (-->) illustrations a new intent call from the activity leftside of the arrow, rightside of the arrow represents the activity that is called. ex.: A --> B means activity A starts activity B. now here's what i want:
1) A --> B --> C pressBack:--> B pressBack:-->A pressBack:--> Exit
2) A --> B pressBack: --> A pressBack: --> Exit
3) A --> B --> A pressBack:--> Exit
as you see, back works as always, BUT when in activity A it exits the application.
the behaviour i got now is 1) and 2) as above but
3) A --> B --> A pressBack:--> A pressBack: --> Exit
keep in mind, i've already overwritten the onBackPressed listener of activity A with a finish() call. even calling system.exit(0) dosnt work. however, even if it would: its not what i want, i want the REAL way to do it android style - i cant imagine system.exit(0) is best practise.
Well this is the default behavior.
If you have another approach, just implement it.
One approach to deal with this is to use the android:launchMode="singleInstance" for activities that can be launched in a singleton manner (only one activity can exist)
For example, if the SMS page in the SMS app was a singleTop, it would have needed only one back press to remove all the SMS pages. It is a matter of choice
Another more aggressive way would be to finish Activities when you start another activity. Of course, such decision would risk making the app less friendly (android users are not accustomed to this behavior). Nevertheless, if this is used only where it may be considered acceptable then it might be acceptable.
A very acceptable place to do this would be a login screen: Once login is successfull, you start another activity (probably designed for logged in users) and finish the login activity.
Enjoy Finally, in my personal opinion, you can add an Exit button. Users will find it nice.
Check my post: Adding an Exit button to Android Application