How can I have my Android app resume where it last was, i.e. the Activity in view, etc.? If I am showing an Activity and press the Home button and then launch my app again it returns to the startup activity. I'd like it to work like an iPhone app where it suspends in place and resumes back to where the user last was.
Thank you.
You may need to set android:alwaysRetainTaskState="true" for your root activity in the manifest. From the documentation:
Whether or not the state of the task
that the activity is in will always be
maintained by the system — "true" if
it will be, and "false" if the system
is allowed to reset the task to its
initial state in certain situations.
The default value is "false". This
attribute is meaningful only for the
root activity of a task; it's ignored
for all other activities.
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.
However, when this
attribute is "true", users will always
return to the task in its last state,
regardless of how they get there. This
is useful, for example, in an
application like the web browser where
there is a lot of state (such as
multiple open tabs) that users would
not like to lose.
Be sure to save any information you want in your onPause method and check that information in onResume. This will let the app reload any information that was communicated. Some widgets keep state but others don't.
Additionally when an an activity is killed it's onSaveInstanceState method is called. So anything that needs to be stored to persistent memory should be done there.
Although i'm working with Mono for Android i had a similar question.
After some time researching on the web you can setup an Activity to be created using the singleton pattern. This will cause your app to only create one instance and - if you go back to the activity - this will load the last state of that activity for you.
You can do this by configuring the activity with the
android:alwaysRetainTaskState="true"
and the
android:launchMode="singleTask" //(preffered, or "singleInstance")
properties.
Singletask is the best since singleInstance is more suitable for single-activity-based apps.
In my case setting the launchmode made this baby rock as i wanted but i don't know if this is a Mono for Android or Android issue at the root..
Be aware: you will need to create an initialize method or something alike if you'd like to create a clean/fresh/new instance of the activity at some point.
Related
when I am in the last activity and I press back, my app goes to the background but when I return my app restarts going back to the "login" screen, if I am in "Home" and I go back it goes to the background because my login activity finished, I understand this is part of how the Android system works. Having an app with an sdk that uses bluetooh with asynTask tasks, I would like to be able to force an activity not to close or cancel when it goes to the background, I am looking for alternative solutions such as making the app stay in "widget" mode or being able to launch some kind of "service" that forces my activity as such not to close or restart when it goes to the background, I'm quite new to all this, any suggestion on how to solve this problem will be welcome
Backing out of the last Activity on the stack treats the app as "closed", and there are expected behaviours associated with that:
The user's assumption in these complete dismissal cases is that they have permanently navigated away from the activity, and if they re-open the activity they expect the activity to start from a clean state. The underlying system behavior for these dismissal scenarios matches the user expectation - the activity instance will get destroyed and removed from memory, along with any state stored in it and any saved instance state record associated with the activity.
So while it is possible to restore the previous state (the example they give is a web browser opening at the same page it was on) the system and components like Navigation are built around this idea that state shouldn't be preserved. You'd have to put in effort to work around that.
Running a Service only keeps your app's process alive - it won't do anything for background Activities, which the system will destroy if it needs the memory. And besides, like it says above, if you back out of an Activity it's considered dismissed and its state is wiped, whether it's been kicked out of memory or not.
Honestly it sounds like you just want to avoid redisplaying the login screen if the user's already logged in? That shouldn't be anything to do with Activity state, you should be storing that data somewhere so you can check it when the app starts, so you can send them to the appropriate screen
There's a whole section about this exact scenario in the Navigation docs. They don't show their UserViewModel (which we're supposed to imagine handling logged-in state, and actually doing the user/password auth if necessary) but the idea is pretty simple - you have a component that exposes a value saying whether the user is logged in or not (which could be stored in e.g. SharedPreferences) and it can automatically navigate away from the login screen based on that.
I found and read a lot of articles talking about global variables in Android, some of them suggests using an subclass of Application + declare it in the manifest file as a glbal variable container.
But some articles mentioned that This class could also be killed when system memory gets low, is this correct?
So, is it 100% reliable to use an Application subclass as a global variable container? And could somebody give me a link to some documents explaining the life cycle of an application in Android (not activity)?
EDIT:
Thanks for the answers, I think I need to explain a bit more of my question.
The situation is, I just want to share a global String variable, Activity A modifies it, and activity B reads it.
When B is currently visible and user receives a call,
If A and B are killed but Application keep untouched (is this what Google calls an empty process?), I'm OK with it.
If A, B, and Application class are all killed and when user come back my app gets a clean start, I'm OK with it.
Which I'm not OK with it is, everything was killed including the Application class, when user come back my app doesn't start fresh, I mean, it starts from Activity B, will this happen? then should I start A manually or let Application class to do the initiation? none of these ideas looks good to me...
The answer is both "YES" and "NO" - the Application class can be used as a "global variable container" in that all activities and classes can rely on it.
However, you cannot rely on the Application class (or any other class) to persist indefinitely. In other words, if the user answers their phone, your application could be destroyed and then re-created when the user completes the call and returns to your app. So, you definitely cannot rely on it to persist data, but you can rely on it to provide global access to data when you app is active.
This is the Android documentation:
http://developer.android.com/training/basics/activity-lifecycle/index.html
This is a really good post on it - read the SECOND highest voted response, in addition to the "accepted" response:
Using the Android Application class to persist data
It explains pretty clearly how your app can be killed/destroyed whether you expect it or not.
EDIT:
To clarify, if you have a variable (call it "myVar") in the Application class and a user sets it in Activity A, then proceeds to Activity B, Activity B will be able to read the change.
If Android "destroys" the application class, which can occur anytime the user is not in your app (and in rare instances even if they are...), the app will be reconstructed so that the Activity Stack is still valid but "myVar" is not set, unless you persist the data.
In other words, Android will recreate the Application class and Activity B, but there is no guarantee that it will recreate Activity A until the user does something to destroy Activity B. Also, it will certainly not "replay" the user actions in Activity A in order to recreate the app state, and in your case that means "myVar" is not reliable.
If you read the references provided, you will see that this is the case (and also I have tested it).
EDIT 2:
To persist data, consider SQLite (which is pretty complicated and there are many references) or SharedPreferences:
How to use SharedPreferences in Android to store, fetch and edit values
This class could also be killed when system memory gets low, is this correct?
Yes.
So, is it 100% reliable to use an Application subclass as a global
variable container?
If you want to use it to pass values it is not reliable.
why?
EDIT:
Which I'm not OK with it is, everything was killed including the
Application class, when user come back my app doesn't start fresh, I
mean, it starts from Activity B, will this happen?
yes. It is possible that you set a value in your application from activity A and then when you are in Activity B user leaves your app and after a while android kills your process. then user comes back wants to look at your app. android again recreates application and activity B but not Activity A and instead of fill the application variable with what has passed Activity A to it, it recreates it from default initialization. So simply you missed what has passed or set by Activity A.
Don’t Store Data in the Application Object
I am trying to simulate Activity and Fragment re-creation and also to check onSaveInstancestate() and onRestoreInstanceState() and generally so check if I am handling activity re-creation in a good way in all cases, for example, just like when screen rotation causing the activity to re-create it self.
But in my case I want to check more options/cases which can cause re-creation because my app cannot be rotate(all activities are in portrait).
I saw many articles, blogs and stackoverflow question/answers about this topic, for example here, here, and here.
And as this stackoverflow answers says Why not use always android:configChanges="keyboardHidden|orientation"?
there are many more events which can cause activity re-creation, so after I read it I wanted to test my app for some of those events.
For example I pressed the home button in my activity and then I went into settings and tried to change the language, change the font size , etc... , but non of those actions made my app re-create as I would expect.
When I returned to my app , it just resumed and onCreate() never called.
So I even check the official documents about this. and they also says that it should cause my activity to re-create: Quoting:
"When a configuration change occurs at runtime, the activity is shut down and restarted by default"
but as I said it didn't happen to me.
This is I huge for me because I was very naïve and thought that if my app will be only in portrait or if I will add to the manifest this line :
android:configChanges="keyboardHidden|orientation|screenSize"
then every thing will be ok and obviously its not because there are many more configurations changes which can restart my activity, so I can't run from it anymore and I want to handle it in a good manner and now I want to also test it.
Changing the device language is one way to force re-creation of all activities that doesn't involve orientation change.
You said that it wasn't being recreated when you change the orientation of your device while in the app. Normally it would. When you added the lines android:configChanges="orientation" it means that you're telling the system you will deal with orientation changes in your app and not to worry about the normal behaviour.
If you remove that from your activity declaration in the manifest, you'll see it operating as expected (destroying/recreating on orientation change).
Hope that helps.
Pressing the home button will only initially cause onPause to be raised. Your Activity will not go through onCreate again until it has been fully destroyed, which won't happen unless Android decides it needs the memory for other processes.
The easiest way is just to remove orientation from configChanges and then rotate your Activity and see what happens. The layouts might not work correctly, but your should be able to inspect your lifecycle code. Similarly, remove keyboardHidden and then toggle the soft keyboard. Your Activity should go through the lifecycle sequence.
Changing the locale for the device should cause your Activity to be recreated. Note that this is the global locale that needs to be changed, not the language the keyboard is typing in.
Other ways come to mind such as manually destroying the app either via a key sequence on the phone (for example, holding down the Home button and swiping left on the app to kill on some phones), or by terminating it from your debugger.
On your device/emulator Developer Options, activate the option:
"Don't keep activities".
With it on, anytime the activity is paused and returned the cycle for saved instance is called (e.g. another activity in front of it or home button pressed to minimize all apps, ...). It's useful to test and simulate recreation and related bugs.
On the first time my app is running, on the root activity, the user is required to select a certain options that determines which data would be downloaded for him from a database.
Once he had picked that option, the data is downloaded and kept on a singleton class that should hold that data as long as the application is running. (Even in the background)
My problem is that sometimes after the user exits my application for a while (using the home button), Android apparently kills some of the activities in my app, and somehow with them, it resets the important singleton class. Causing my app to receive all kinds of null reference exception once I try to access the data that is supposed to be kept on the singleton.
I understand that the Android OS can sometimes choose to kill an application, but allow the user to return to it from his last visited activity. Sometimes it just kills the whole application and forces the user to begin from the start.
I was looking for a solution, and I found out about "android:alwaysRetainTaskState" attribute that I can apply on my root activity. Apparently with it, whenever android decides to kill my app, it would at least force the user to begin from the first activity where I can re-download the data, instead of allowing the user to begin with a more advanced activity causing him to get null exceptions.
However when I applied it on my application it did not work, and when I returned to my application I was beginning from an advanced activity, with an empty singleton instance.
I also tried "android:clearTaskOnLaunch" and it worked, but it's an overkill, since I don't want that every time the user would return to the app, he would have to start over. I want it to happen only if android decided to kill the app.
Is there something I'm doing wrong? Is there any chance maybe there's a better solution for keeping the singleton alive?
Thanks!
Nope. There is not better solution. This is how it works. Android can kill your application's process whenever it wants to (as long as it is in the background). You can keep data in a singleton, but it is always possible that Android kills your process anyway. When the user returns to your application Android will create a new process and then create a new instance of the activity that the user is resuming. You need to put code in onCreate() of all your activities that recognizes that your singleton is gone and then does an appropriate thing (either redirects to the root activity of your application or reinitializes your singleton.
It is pretty easy to tell if your process has been killed and recreated. Just add a static boolean variable to your singleton that you set to true when it has initialized. In onCreate() of all your activities, check the state of that variable and do something intelligent if the variable is false.
Often when I open my Android app from either my Home screen shortcut or from the apps menu it restarts the main activity.
How can I prevent this behavior and make it bring the existing instance to the foreground if there is one running?
I've searched quite a bit to no avail. It would seem as though most others are not having this problem?
Thanks!
You can never assume that Android retains the state of your app after you move away from it - because of a low memory situation, it may have removed it from memory.
Your best bet is to store the current state (including the current activity) in your SharedPreferences, and in your main activity (the one marked as LAUNCHER in your manifest), you check the shared preferences and go to the activity marked there. You can also use the SharedPreferences to store other information about the activity, i.e. you can use it to fill out text fields and other things with whatever values they had when the user left.