I've noticed an odd behaviour in an app I'm analyzing and I would like to know if this is by design or it's simply a bug of the platform?
I have a complex application but to simplify my example lets say I have an application with Activity A and B. Now if I run my application and go from A -> B, given that I won't finish Activity A, then I will kill the process (but the app window is still visible in Recent applications) then if I tap the window in recent apps what would happen is:
1) Process is being created
2) Application object is being created
3) Stack is untached (A -> B) and after analyzing it by the framework Activity B is recreated
4) Activity A is "dead" untill I hit the back button
Now the interesting thing happens if I introduce a large singleton instance, lets say an instance of "Dictionary" which can hold many key-value pairs. If that dictionary instance is large enough the above scenario will not happen, meaning that the stack appears to be cleared and my application will follow a typical launch scenario so Activity A is being created instead of Activity B.
Is this a proper behaviour of the Android Framework and if so... why is that proper? I'm interested in the reason and why this occurs.
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 am using Singleton pattern. When application goes into background the OS kills the app to release memory. When user comes back to app my application starts from same Activity User left off but my singleton instance is not available because it was released too when OS released memory.
Suppose I am at Activity 5 and I have values int a = singleton.getInt() it will give me a null pointer exception. Other local views initialized are null too. But if my application restarts from splash screen then its all good because app flow is starting from scratch. Sometimes it starts from Splash, some times it goes to Activity 5 or whatever activity User left off (which will cause null pointer exception). I have used a lifecycle Observer to monitor application state in MainApplication but what exactly is the root of this issue. Any ideas?
Why does this happen?
When the system kills your application to free the memory it saves a few pieces of data about the current state of your Application into the internal OS storage. Later on, when the user opens your app once again, the system takes that saved data from the storage and tries to restore the state of the Application.
The reason for that behavior is to make the user experience smoother. By restoring the state - the user can quickly continue doing things he was doing before quitting your application.
Some of the data that is stored in the OS storage:
Activities back stack (back stack of the Task)
FragmentManagers back stack
Bundle that you saved in the onSaveInstanceState methods
Please note: ViewModels are not saved between application re-creation. Even though they are saved upon Activity recreation(configuration change, such as screen rotation). So data that you store inside of your ViewModels (if any) would be lost!
In order to support this OS feature and ensure a smooth user experience in your application, you must design your application to not depend on any Launcher Activity to instantiate your singletons and instead use some other architectural approach that would not require your Launcher Screen to launch every time the application restarts.
What can you do?
You could try one of the following:
Save all the user input data (if any) to the Bundle in onSaveInstanceState method.
Migrate from Splash Screen Activity or Launcher Activity in favor of the Reactive approach to data instantiation.
Move your Singleton instantiation to Application class. Note: This could significantly increase the launch time of your application.
That is by no means an exhaustive list of actions you could do. I bet you would have better ideas that are applicable to your own application.
If migrating away from Launcher Activity is not possible at the moment, I suggest adding to your Activity onCreate method a check that everything is instantiated and ready to use. If not - immediately navigate the user to your Launcher Activity.
Please note: It would be good UX to save back stack and navigate back to the current activity as soon as your logic on Launcher Activity is done working.
Can anybody confirm the following regarding the android application lifecycle?
1) When application is in foreground the memory will contain instance of the Application object, instances of all activities (not killed) and all the object references that are referenced from one of the root's (haven't been garbage collected)
2) When application goes to background, at some point the Android Framework can:
a) Kill the whole process given to the purpose of the application which will essentialy erase all the objects from the memory
b) Kill ONLY (so essentialy no other object reference will be deleted) the activities (by finishing them and in essence any fragments as well) saving their states and creating the Activities Stack and leaving anything else (Application object, any other static objects, references that are reachable from any of the roots).
I'm mostly interested in 2b, but I would appriciate confirmation on all of these points as I'm trying to grasp mentaly the whole concept from start to finish.
If you are looking for official confirmation then better ask Google only :).
but i feel after reading this you will get a better understanding of these concept.
Android memory management
android process lifecycle
Answer for 1st question:
yes confirm using DDMS.
answer for 2a question: yes OS can kill process any point of time when needed memory for other process which will result into killing all object related to process.
answer for 2b questiong:
From official documentation
Process Lifecycle 3. A background activity (an activity that is not visible to the user and has been paused) is no longer critical, so the system may safely kill its process to reclaim memory for other foreground or visible processes. If its process needs to be killed, when the user navigates back to the activity (making it visible on the screen again), its onCreate(Bundle) method will be called with the savedInstanceState it had previously supplied in onSaveInstanceState(Bundle) so that it can restart itself in the same state as the user last left it.
Yes you are mostly correct about 2b).
If an activity is paused or stopped, the system can drop the activity
from memory by either asking it to finish, or simply killing its
process.
However there are instances where onSaveInstantSate isn't called:
Note that it is important to save persistent data in onPause() instead
of onSaveInstanceState(Bundle) because the latter is not part of the
lifecycle callbacks, so will not be called in every situation as
described in its documentation.
Android Docs Source
You can request android to always destroy activities on background by enabling the following developer option. If you are debugging your app you should be able to step through the life cycle methods and see what is happening.
Settings -> Developer options -> Apps -> Don't keep activities
There is no typical life-cycle for application exists. Application object lives in memory until it is not being killed either by Android itself or by manually by user.
For the above points, here are your answers:
1) This is true.
2) a) That is also true.
2) b) When application goes background, you can only save the data of the current activity that was in foreground. Also, when you kill the application it self (by removing it from recent list), all the activities in the app stack and their saved data (not persistent data) got killed as application is the base for all the activities.
1) When application is in foreground the memory will contain instance
of the Application object, instances of all activities (not killed)
and all the object references that are referenced from one of the
root's (haven't been garbage collected)
> There will only ever be a few such processes in the system, and these
> will only be killed as a last resort if memory is so low that not even
> these processes can continue to run. Generally, at this point, the
> device has reached a memory paging state, so this action is required
> in order to keep the user interface responsive.
2) When application goes to background, at some point the Android
Framework can:
.
a) Kill the whole process given to the purpose of the application
which will essentialy erase all the objects from the memory
> These processes have no direct impact on the user experience. Provided
> they implement their Activity life-cycle correctly (see Activity for
> more details), the system can kill such processes at any time to
> reclaim memory for one of the three previous processes types. Usually
> there are many of these processes running, so they are kept in an LRU
> list to ensure the process that was most recently seen by the user is
> the last to be killed when running low on memory.
b) Kill ONLY (so essentialy no other object reference will be deleted)
the activities (by finishing them and in essence any fragments as
well) saving their states and creating the Activities Stack and
leaving anything else (Application object, any other static objects,
references that are reachable from any of the roots).
Partially as in point 2.a.'s explanation
> Usually there are many of these processes running, so they are kept in an LRU
> list to ensure the process that was most recently seen by the user is
> the last to be killed when running low on memory.
Source - developer.android.com
Well this thing depends upon how Android OS operates. Android Device is an embedded System but works almost same as a PC and when I say Android as an OS, it will definetely have all the features of an OS. The thing which you are pointing upon is the Memory Management and Scheduling feature of Android OS.
MMU(Memory Management Unit) logically give preference to currently executing task i.e ur launcher or any other Application which u r working upon. Two things I want to answer which can help u bit more:
Views (whether xml generated or Javacode generated, they are dynamically generated.).
Android OS runs all apps as a process with sub processes(Activities) on a Dalvik Virtual Machine.
All your Activities before they are created they are null, when they are created then their instance is generated. Upon opening them again their saved instance is again viewd(Concept of Singleton Design Pattern).
So let me tell you that I don't think that both of the options are right. What I beleive is following:
1. View will always be generated dynamically.
2. Instance will be saved in Memory.
3. On background going of Application the whole process with instances available will be their in Memory.
Ok, during my search quest in recent weeks I was able to get some more information and now I can answer my own (and hopefully for others) questions:
1) Correct
2a) Correct
2b) False. The android framework, if in need of memory or if due to some other reason it has to "kill/reduce" the application it can do so only by killing the whole process that is dedicated to that application. The android framework can neighter kill chosen activity(ies) or kill all activities but leave all other objects alive (like Application object, singletons etc.)
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 face the following very annoying problem:
I'm using the Google Compatibility Library in order to future-proof my apps.
Now... I'm keeping track of my backstack:
1) Launch App.
2) User Interaction A -> Fragment gets added to UI/ Back Stack.
--- Backstack Size: 1 ---
3) User "backgrounds" the app.
4) User kills the App with a Taskkiller / or the app gets killed by the android system
5) Launch app again. Full Restart of the application (Application.onCreate()) presented to the User.
6) User Interaction A -> Fragment gets added to UI/ Back Stack.
--- Backstack Size: 2 ---
At this point I would want to have a backstack size of 1.
If the user presses back now, the app takes him back to some former state, which doesn't make sense anymore, because the app presented a fresh start.
Any Idea on How to do this??
Thx
Although your application has indeed been killed, there is not technically a 'full restart' when you try to launch it again. This is certainly not the way Android would want you to consider the situation.
When you background your app, Android will save the state of the fragments that have been added to the fragment manager (as well as the state of which activities are open, and their view state). When you relaunch your app after getting killed, Android will give you back all of this state and so you should be able to resume from exactly where you left off. This means you should consider that 'User Interaction A' has already happened and really you are at step 2) again. As you have noticed, the backstack is preserved; this is because the fragment transactions you have performed are also preserved.
The problem is of course, that we don't always write our apps in a way to match this behaviour. If your app presents a 'fresh start' after being killed whilst backgrounded, then arguably it is not really following the Android approach (assuming there is some user state worth saving).
I think you should try as best you can to resume as at step 2); it will likely be (marginally!) easier than trying to prevent Android from saving this state.