I have a very important initialization to do when the app starts. I found the best way to do is to put that code inside onCreate() of the class which extends Application class.
class ApplicationDemo extends Application{
#Override
public void onCreate(){
super.onCreate();
Log.d("LOG", "Inside onCreate()");
}
}
The Problem
I do not find the log statement to be executed every time the app is run. Like I start the app for the first time, get the log statement, then close the app and start again from the launcher. No, the log statement doesn't come.
What is the problem? How can I ensure a particular code is run every time my app is run and before anything else is performed?
My guess is that you truly have open your application just once.
I'm pretty sure that, after you closed your application, it truly just goes into the background, waiting to be put in the foreground again. (It does not get created again, you only reuse something you already have created.)
Try making sure you actually killed the process of your application before re-opening it; to make sure you actually closed & reopen it, and not just do a simple background-foreground thingy.
This sounds like an Android activity lifecycle problem.
I've included a link about pausing and resuming an activity
http://developer.android.com/training/basics/activity-lifecycle/pausing.html
It looks like when you are exiting the app, your activity is being paused. Likewise when you re enter the app, if the process is still running, the activity is getting resumed rather than recreated.
From here, you can either move the code to the onResume() or you can leave it in onCreate() but make sure that exiting the app kills the process. that could be done by putting
getActivity().finish();
System.exit(0);
in any path that directs the user to the home screen (onBackPressed(), exit buttons, etc.)
for starting, try putting a Log statement in onResume and watch where the two get called.
I hope this helps.
In Android you usually do not 'close' an application, but rather suspend it.
So, when you run it again, it just pops back.
To ensure your app is closed, open the list of running application, find your one and force stop it.
An application or an activity can exist even if it's UI is not displaying. The onCreate() callback is only called when the object is created anew.
This simply means that "every time an user opens the app from the launcher icon".
Then you should be putting the code in the onResume() callback of your launcher activity declared in the manifest. You can make the launcher activity a thin activity that only does this once-per-activation init and then launches the actual main activity.
Sure, there can be prior code run, such as onCreate() of the Application and onCreate() of the Activity so it won't always be the first thing to run, but it will be guaranteed to run every time you launch from the menu.
You can use from bellow code for Kotlin:
override fun onTrimMemory(level: Int) {
super.onTrimMemory(level)
when (level) {
ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN -> {
/*
Release any UI objects that currently hold memory.
"release your UI resources" is actually about things like caches.
You usually don't have to worry about managing views or UI components because the OS
already does that, and that's why there are all those callbacks for creating, starting,
pausing, stopping and destroying an activity.
The user interface has moved to the background.
*/
System.exit(0);
}
ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE,
ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW,
ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL -> {
/*
Release any memory that your app doesn't need to run.
The device is running low on memory while the app is running.
The event raised indicates the severity of the memory-related event.
If the event is TRIM_MEMORY_RUNNING_CRITICAL, then the system will
begin killing background processes.
*/
}
ComponentCallbacks2.TRIM_MEMORY_BACKGROUND,
ComponentCallbacks2.TRIM_MEMORY_MODERATE,
ComponentCallbacks2.TRIM_MEMORY_COMPLETE -> {
/*
Release as much memory as the process can.
The app is on the LRU list and the system is running low on memory.
The event raised indicates where the app sits within the LRU list.
If the event is TRIM_MEMORY_COMPLETE, the process will be one of
the first to be terminated.
*/
}
}
}
And bellow code for Java:
public void onTrimMemory(int level) {
// Determine which lifecycle or system event was raised.
switch (level) {
case ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN:
/*
Release any UI objects that currently hold memory.
"release your UI resources" is actually about things like caches.
You usually don't have to worry about managing views or UI components because the OS
already does that, and that's why there are all those callbacks for creating, starting,
pausing, stopping and destroying an activity.
The user interface has moved to the background.
*/
System.exit(0);
break;
case ComponentCallbacks2.TRIM_MEMORY_RUNNING_MODERATE:
case ComponentCallbacks2.TRIM_MEMORY_RUNNING_LOW:
case ComponentCallbacks2.TRIM_MEMORY_RUNNING_CRITICAL:
/*
Release any memory that your app doesn't need to run.
The device is running low on memory while the app is running.
The event raised indicates the severity of the memory-related event.
If the event is TRIM_MEMORY_RUNNING_CRITICAL, then the system will
begin killing background processes.
*/
break;
case ComponentCallbacks2.TRIM_MEMORY_BACKGROUND:
case ComponentCallbacks2.TRIM_MEMORY_MODERATE:
case ComponentCallbacks2.TRIM_MEMORY_COMPLETE:
/*
Release as much memory as the process can.
The app is on the LRU list and the system is running low on memory.
The event raised indicates where the app sits within the LRU list.
If the event is TRIM_MEMORY_COMPLETE, the process will be one of
the first to be terminated.
*/
break;
default:
/*
Release any non-critical data structures.
The app received an unrecognized memory level value
from the system. Treat this as a generic low-memory message.
*/
break;
}
}
On my phone even if I close an app it'll keep running in the background until you close from there manually.
You can use
onResume() {}
To run something every time the Activity gets called again.
You should in AndroidManifest.xml in tag "application" set field android:name=".ApplicationDemo"
UPD
author edited question with my assertions.
Related
I understand the basic Lifecycle of Activity/Fragment but sometimes, when user puts the app in background state for long time I'm not sure what's going to happen when he opens it again. Recently I've encountered a bug: User gets nullpointer exception by calling method of a view saved in class variable (textView = findViewById(...)), inside fragment's OnResume method. The variable is set in OnViewCreated(). Is that possible that over long period of time fragment might lose it's fields due to lack of memory? When onResume() will be called and when onCreate()?
If the app is in background for a long time its process will be killed by OS, or if the device is running low memory. To test how your app works under these conditions use flag "Do not keep activities" in Developer options on your device. In the described case onCreate will be called when Activity will come to the foreground.
If the process is not yet killed then onResume will be triggered. Normal variables persist, but the problem is that you can never be sure when you're calling onResume and when you're calling onCreate (since you have no control over when Android just goes and tosses stuff on the stack out the window... anything not currently being used is eligible for destruction).
So my solution is to add a null check with if condition: if the variable is null then initialize and perform actions, if not then just preform actions.
I have the following piece of code in Activity
// Cache object is holding other resources like thread handle, file handle.
// Explicit clean up is required when it is no longer used.
public static Cache cache = new Cache();
#Override
public void onPause() {
super.onPause();
if (this.isFinishing()) {
cache.cleanUp();
}
}
Note that, I need to have isFinishing check, as having phone rotation, home press, launching new activity... will trigger onPause as well. So, having the cleanup cache due to such "simple" operation defeat the purpose of having Cache object.
However, there is a possibility of resource leakage in my design.
Run the app
Press Home
Run other memory intensive app by running them, pressing Home, running the others again.
At some point, system discovers it should remove my app as it is not activated for quite some time. Hence, cache will become null. However, I have no chance to call cache.cleanUp
Long press on Home button. My app should still appear in the list.
Select it. The activity will onCreate again, and 2nd instance of static cache will be created again.
In such case, we are having resource leak, as the previous allocated old thread handles, file handles owned by 1st cache object, are still in the system. We have no way to deal-locate them, because the 1st cache object is destroyed by the system.
I wish there is a callback by system, whenever the system decide to destroy my app due to home pressed. With such callback, I can perform necessary clean up call on my static objects, before they are being destroyed.
May I know how I can achieve so?
In such case, we are having resource leak, as the previous allocated
old thread handles, file handles owned by 1st cache object, are still
in the system
GC will take care of it. Thats the reason your app is killed. So that such memory gets cleaned up and used by other apps.
if(cache!=null) {
cache.cleanUp();
}
It is better you assume the logic that "I will do this and this only if cache is not null".
There is no callback method for Home key press. If you want to destroy your apps on Home key press, better set a static variable on back key press(onKeyUp and if keycode==back_key). and onPause method, if that variable is not set then destroy that activity (finish();).
Long press on Home button. My app should still appear in the list.On :: that list for recent activity its not depend on killing your activity etc...
I am creating a simple application that entails multiple activities. It is necessary for my application to resume one of two activities based on a certain system preference. Because of this, I have implemented a Dispatcher class that is linked to action.MAIN, that then starts the correct Activity by examining the system preferences within its onResume() callback.
The Problem
Since I am doing this in onResume(), when the back button is pressed on any of the resulting activities, the Dispatcher is resumed, and as a result it again tries to start the same Activity again. This prevents the user from ever leaving the application unless they press the home button.
Some Code
Here is some code excerpts from my classes to help clarify my situation:
Dispatcher.onResume(void) : void
protected void onResume() {
super.onResume();
if(!handled){
Intent activity_switcher;
//If a game is active...
if(manager.isGameActive()){
//Start the the Game Manager with the appropriate game.
activity_switcher = new Intent(this, GameManager.class);
}
//If a game is not active...
else{
//Start the Game Menu
activity_switcher = new Intent(this, Menu.class);
}
//Start the appropriate activity
startActivity(activity_switcher);
overridePendingTransition(0, 0);
}
else{
//Finish the application
finish();
overridePendingTransition(0, 0);
}
}
Some of the variables are as follows:
manager is the variable representing my class that interfaces with the system preferences.
handled is the variable that determines if the event has been handled yet (see "Attempted Solution #1" below)
Attempted Solution #1
I have considered implementing a boolean class variable, handled, that is tested before the activities are started. If the value is found to be true, then the Dispatcher simple makes a call to finish(), however if the value is false, then the appropriate activity is started and handled is set to true so that when the application returns to this Activity, it will simply finish.
This will not work, because...
If the user pressed the home button on one of the resulting activities, then when they resume the application, they will be placed on the dispatcher activity, and the application will immediately finish because it thinks that it was handled (the variable is still true).
Attempted Solution #2
I tried to find some way to only run to the Dispatcher once per application life cycle. This makes sense because the user would never want to return to the Dispatcher as it is an Activity that should only be ran once at launch time. So, I included a counter that would be incremented each time onResume() was called, and reduced to 0 each time finish() was called.
This will not work, because...
Again, if the user presses the home button, then when the application is re-launched, the Dispatcher will think that it has already been run once (because there was no call to finish()), and will immediately finish again.
Attempted Solution #3
I figured that if I could somehow determine which activity was previously active, then I could dynamically react to the case where the user pressed the back button, and then and only then inform the Dispatcher that it should finish, then there would be no immediate finishes in the case when the user presses the home button.
This was accomplished by using a static function returningFromMenu() that, when called from the menu Activity, raised a flag in the Dispatcher class that informed the it to finish.
Attempted Solution #4 (Current Implementation)
Simply moving all of this activity switching code into onCreate(). This would enforce the "one time" nature of the Dispatcher.
This might work, because...
This will handle the case where the user returns to the activity (using onResume()), and, since there will be no flags, there is no issue when returning to the application after pressing the home button.
My Question
Is there any way to determine which Activity was last finished, other than having to use a static method or member? I know that this is a very bad practice and would like to avoid it if possible.
Updates
Last Updated: 12 Feb 2013 3:45PM EST
Approach #4 seems to be working for my purposes, however I still think that the question here could be of great use to developers, and will refrain from answering my question until I have given enough time for a more holistic solution to be posted.
The Solution
As is stated in "Updates" above, this problem was solved by simply moving the code into onCreate() so that the switch was made only once. Equivalently, I could have simply made a call to finish() immediately after starting the activity in order to remove the calling activity from the back stack.
Thank you all for your efforts in the comment section!
If Java provides Garbage Collection, then what is the need of onDestroy() in Activity Lifecycle?
onDestroy: The final call you receive before your activity is destroyed. This can happen either because the activity is finishing (someone called finish() on it), or because the system is temporarily destroying this instance of the activity to save space.
Here is an example......
public void onDestroy() {
super.onDestroy();
}
OS decides when things "go away." The onDestroy is there to let your app have a final chance to clean things up before the activity does get destroyed but it does not mean that the activity will, in fact, be GCed. Here is a good article that I recommend people to read that relates to creating an exit button. While it's not exactly what you asked about, the concepts will help you understand what's going on.
You can use onDestroy() to finalise the program. I have used it in the code bellow to tell the server that the client is closing its socket to the server so I can notify the user on the server end that the client has disconnected.
client:
...
protected void onDestroy(){
super.onDestroy();
if(connected) {
clientMessage.println("exit");
clientMessage.close();
try {
socket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
finish();
}
...
server:
...
while (connected) {
input = clientMessage.readLine();
if ("exit".equals(input)){
break;
}
...
}
...
onDestroy() is a method called by the framework when your activity is closing down. It is called to allow your activity to do any shut-down operations it may wish to do. The method doesn't really have anything to do with garbage collection (although your shut-down operations—if any—might involve releasing additional resources that can be gc'ed). In particular, it has nothing to do with C++ destuctors (despite its name).
If you have no shut-down operations to do, you don't need to override it. The base class does essentially nothing.
onDestroy may be called when an activity is destroyed, but you can not count on it. There are situations where the system will simply kill the activity's hosting process without calling this method (or any others) in it, so it should not be used to do things that are intended to remain around after the process goes away.
See: http://developer.android.com/reference/android/app/Activity.html#onDestroy()
In the Android Activity Lifecycle's onDestroy docs:
onDestroy() is called before the activity is destroyed. The system
invokes this callback either because:
the activity is finishing (due to the user completely dismissing the activity or due to finish() being called on the activity), or the
system is temporarily destroying the activity due to a configuration change (such as device rotation or multi-window mode)
The Activity#onDestroy() API docs also answers it quite well:
This method is usually implemented to free resources like threads that are associated with an activity, so that a destroyed activity does not leave such things around while the rest of its application is still running. source
As the quote from the docs say, its for preventing a destroyed activity leaving things around (e.g. memory leaks through referencing, threads), but only when the rest of the app still runs. If the application process ends, it doesn't matter if you forget to clean up threads or other resources since the OS will do it for you. You don't need to override onDestroy.
There is no need to do what sam786 is doing (overriding and just calling the super method) as that is absolutely useless. All other answers seem to go along the lines of "clean up", but don't explain what kind of clean-up or when. You should not be saving any data in onDestroy(), as you can't guarantee it will be called, so you will lose data sometimes. It won't be called when you press the home button, for example (the case where you want data to be saved).
The onDestroy is there to let your app have a final chance to clean things up before the activity does get destroyed
Article Exit Button in Android
It gives your program a chance to do things like cleanup resources (say threads) so that they don't pollute the associated application. If you don't have any use for it, then don't override it.
See:onDestroy()-Android Reference
I start my Android app, which in turns initializes some state on the first screen. The app has a many screens, and after randomly navigating through some screens, I minimize the app using the "Home key". Now after running some other apps from the phone, the OS decides that it needs to free up my app and hence kills it.
Now when I again click on the app icon, the OS remembers the history and tries to go back to the screen from where I minimized the app. But, the problem is since the OS purged my app sometime back, all my states are lost and the screen may not have any relevance.
How do I tackle this? How do I ensure that the OS calls the launcher screen, if it has been purged before and not the Activity in the history?
From your above comment about singleton class being initialized I also faced situations similar to you. Since I could not avoid it, what I did was I used the Application class. Whenever the OS decides to purge your app, the next time you launch the app, onCreate on the Application class will be called. Override the onCreate method to initialize the singleton class rather than doing the same in the launcher screen
The code snippet is as follows
public class CellApplication extends Application {
#Override
public void onCreate() {
super.onCreate();
// Do your singleton class initialization here
}
}
You don't make sure the OS calls the launcher screen. The best way to solve this problem ist to save the state of your screens.
Everytime one of your activities is put in background onSaveInstanceState is called. This allows you to save the state of your app to the bundle that is provided in this method. If your app resumes onCreate will be called with the exact same bundle. You can now rebuild the app the same state the user left it.
Just check if the the bundle in onCreate is null. If it is null your activity is new if not rebuild the state from the bundle.