In my next app version I need to have a boolean flag enableNotification. So in order everything works fine in my app after user launches my app in MainActivity it sets this flag to false and I saves it to SharedPreferences. If it doesn't go to MainActivity and sets this flag to Shared my app will work wrong.
So my question is whether after user upgrades his app on Google Play to the newer version (the old version doesn't have this flag in SharedPref), will it go first to MainActivity and not to the Activity the user was before (SecondActivity, ThirdActivity...)? Or it's better to save this flag to the DB, so in onCreate() set this flag to false?
Updating an App on Android force closes it.
So the next time the user opens the app, it will start the Activity that you declared with the ACTION_MAIN Intent Filter in the Android Manifest (probably MainActivity)
If your app depends on the SharedPreference 'enableNotification' to works, then you need to do the checking in Application class first.
Initialize the value in Application class first if the app never have the value before. Do the checking in application onCreate() because Application class is called before Activity as the documentation says:
void onCreate ()
Called when the application is starting, before any activity, service,
or receiver objects (excluding content providers) have been created.
Implementations should be as quick as possible (for example using lazy
initialization of state) since the time spent in this function
directly impacts the performance of starting the first activity,
service, or receiver in a process. If you override this method, be
sure to call super.onCreate().
Related
Is it possible from the Application class onCreate method (not Activity!!) to identify how the app has been launched?, like if it was from the Launcher or Push Notification or a boot complete broadcast receiver etc'
Also, is there a way to get the Intent object (if exists) which caused the launch, from the Application onCreate?
Basically what I am interested is to recognize if it was from Launcher or not and get the Intent if exists. All this, in the Application class, and not Activity.
First of all, I don't believe it's possible to check whether the app has been launched by the launcher directly, but rather with a process of elimination.
Technically there is a way to get the Intent, which was used to launch the App in the Application's onCreate.
Since you can use Intent to start Activities, not Applications, you can use registerActivityLifecycleCallbacks to register an onActivityCreated callback in your App's onCreate, which gives you access to the created activity.
Once you have the activity object, you can call activity.getIntent() to get the Intent object.
The onActivityCreated callback also gives you a savedInstanceState Bundle, which you can utilize to determine, whether the App was already running before or not.
Some background on a problem that I have been encountering: in my app I have a singleton object that I use regularly to access things like id and token for network calls. Sometimes when the app is killed in the background, this singleton loses its state. However, when the app is opened again and starts up in some Activity past the launcher Activity, the singleton is null.
I am in the process of refactoring this, but have been agonizing over how to ensure that the singleton will always be present even in app restart, but I'm not sure what Android does when the app restarts from being backgrounded.
I went through source code in some of the libraries we use in the app (Facebook, Intercom) to see how they manage their singletons and why their static variables seemed to just always be present, and came upon a theory.
So on a normal app cold start, the app behaves like this:
Application.onCreate() -> Launcher.onCreate() -> Activity A -> Activity B
Say the user was in Activity B and backgrounds the app. After using some other apps, they come back to my app but it has been killed at some point in between. The lifecycle then becomes this:
Application.onCreate() -> Activity B
I think the problem is that I initialize the singleton in the launcher Activity, and as a result, when B tries to get a value from the singleton, it comes up null. If I initialize the singleton in Application.onCreate(), it will always be initialized when the app is pulled up again. Is this correct?
TL;DR An application that is killed and brought to foreground again will always call its Application.onCreate() and then forward directly to the Activity it was on. Therefore, app initializations that are critical to the app functioning should live in the Application onCreate().
A application that is killed and brought to foreground again will always call its Application.onCreate() and then forward directly to the activity it was on. Therefore, app initializations that are critical to the app functioning should live in the Application onCreate().
Correct.
I think the problem is that I initialize the singleton in the LauncherActivity, and as a result, when B tries to get a value from the singleton, it comes up null. If I initialize the Singleton in Application.onCreate(), it will always be initialized when the app is pulled up again. Is this correct?
In your case the problem is really in that. However, if by "it comes up null" you mean the singleton instance is null then it is not how a singleton is supposed to work. No matter where you call singleton's methods from, its instance should not be null.
Yes, the Application.onCreate() is called always when the app comes to foreground, so every Singleton that you need to initialize must be there.
In Windows Phone, there is Application.LoadCompleted Event for detecting the finish of starting an application.
Note the finish means that users are able to interact with the app.
Is there similar API on Android? Any other approaches to achieve this?
after onResume() gets called it means the user can start interacting with your app. Consult this document for more information
You can override onCreate method of main Activity.
It depends what you mean by 'finished starting'. Activities, including the main activity, can be created and destroyed - and therefore onCreate() called - multiple times, for example (in the default behaviour) when the device orientation changes. onResume will be called even more often, for example every time the activity comes to the foreground. Then there's onStart(). See the Android developer docs to see when in the lifecycle each is invoked. It's true that the first time onResume() is called on the main activity will be when the app is fully started, but you won't know it's the first time without storing state somewhere outside any activity, for example on a singleton, or by subclassing the Application class, which is not something especially encouraged, as far as I can tell.
Scenario:
I've four activities in my Android Application, lets say A, B, C and D. There is one Constants.java class in the app which extends Application class in order to maintain global application state. The Constants class have all the constants variables of the app. The activity flow is like this A-->B-->C-->D. When back button is being pressed from Activity A, I'm calling finish() method which will finishes the activity A and closes the application. After that if I'm opening the app from all apps, there is a variable in Constants.java whose value persists from the last launch. The same thing is not happening when I'm doing System.exit(10) followed by Process.killProcess(Process.myPid()) from activity A(on back pressed).
Questions:
Will finishing all activities by calling finish() of each activity will close the Application(Its process)?
How the value of a variable persists even if its all activities are finished(closed)?
Is it fair to call System.exit(10) followed by Process.killProcess(Process.myPid()) for exiting the application?
Update:
How can I clear the application constants on exit of the application(Back press of the HomeActivity)?
1) No, Android does not guarantee so. It's up to the OS to decide whether to terminate the process or not.
2) Because the Activity instance still lives in the Dalvik VM. In Android each process has a separate Dalvik VM.
Each process has its own virtual machine (VM), so an application's
code runs in isolation from other applications.
When you call finish() this doesn't mean the Activity instance is garbage collected. You're telling Android you want to close the Activity (do not show it anymore). It will still be present until Android decides to kill the process (and thus terminate the DVM) or the instance is garbage-collected.
Android starts the process when any of the application's components
need to be executed, then shuts down the process when it's no longer
needed or when the system must recover memory for other applications.
3) I wouldn't do so unless you have some very strong reason. As a rule of thumb, you should let Android handle when to kill your application, unless there's something in your application state that requires an application reset when it loses focus.
Quotes source
Will finishing all activities by calling finish() of each activity will close the Application(Its process)?
No, it should not. This is because Activities are not the only component of an app. Services, BroadcastReceivers can still run without a UI. By keeping the Application process running while it can, Android ensures faster response to the user opening the app again, or faster launching of Services etc. as the Application instance doesn't need to be recreated.
Your process will only be terminated if you or another app explicitly kill it, or the system kills it to free resources.
How the value of a variable persists even if its all activities are finished(closed)?
Your variable is in the Application class, which follows a Singleton model, and hence your value will persist until the entire app process is killed.
Additionally, finish() only calls onDestroy(), which is not a deconstructor, as explained here. So even Activity variables may persist after finish has been called, as your instance is still kept around until Android feels the need to destroy it, or your process is killed.
Is it fair to call System.exit(10) followed by Process.killProcess(Process.myPid()) for exiting the application?
While this will kill the app, it is not recommended. See this question for a variety of reasons for that.
for your Update:
How can I clear the application constants on exit of the application(Back press of the HomeActivity)?
Override onBackPressed inside your HomeActivity and before call super.onBackPressed() clear all the variable. If you have a setter for a String located inside your Application subclass:
#Override
public void onBackPressed() {
getApplication().setMyString(null);
super.onBackPressed();
}
if you have plenty states to clear you can write a method wich reset all the fields and call it:
#Override
public void onBackPressed() {
getApplication().clearAllMyFields();
super.onBackPressed();
}
Of course those field have not to be marked as final or static final
Android will keep the process until it needs to reclaim the process memory. That way, if the user immediately returns to your application, your application will appear quicker.
The value will persist until the application is killed.
Should not using System.exit(10) followed by Process.killProcess(Process.myPid()) for exiting the application?
You should really think about not exiting the application. This is not how Android apps usually work.
The android app I am working on overrides the Application class to store lightweight state (username, gps location, etc) in static vars. Most of this state is set in OnCreate of the launch activity (username retrieved from prefs, location listener runs). Is it safe to rely on the launch activity to initialize the Application class? Are there any cases where the Application class might be re-created without the Launch activity also being created?
The question comes up because I ran into a null pointer exception accessing a variable in the Application class on resuming the app after the phone was asleep for several hours (the app was left in the foreground before phone went to sleep). Is it possible that the process was killed while the phone was asleep and on waking the phone, the Application class was re-created, the top activity in the stack was resumed, but the launch activity.onCreate wasn't run thus the Application class wasn't initialized?
Note that I have tried to test these kinds of scenarios by Forcing the App to stop using Settings / Manage applications. However, I'm not able to recreate the problem. On the next run, the Application class is created, followed by the launch activity.onCreate.
Is it safe to assume that the Application class instance will exist as long as the process, and that when the Application class is created it is equivalent to "restarting" the application ie. start with a new activity stack (and first activity on stack is the launch activity)?
No. Your entire application can be killed and recreated with the task stack intact; this lets the system reclaim memory on devices that need it while still presenting a seamless illusion of multitasking to the end user. From the docs:
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.
That is, the process (which the Application is tied to) can be killed off but then restarted, and the individual activities should have enough info to recreate themselves from what they've saved before being killed, without relying on global state set in the process by other Activities.
Consider storing persistent shared state that needs initialization by an Activity in either a SharedPreference or SQLite database, or passing it to Activities that need it as an Intent extra.
You can test the scenario by killing the process of your running application.
Step 1. Open your app, and then press Home button to hide it into background.
Step 2. Invoke adb shell
Step 3. Enter command su (you have to get ROOT permission in order to kill process)
Step 4. ps (list all running process ID and find yours)
Step 5. kill 1234 (assume your application running on process 1234)
Step 6. Then, go back to your device and click the launch icon again. You may find the last activity on activity stack is reopen. You may also find onRestoreInstanceState() method is called for the activity.
In short: do initilization in YourApplication.onCreate, not some LaunchActivity
Docs to check:
- Processes and Threads
- API Guides > Activities
Is it safe to rely on the launch activity to initialize the Application class?
Yes, as long as you remember that Application can exist longer that Activity and the Activity may be killed and recreated. I am not sure what Intent will resurrected Activity get: LAUNCH or VIEW
(For scenario when activity was killed as too heavy, while there was long running service binded to app )
Are there any cases where the Application class might be re-created without the Launch activity also being created?
yes, if the last visible activity was not LaunchActivity
check Android application lifecycle and using of static
Is it possible that the process was killed while the phone was asleep and on waking the phone, the Application class was re-created, the top activity in the stack was resumed, but the launch activity.onCreate wasn't run thus the Application class wasn't initialized?
If there were several different Activities launched A, B, C and them whole process killed, then I think Android OS is good with only creating Application and C activity, while A and B would be re-creted on access, that is on returning to them.
Is it safe to assume that the Application class instance will exist as long as the process,
yes
and that when the Application class is created it is equivalent to "restarting" the application ie. start with a new activity stack (and first activity on stack is the launch activity)?
I not sure when restarting the launch activity would be called first,
but the last, i.e. the one that user should see.
"I ran into a null pointer exception accessing a variable in the Application class on resuming the app"
Check this link..
http://www.developerphil.com/dont-store-data-in-the-application-object/