Activity gets destroyed when PowerManager.goToSleep is called - android

I have an activity which sometimes gets destroyed by the system as a response to PowerManager.goToSleep(...) being called. The behavior is not consistent and I can't figure out the reason for this.
Here is the relevant code for my activity's onCreate which is the most relevant part of code:
protected void onCreate(Bundle bundle) {
super.onCreate(bundle);
requestWindowFeature(android.view.Window.FEATURE_NO_TITLE);
IntentFilter userprsentfilter = new IntentFilter(Intent.ACTION_USER_PRESENT);
mUserPresentReceiver = new UserPresentReceiver();
registerReceiver(mUserPresentReceiver,userprsentfilter);
Log.d(TAG, "created.");
}
protected void onDestroy() {
Log.d(TAG, "finished.");
}
Somewhere, on some distant service and sometimes by the activity itself,
PowerManager.goToSleep(SystemClock.uptimeMillis())
is called causing the activity the get destroyed.
Can anyone please shed some light on why the system will try to sometimes destroy an activity when PowerManager.goToSleep is called? Also, is there a way to make the sure or lower the chances of the activity getting destroyed by the system? I can say with certainty that resources are not scarce when this happens.

All Android apps are subject to being shut down at any time. This can happen when the app is backgrounded, when it is consuming too many system resources, or when the phone sleeps. You can't (and shouldn't try to) alter that behavior: it does this on purpose and for very good reasons.
If you have an operation that needs to continue running under these circumstances, you need to implement it as a Service. This will allow it to run even when the phone is sleeping.

Related

Restarting the app after process has been killed by the OS

Android kills the application's process when it is in the background and it needs more memory.
I've read a few articles about this. Some people recommend restarting the app when this happens. But none of the articles give me information on how to do something like that.
Is there a way to go back to the root activity after an application's process has been destroyed and the app goes back into the foreground? What would be the best way to do something like this?
The only solution i found that works for me is putting this code in a base class for activities to inherit:
private static boolean isFirstOnCreate = true;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(getLayoutResource());
if (isFirstOnCreate && savedInstanceState != null) {
startActivity(getPackageManager().getLaunchIntentForPackage(getPackageName()));
finishAffinity();
}
isFirstOnCreateInvocation = false;
See my answer to this similar question or this answer to a similar question.
Basically you want to set a static variable when your app is started, and in each Activity you need to check if that variable is still set. If it isn't, it means that Android has killed the OS process hosting your app and created a new one after the user returns to your app. You can detect this situation and then do whatever is appropriate. Usually, this means redirecting the user to the first Activity and reinitializing your application.

Should I start/stop service in onStart/onStop, or onCreate/onDestroy

Currently, I have service, which runs in separate process. Here is the code in main activity.
#Override
public void onStart() {
super.onStart();
// Start auto complete service.
autoCompleteServiceIntent = new Intent(AutoCompleteService.class.getName());
startService(autoCompleteServiceIntent);
bindService(autoCompleteServiceIntent, serviceConnection, 0);
}
#Override
public void onStop() {
super.onStop();
// Stop auto complete service.
unbindService(serviceConnection);
stopService(autoCompleteServiceIntent);
autoCompleteServiceIntent = null;
}
The service will have the following characteristics.
The service runs in separate process. The reason is that, it will load a large data into memory. Having the service to run in separate process, will allow us to have larger memory limit.
Once main activity dead, the service shall dead too.
I was wondering, should I start/stop service in onStart/onStop pairs? Or, shall I start/stop service in onCreate/onDestroy.
The good thing I can think of, when having the code in onStart/onStop pairs is that, I can release unused memory immediately, whenever the activity is invisible. Hence, free up large system resource. Note, onDestroy is not always being called immediately, even the activity has quit.
The bad thing is, if I press HOME and come back frequently, my service will perform memory loading/unloading frequently. This may cause my application performs considerable slower.
In your scenario you should stop the service onDestroy the reason been is that, its called when the activity is destroyed self, foreclosed or by system when it needs memory. So that will be a appropriate place to end the service.
Where else onStop will be even called when you move back and forth in your application or visit home. The reason onDestroy is not called on home press is the activity is not destroyed yet. Where as if you close activity pressing back it will call onDestroy.

Use of onDestroy( ) in Android

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

Detect whether application is quit by the OS because of low RAM

In the application I'm building, I need to detect the application quitting if and only if the application has been quit when its in the background because the OS is reclaiming memory.
From my own experimentation, the onDestroy is called on EVERY instance. I've tried checking for isFinishing but I'm not 100% sure which situations this isolates it to.
#Override
public void onDestroy()
{
super.onDestroy();
Log.i("V LIFECYCLE", "onDestroy");
if (!isFinishing())
{
// are we here because the OS shut it down because of low memory?
ApplicationPreferences pref = new ApplicationPreferences(this);
// set persistant flag so we know next time that the user
// initiated the kill either by a direct kill or device restart.
pref.setThePersistantFlag(true);
Log.i("DEBUG", "onDestroy - ensuring that the next launch will result in a log out..");
}
}
Can anyone shed light on my issue here? Thankyou.
Through trial and error I have worked out a solution that works perfectly for anyone thats interested. I have narrowed down the case when the application state is being resumed (onResume) in the case of the OS reclaiming memory.
public boolean wasJustCollectedByTheOS = false;
#Override
public void onSaveInstanceState(Bundle savedInstanceState)
{
super.onSaveInstanceState(savedInstanceState);
// this flag will only be present as long as the task isn't physically killed
// and/or the phone is not restarted.
savedInstanceState.putLong("semiPersistantFlag", 2L);
}
#Override
public void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
long semiPersistantFlag = savedInstanceState.getLong("semiPersistantFlag");
if (semiPersistantFlag == 2L)
{
savedInstanceState.putLong("semiPersistantFlag", 0L);
this.wasJustCollectedByTheOS = true;
}
}
// this gets called immediately after onRestoreInstanceState
#Override
public void onResume() {
if (this.wasJustCollectedByTheOS){
this.wasJustCollectedByTheOS = false;
// here is the case when the resume is after an OS memory collection
}
}
I don't know whether its help you or not,
From Android Activity class,
public void onLowMemory ()
This is called when the overall system is running low on memory, and would like actively running process to try to tighten their belt. While the exact point at which this will be called is not defined, generally it will happen around the time all background process have been killed, that is before reaching the point of killing processes hosting service and foreground UI that we would like to avoid killing.
Applications that want to be nice can implement this method to release any caches or other unnecessary resources they may be holding on to. The system will perform a gc for you after returning from this method.
And Since: API Level 14
public abstract void onTrimMemory (int level)
Called when the operating system has determined that it is a good time for a process to trim unneeded memory from its process. This will happen for example when it goes in the background and there is not enough memory to keep as many background processes running as desired. You should never compare to exact values of the level, since new intermediate values may be added -- you will typically want to compare if the value is greater or equal to a level you are interested in.

Android lock screen behaviour

If I press home and come back to my app a little later I will find that the state has been preserved perfectly. For some reason however if I lock the phone and then unlock it, my app has been returned to the original state bar a few things here and there. When I looked into the logs I found that onCreate had been called while the phone was in a locked state. Because locking the phone is quite an off hand thing to do, having your game reset every time you do so is not desirable to the user. How can this be avoided at least for a longer period of time than a few seconds after locking the phone?
This is how Android OS works, it decides by it's own when to destroy your view. To avoid loosing this information there is a Method that can be reimplemented in your activity
#Override
public void onSaveInstanceState(Bundle outState){
iGameContent.saveGame(outState);
}
Save all your needed data into outState, and in the onCreate method, check if its a new instance or saved instance, like this:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.game);
if (savedInstanceState!=null){
iGameContent.loadGame(savedInstanceState);
}else{
// Normal initialization
}
}
An example of the save/load to a Bundle is the following:
public void loadGame(Bundle aBundle){
iBadsHit = aBundle.getInt("iBadsHits",0);
}
public void saveGame(Bundle aBundle){
aBundle.putInt("iBadsHit", iBadsHit);
}
If your log is showing that onCreate has been called then that means your apps process was killed.
Do you know the Android Activity Lifecycle? If not, read up on it here: Android Activities
The behavior on screen lock could vary from one device to other. Some events could cause the destruction of the app. You can try to handle some of this events to avoid this situation specifying it on the AndroidManifest.xml:
android:configChanges="keyboardHidden|orientation"
These two are the most problematic in screen lock. Yo can find more information on the last chapter of this nvidia document

Categories

Resources