I have a simple game object (the main UI object) with OnApplicationPause that prints out the Pause status (true/false) in the debug log.
When I run it on android, and press the Home Button to leave the app, I see that the OnApplicationPause() is called twice in a row, with the same pauseStatus (true). The same happens when I reopen the app: the OnApplicationPause is called twice with Pause status false.
Why is it being called twice and can I avoid it? Am I doing anything wrong?
I also tried to create a separate GameObject, that includes the same debug code. The issue doesn't occur there - only in my main UI object.
Are you 100% sure that your script containing the OnApplicationPause() method is not present twice in the Scene when Pause occurs? or present on a previous Scene on a DontDestroyOnLoad GameObject?
OnApplicationPause is called on each active MonoBehaviour when pause occurs.
So having two Debug.Log means two scripts instances running if you don't call it manually yourself.
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 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.
I am using a WebView in my app's sole Activity. Whenever the user clicks on the BACK button, I override the onKey and process some clean up before calling finish of the activity.
I see that once in a while (maybe 1 out of 20 times), onDestroy is not called. And in this case, if I launch my app again, a blank screen comes up. The Activity's onCreate is not called, and neither is my overridden Application's onCreate.
Does anyone know why this happens, and are there any possible solutions?
Thanks,
Rajath
Based on the little less than a line of code you have provided, please do the following:
Stop overriding back key.
Do the cleanup elsewhere, e.g., in onPause().
It turns out that I was capturing uncaught exceptions using the UncaughtExceptionHandler(). So, sometimes when the app was actually crashing in onDestroy(), the subsequent session was not properly launched.
Of course, in the case where the app's onDestroy() was not called at all, the problem is still fixed when I don't use UncaughtExceptionHandler(). Not sure why though.
-Rajath
I don't know where to put my Debug.stopMethodTracing();
What is the last function that gets called before activity is destroyed (while running LibGDX)?
Edit: I tried to put it in overriden method onDestroy() from AndroidApplication, but it didn't seem to get called whenever i pressed home button or killed the activity in eclipse.
Thanks
The libGDX ApplicationListener has pause and dispose callbacks that will be invoked on the exit path. The pause is called when exiting (not just a suspend/resume), so its where I persist the state of my game.
See http://code.google.com/p/libgdx/wiki/ApplicationLifeCycle
My question is can i get to know when the entire application gets paused/resumed start/stop etc.
For example if i have 5 activities in my application. Whenever any activity gets paused/resumed android notify the activity by calling the onPause/onResume methods.
So there are two possible scenarios when my activity gets paused.
1. My activity-2 gets paused because my activity-3 gets invoked.
2. My activity-2 gets paused because of some outside activity like incoming call.
Here I am interested only tracking when my activity gets paused by outside activities not my own application activities.
So is there any android provided solution for this or do I have to write my customized solution.
Thanks
Dalvin
There is no solution provided by the API because it is not needed in most cases.
What you can do is to create an abstract activity and make all your activities inheriting from this abstract one.
In this abstract activity, by overriding onCreate, onResume, onPause, onDestroy, you can manage to count how many of your own activities are "alive", and then determine the state of your application.
This could work but it's not really the Android phylosophy
You can know the starting of the whole application on application.oncreate() but there is no indicator for the whole application pause. Most of the cases never needs it anyway.
So further read in the activity lifecycle and the application class.
Still you can do this option in your program by overriding the onPause in each class and save a value to the sharedPrefrences then check on this value all over the application
If I understand your question, you want your app to be able to distinguish between exiting the current activity within the context of your program or by an external event like a phone call. I have used the following method in the past to do this (although it may not be the best, it definitely works):
(1) Set up a value in SharedPreferences (the built in file for storing a program's data). Call it something like "exitStatus" which is set to 1 for an exit within the program code and 0 for an exit based on external events.
(2) Now, within each of your activities, set the value of exitStatus to 0 in onResume (which is called no matter how you enter). If your program exits due to an external event within that activity, this value will persist when the program is reloaded.
(3) At the end of your activity, at all points where you are going to transfer to another activity, first set exitStatus to 1. Then, when you arrive at the other activity, it will know that you arrived there from within your program.
(4) Thus, just to be clear, each of your activities can check exitStatus at the outset to see whether you are entering from within your program context (= 1) or after a non-local exit of some kind (= 0).
That's all there is to it. I use this method to be sure that load data for my app is present as it may be lost if a user turns off their device so that the app tries to pick up in the middle of things when they later reboot, etc.
Instead of making base activity and override onPause/onResume you can use
registerActivityLifecycleCallbacks(Application.ActivityLifecycleCallbacks callback)
where you can handle these states for application activities in one place.