I issue the a notification with an action that opens mainactivity. This is the first time the activity is called, created and everything works perfectly. After I pause the activity I automatically call onDestroy() of the activity and it is destroyed with success. When I click the notification for the second time, however, there is an error that says FATAL EXCEPTION: main can't resume activity. If the activity was destroyed I wasn't expecting it to be resumed but recreated again... why is this happening and how can I force the recreation of the activity by these methods?
Do not call onDestroy() directly!
These are lifecycle methods that the system should call. The problem you are having is that the system still believes the activity is paused (rather than destroyed as you would have liked) since it was never notified. You undoubtedly invoked super.onDestroy() within your onDestroy() method (the right thing) which caused part of the activity to clean itself up, making it non-resumable. When the system comes around the resume the activity in which it thought was paused, it throws that error.
Fortunately, there are ways to tell the system to kill your activity when you want it, through a method called finish().
Android documentation:
Call this when your activity is done and should be closed. The ActivityResult is propagated back to whoever launched you via onActivityResult().
Replace your call to onDestroy() with this call should resolve your issue.
Never call lifecycle methods directly!
Related
What happens when we call the finish()method for the activity inside onCreate()?
Will the app get time to display the Activity, but then rapidly close, or won't it show anything?
This is just a doubt that I had before reading about some malware services for android that allegedly use this idea... Does it effectively work?
I just tested and debugged it, the Activity starts but is immediately closes once the event is generated.
As MrMins mention it will rapidly close. The lifecycle will skip over some important steps, therefore causing potential issues.
But to answer you question it will run only momentarily.
Here is the android documentation of the lifecycle: https://developer.android.com/guide/components/activities/activity-lifecycle.html
As per official documentation:
You can call finish() from within this function, in which case onDestroy() will be immediately called after onCreate(Bundle) without any of the rest of the activity lifecycle (onStart(), onResume(), onPause(), etc) executing.
Since
The visible lifetime of an activity happens between a call to onStart() until a corresponding call to onStop().
so the "visible lifetime" is not reached for that case.
I just came across this code in
Intent wizard = new Intent();
wizard.setClass(this, A.class);
wizard.putExtra("Domain", A.getInstance().B);
startActivity(wizard);
finish();
Why should we call finish() method here?
What's it purpose?
finish() Call this when your activity is done and should be closed, when starting an activity calling finish() will close the current activity and it will not be available in the Activity Stack.
finish();
finish is used for closing current activity.It is like you are sending data to other activity/Opening new activity and closing your current activity.
You are not imperative forced to do that...
normally people do that if and only if the want to destroy the activity that is starting the intent, but that must no be your case...
in the life cycle of android you will see:
assuming you activity is visible, then calling finish() method will call
onPause(), then onStop() and finally the onDestroy()
Let's understand it using few quotes
finish - Call this when your activity is done and should be closed. The ActivityResult is propagated back to whoever launched you
via onActivityResult()
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.
when you call finish() on an activity, the methods followed by onDestroy() is executed.. eg: onPause()> onStop() > and onDestroy()they can be differ from the place you call finish()!
onDestroy() is meant for final cleanup - freeing up resources that you can on your own,closing open connections,readers,writers,etc. If you don't override it, the system does what it has to.
It inform the system that you want to finish the selected Activity so it wil call onDestroy() after you finish the activity.(but this does not mean that onDestroy() only gets called by finish(),system can do that when it's running out of resources after the activity is sent to the back state)
Also there are more interesting questions like Activity.finish() called but activity stays loaded in memory that you might like
I understand when these methods are called: onCreate(), onStart(), onResume(), onPause(), onStop(), onDestroy().
However, will these methods actually do anything by default even if I didn't write any code in them?
For example, when the onPause method is called, will it automatically help me to pause and save resources even if I didn't specify the code for doing so? Or must I code everything manually?
If so, what is the general guideline of what kind of resources to save during OnPause and OnStop?
You MUST code those events if you want to do something inside your app. The activity lifeclycle (activity lifecycle part) will do tasks related to the android system, besides, the activity lifecycle give to you the opportunity to do things on your own when the events happens, but is up to you and your code to do things for your app.
If the only thing that you want to achieve is save/restore data you can use onSaveInstanceState. Take a look here How to use onSavedInstanceState example please
Refer to Activity Lifecycle
onCreate() Called when the activity is first created. This is where
you should do all of your normal static set up: create views, bind
data to lists, etc. This method also provides you with a Bundle
containing the activity's previously frozen state, if there was one.
Always followed by onStart().
onRestart() Called after your activity has been stopped, prior to it
being started again. Always followed by onStart()
onStart() Called when the activity is becoming visible to the user.
Followed by onResume() if the activity comes to the foreground, or onStop() if it becomes hidden.
onResume() Called when the activity will start interacting with the user. At this point your activity is at the top of the activity stack, with user input going to it.
Always followed by onPause().
onPause() Called when the system is about to start resuming a previous activity. This is typically used to commit unsaved changes to persistent data, stop animations and other things that may be consuming CPU, etc. Implementations of this method must be very quick because the next activity will not be resumed until this method returns.
Followed by either onResume() if the activity returns back to the front, or onStop() if it becomes invisible to the user.
onStop() Called when the activity is no longer visible to the user, because another activity has been resumed and is covering this one. This may happen either because a new activity is being started, an existing one is being brought in front of this one, or this one is being destroyed.
Followed by either onRestart() if this activity is coming back to interact with the user, or onDestroy() if this activity is going away.
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. You can distinguish between these two scenarios with the isFinishing() method.
Because an app I'm building will handle rather sensitive data I want to sync the SQLite db with the server every time the user logs in, and remove emty the db every time the app loses focus (because the user moves to the home screen or another app).
Seeing the Activity lifecycle, my idea was to do this by emptying the database in the onDestroy of every Activity. To test the described lifecycle I just Override all lifecycle methods (onCreate, onStart, onResume, onPause, onStop, and onDestroy), included some log messages in them, and fired up my app.
The log messages are included in my SettingsActivity. When I enter my app and move to the Settings it runs onCreate, onStart and onResume (as expected). When I then click a setting and move to the next screen it runs onPause and onStop (still as expected). To move back to the settings screen I click the back button and it runs onStart and onResume again (still as expected), when I now click the back button again to move back to the initial screen, it (to my surprise) runs onPause, onStop AND onDestroy.
So my questions;
Why does it destroy the Activity when the app is not finished?
And more importantly: how can I run my CleanUp method when the app closes or loses focus?
You can have some more information here : http://developer.android.com/training/basics/activity-lifecycle/stopping.html
Even if I think you already read it because you already study the activity lifecycle, you can see in the first figure that the onDestroy() is called after the onStop() and this call is totally managed by the system : you shouldn't expect any behavior. The system will decide itself WHEN to call this method, and sometimes, this method will never be called (see here : http://developer.android.com/reference/android/app/Activity.html). When system needs memory, your activity will pass in onStop() and nothing more.
So, to answer your second question, you shloud read the note in the documentation about the onDestroy() method :
Note: do not count on this method being called as a place for saving
data! For example, if an activity is editing data in a content
provider, those edits should be committed in either onPause() or
onSaveInstanceState(Bundle), not here. 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. 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.
So it's pretty clear that it's a bad place to make your clean-up process. So you shloud use one of onPause() or onStop() method.
onStop() is described like this in the documentation :
Called when you are no longer visible to the user. You will next receive either onRestart(), onDestroy(), or nothing, depending on later user activity.
onPause() is described like this in the documentation :
Called as part of the activity lifecycle when an activity is going
into the background, but has not (yet) been killed.
[...]
When activity B is launched in front of activity A, this callback will be
invoked on A. B will not be created until A's onPause() returns, so be
sure to not do anything lengthy here.
[...]
In situations where the system needs more memory it may kill paused processes to reclaim resources.
We now know that onPause() is designed to allow you to save your data, and also that after onPause() was executed, the system could kill your process. So, making the clean-up in onPause() seems to be the safest place as you're pretty sure it will be called everytime.
Also, as you can read, making your clean up here can make your app slow, but anyway cleaning and recreating your database at each gain/loose of focus is a really heavy process...
To resume : make your clean up process in the onPause() method and your init process in the onResume(). Keep it mind that your application can be really slow with this kind of process.
Hope this can help you.
Destroying the Activity on back is the normal behavior. From the Android developers site
There are a few scenarios in which your activity is destroyed due to normal app behavior, such as when the user presses the Back button...
Has for detecting when the application goes to background, there is no simple method call that will let you know that. However this previous question contains some nice answers on how to do it.
You can't do this (call a function) in java part of app.
Only in the native part.
About your second question, this way you could run your CleanUp method when the app closes fully. You will need to implement your method inside a service that in this case I named "ExitService"
First create this service class:
public class ExitService extends Service {
#Nullable
#Override
public IBinder onBind(Intent intent) {
return null;
}
#Override
public void onTaskRemoved(Intent rootIntent) {
System.out.println("onTaskRemoved called");
super.onTaskRemoved(rootIntent);
//do something you want before app closes.
ADD YOUR METHOD HERE, or CALL IT
//stop service
this.stopSelf();
}
}
Then, declare this way your service in the manifest "application" label:
<service
android:enabled="true"
android:name=".ExitService"
android:exported="false"
android:stopWithTask="false" />
Now, just start the service wherever you want to do something before your app closing.
Intent intent = new Intent(this, ExitService.class);
startService(intent);
All the sources I read have all mentioned couple of cases and concluded with "a few other cases". What are ALL the cases when the onSaveInstanceState method called in a View/Activity?
onSaveInstanceState() will be called by default for a view if it has an id.
google said: "The default implementation takes care of most of the UI per-instance state for you by calling onSaveInstanceState() on each view in the hierarchy that has an id".
More info here.
Whenever there is as soft kill of the activity. I.e when the orientation changes or when the process is killed by android due to low memory.
It's not called when the user knowingly just navigates away from the activity.
Refer to this link: https://sites.google.com/site/jalcomputing/home/mac-osx-android-programming-tutorial/saving-instance-state
The doc says
This method is called before an activity may be killed so that when it comes back some time in the future it can restore its state.
Also be aware that onSaveInstanceState can be called on a fragment directly after onCreate (onCreateView, onActivityCreated, onStart, and onResume will NOT be called), if the fragment is attached to an activity but not shown, then destroyed. Thus you need to be sure that everything you reference in onSaveInstanceState is initialized in onCreate, otherwise you risk a NullPointerException.
onSaveInstanceState() is called when there is an orientation change
or user presses home button.
If there is an another activity in front of an
activity and the OS kills the hidden activity in order to free
memory(or when memory is needed elsewhere), then onSaveInstanceState() is called so activity can save its state information which is restored using onRestoreInstanceState() when user start that activity next time .
Default views of Android save their state via a call to
View.onSaveInstanceState which is restored by the default implementation of onRestoreInstanceState
As per doc
If the user interacts with an activity and presses the Back button or
if the finish() method of an activity is called, the activity is
removed from the current activity stack and recycled. In this case
there is no instance state to save and the onSaveInstanceState()
method is not called.
If the user interacts with an activity and presses the Home button,
the activity instance state must be saved. The onSaveInstanceState()
method is called. If the user restarts the application it will resume
or restart the last running activity. If it restarts the activity it
provides the bundle with the save data to the onRestoreInstanceState()
and onCreate() methods.
If you override onSaveInstanceState() and onRestoreInstanceState() you
should call the super implementation of it, because the default views
of Android store their data via a call to View.onSaveInstanceState
from the onSaveInstanceState() method of the activity. For example
EditText stores its content via the default call of this method.
This method did not call when user presses "return" button,this is one of that case..
onSaveInstanceState is called when ever activity is out of veiw.. like when u press home key, onSaveInstanceState is called.
From here: the answer is onSaveInstanceState() gets called regardless of whether or not your app process is killed. So in all of these scenarios, onSaveInstanceState() is called:
Normal background scenario
Your activity goes into the background and onSaveInstanceState() is called
You do some other things
Your user navigates back to your activity
Process kill background scenario
Your activity goes into the background and onSaveInstanceState() is called
You do some other things and during this time the system starts running low on resources and closes your app’s process
Your user navigates back to the activity
onRestoreInstanceState() and onCreate() (with the saved instance state bundle) are called
Configuration change scenario
A configuration change occurs and onSaveInstanceState() is called
onRestoreInstanceState() and onCreate() (with the saved instance state bundle) are called
The difference is whether onCreate()/onRestoreInstanceState() are called. In the process kill and configuration scenarios they are called. In the normal scenario, there is no need to recreate the activity and neither are called.
Note that onSaveInstanceState() is called when your activity goes into the background and NOT when the app process is about to be killed. This is because in the scenario your app process gets killed, the system is pretty resource constrained as is and it would NOT be a good time to spend cycles storing key/value pairs in RAM.