Android: Is onPause() guaranteed to be called after finish()? - java

Couldn't find a solid answer to this anywhere. I have a method where finish() is being called, and onPause() is called afterward.
Is onPause() guaranteed to be called after a call to finish() ?

Android will generally call onPause() if you call finish() at some point during your Activity's lifecycle unless you call finish() in your onCreate().
public class MainActivity extends ActionBarActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
finish();
}
#Override
protected void onPause() {
super.onPause();
Log.d(TAG, "onPause");
}
#Override
protected void onStop() {
super.onStop();
Log.d(TAG, "onStop");
}
#Override
protected void onDestroy() {
super.onDestroy();
Log.d(TAG, "onDestroy");
}
}
Run, and observe that your log will only contain "onDestroy". Call finish() almost anywhere else and you'll see onPause() called.

The system calls this method as the first indication that the user is leaving your activity (though it does not always mean the activity is being destroyed). This is usually where you should commit any changes that should be persisted beyond the current user session (because the user might not come back). so
onPause() is guaranteed..The official documentation here
EDIT 1
onCreate() is to onDestroy() && onStart() is to onStop() && onResume() is to onPause() .. onStart() is called when onCreate() finishes its work. if not its not called.. onResume() indicates the ui is about to be shown to the user -(An Activity's content is the screen the user sees).
if you call finish() in onCreate(), onPause() will be skipped because onResume() was never called same goes to onStart() .. so in some cases you can say its not; but that will be false, because what's an Activity that is not a screen or serve as a container for screens-(Fragment).
and why would you call finish(); directly in your Activity's onCreate()? From how Activities work in general, onPause() will always guarantee is calling..

Yes, whenever you activity is going to be disappeared, onPause is called.

It is a bit late but may help future visitors.
I faced the problem of onPause() not being called when I tried to make an splash screen for my app following this tutorial.
After some fiddling around and forcing my mind I figured out why! the onCreate() method looks like this:
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = new Intent(this, MainActivity.class);
startActivity(intent);
finish();
}
So before the activity gets a chance to get started or resumed I was forcing it to be finished and so bypassing the other state method calls!
But as far as I know from the official Activity documentation in any other situation (at least normal ones!) the onPause() method is guaranteed to be called!

Related

Retaining variable value when stopping android activity

I've got two activities, A and B. Activity B can be opened by pressing a button in Activity A.
In activity B I have an integer variable which I would like to keep for when I return to activity B from A. My problem is when I press the back button to go from B to A the activity is destroyed.
I have overwritten the onBackPressed method to:
#Override
public void onBackPressed(){
Intent i = new Intent(this, Game.class);
startActivity(i);
}
I can see from my logs that activity B is in the state onStop() after back button is pressed, however, onRestart() is not being called so the activity must be getting killed for memory reasons.
I have read answers to other posts suggesting I use onSaveInstanceState() but when I try to access the bundle in onCreate() the bundle is null. Method onRestoreInstanceState() does not get called.
protected void onSaveInstanceState(Bundle savedInstanceState){
Log.i(LOG, "instance saving");
super.onSaveInstanceState(savedInstanceState);
savedInstanceState.putInt("score", userScore);
}
I have also tried SharedPreferences but this is not useful because I do not want my data to persist when the activity/application is intentionally destroyed.
I think your problem is in understanding the whole Task ecosystem. When you press back button you pop out your activity from the Task, because of that it is destroyed and onDestroyed() is called. To sum-up I think you are just getting every time a brand new activity. onSaveInstanceState() isn't called because activity is killed by user, not by the OS.
Take a deeper look at this developer tutorial.
Also I think those two must be helpful : me and me!
you can store variables in the app class https://developer.android.com/reference/android/app/Application.html or you can make your own singleton class for this
https://www.tutorialspoint.com/design_pattern/singleton_pattern.htm
Starting a Activity - A on onBackPressed will definitely kill the current Activity - B. Instead of starting Activity again just call onBackPressed in Activity - B and add a stage called onResume() which is called when you resume back to Activity B from A
Remove this:
#Override
public void onBackPressed(){
Intent i = new Intent(this, Game.class);
startActivity(i);
}
With this:
#Override
public void onBackPressed(){
super.onBackPressed();
}
When you coming back from A to B, in B #Override stage onResume() and in this you can save the value while coming back from Activity A.
Add this in Activity B:
#Override
protected void onResume() {
super.onResume();
// save values here for resume
}
Look the Activity Life Cycle:

Why is my onResume being called twice?

Basically, this is what I'm doing
1) Set AlarmManager to execute BroadcastReceiver (BCR)
Intent intent = new Intent(m_Context, BCR.class);
intent.putExtras(extras);
PendingIntent pendingIntent = PendingIntent.getBroadcast(m_Context, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
AlarmManager am = (AlarmManager) getSystemService(Context.ALARM_SERVICE);
am.set(AlarmManager.RTC_WAKEUP, StartTime, pendingIntent)
2) Start MyActivity from BCR
#Override
public void onReceive(Context context, Intent intent) {
Intent newIntent = new Intent(context, MyActivity.class);
newIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_SINGLE_TOP);
context.startActivity(newIntent);
}
3) Have MyActivity turn on the screen if its not on
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(LayoutParams.FLAG_DISMISS_KEYGUARD);
getWindow().addFlags(LayoutParams.FLAG_SHOW_WHEN_LOCKED);
getWindow().addFlags(LayoutParams.FLAG_TURN_SCREEN_ON);
setContentView(R.layout.myactivity);
}
#Overide
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
}
For some reason, I notice that right when MyActivity is opened, it's flow goes like:
onCreate/onNewIntent -> onResume -> onPause -> onResume
I'm not sure why it does an onPause right away. I notice this only happens when the screened is being turned on by the flags. Does anyone know why this happens? Is there any way this behavior can be prevented?
if you trying request permissions every time it can cause such problems, just check if you already granted them
requestPermissions can cause it:
onCreate
onStart
onResume
onPause
onResume
Use this method ContextCompat.checkSelfPermission(context, permission) to check if permission was granted or not before requesting it
This method returns int and you can check it with PackageManager.PERMISSION_GRANTED constant
Just in case anyone else runs into this, I seem to notice this behaviour only when I inflate fragments inside of an activity via XML layout. I don't know if this behaviour also happens with the compatibility library version of Fragments (I'm using android.app.Fragment)
It seems the activity will call Activity#onResume once before calling Fragment#onResume to any added Fragments, and then will call Activity#onResume again.
Activity:onCreate
Fragment:onAttach
Activity:onAttachFragments
Fragment:onCreate
Activity: onStart
Activity: onResume
Fragment: onResume
Activity: onResume
If you have ES File Explorer then FORCE STOP it. Somehow, they interrupt your app's lifecycle (comments suggest some kind of overlay).
My issue with onResume being caused twice was because onPause was somehow being called after the activity was created.. something was interrupting my app.
And this only happens after being opened for the first time after installation or built from studio.
I got the clue from another post and found out it was because of ES File Explorer. Why does onResume() seem to be called twice?
As soon as I force stop ES File Explorer, this hiccup behavior no longer happens... it's frustrating to know after trying many other proposed solutions. So beware of any other interrupting apps like this one.
I was researching about this for a while because on the internet there is no any mention about this weird behaviour. I don't have a solution how to overcome this dark-side-behavior but I have found an exact scenario when it certainly happens.
onPause-onResume-onPause-onResume just happens every time, when app is starting first time after installation. You can simply invoke this behavior by doing any change in code and rerunning (which includes recompiling) the app from your IDE.
No matter if you use AppCompat libs or not. I have tested both cases and behavior carries on.
Note: Tested on Android Marshmallow.
I have borrowed the code from this thread about fragment and activity lifecycle and here it is (just copy, paste, declare activity in manifest and run Forest run):
import android.app.Activity;
import android.app.Fragment;
import android.app.FragmentTransaction;
import android.content.Context;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
public class TestActivity extends Activity {
private static final String TAG = "ACTIVITY";
public TestActivity() {
super();
Log.d(TAG, this + ": this()");
}
protected void finalize() throws Throwable {
super.finalize();
Log.d(TAG, this + ": finalize()");
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, this + ": onCreate()");
TextView tv = new TextView(this);
tv.setText("Hello world");
setContentView(tv);
if (getFragmentManager().findFragmentByTag("test_fragment") == null) {
Log.d(TAG, this + ": Existing fragment not found.");
FragmentTransaction ft = getFragmentManager().beginTransaction();
ft.add(new TestFragment(), "test_fragment").commit();
} else {
Log.d(TAG, this + ": Existing fragment found.");
}
}
#Override
public void onStart() {
super.onStart();
Log.d(TAG, this + ": onStart()");
}
#Override
public void onResume() {
super.onResume();
Log.d(TAG, this + ": onResume()");
}
#Override
public void onPause() {
super.onPause();
Log.d(TAG, this + ": onPause()");
}
#Override
public void onStop() {
super.onStop();
Log.d(TAG, this + ": onStop()");
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, this + ": onDestroy()");
}
public static class TestFragment extends Fragment {
private static final String TAG = "FRAGMENT";
public TestFragment() {
super();
Log.d(TAG, this + ": this() " + this);
}
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, this + ": onCreate()");
}
#Override
public void onAttach(final Context context) {
super.onAttach(context);
Log.d(TAG, this + ": onAttach(" + context + ")");
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
Log.d(TAG, this + ": onActivityCreated()");
}
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d(TAG, this + ": onCreateView()");
return null;
}
#Override
public void onViewCreated(View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
Log.d(TAG, this + ": onViewCreated()");
}
#Override
public void onDestroyView() {
super.onDestroyView();
Log.d(TAG, this + ": onDestroyView()");
}
#Override
public void onDetach() {
super.onDetach();
Log.d(TAG, this + ": onDetach()");
}
#Override
public void onStart() {
super.onStart();
Log.d(TAG, this + ": onStart()");
}
#Override
public void onResume() {
super.onResume();
Log.d(TAG, this + ": onResume()");
}
#Override
public void onPause() {
super.onPause();
Log.d(TAG, this + ": onPause()");
}
#Override
public void onStop() {
super.onStop();
Log.d(TAG, this + ": onStop()");
}
#Override
public void onDestroy() {
super.onDestroy();
Log.d(TAG, this + ": onDestroy()");
}
}
}
I don't know for sure what's going on, but I suspect that your activity is being restarted because setting the screen on is treated by the system as a configuration change. You might try logging the configuration on each call to onResume to see if that's what's happening and, if so, what is actually changing. You can then modify the manifest to tell the system that your activity will handle the change on its own.
protected void onResume() [
super.onResume();
Configuration config = new Configuration();
config.setToDefaults();
Log.d("Config", config.toString());
. . .
}
I have similar problem.
My situation was next
CurrentActivity extends MainActivity
CurrentFragment extends MainFragment
I was opening CurrentActivity with intent as usually. In onCreate CurrentAcitivity I was replacing CurrentFragment.
Life Cycle was:
1. onResume MainActivity
2. onResume CurrentActivity
3. onResume MainFragment
4. onResume CurrentFragment
called onPause Automatically, and after that again
onResume MainActivity
onResume CurrentActivity
onResume MainFragment
onResume CurrentFragment
I decide to retest everything and after few hours spend trying and playing I found root issue.
In MainFragment onStart I was calling startActivityForResult every time (in my case android popup for turning on Wifi) which was call onPause on MainFragment. And all of us know that after onPause next is onResume.
So its not Android bug, it's only mine :-)
Happy lifecycle debuging!
I also ran into this onresume-onpause-onresume sequence (on 4.1.2 and above, but I did not experience this on 2.3). My problem was related to wakelock handling: I accidentally forgot to release a wakelock and reacquiring it caused an error with a message "WakeLock finalized while still held". This problem resulted in onPause being called immediately after onResume and resulted in faulty behavior.
My suggestion is: check for errors in the log, those might be related to this issue.
Another hint: turning on the screen might be a bit more tricky than simply using window flags. You might want to check this answer here - it suggests you set up a receiver to check if the screen has already been turned on and launch the desired activity only after: https://stackoverflow.com/a/16346369/875442
I had a similar issue, and my problem was that at the onCreate() method, I was doing:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
super.setContentView(R.layout.friends); <-- problem
}
My call to "super." was triggering the onResume() twice. It worked as intended after I changed it to just:
#Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.friends); <-- 'super.' removed
}
Hope it helps.
Have you tried calling your getWindow().addFlags(...) before calling super.onCreate(savedInstanceState) in onCreate method?
I had a similar problem. onResume was called twice when my onCreate looked like this:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
setContentView(R.layout.main);
...
}
Changing it to:
#Override
public void onCreate(Bundle savedInstanceState) {
AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_YES);
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
...
}
... fixed the problem.
It seems that using Activity from the support library saves and restores instance automatically. Therefore, only do your work if savedInstanceState is null.
I just ran into this, and it seems that getWindow().addFlags() and tweaking Window properties in general might be a culprit.
When my code is like this
#Override
protected void onCreate(Bundle savedInstanceState) {
requestWindowFeature(Window.FEATURE_NO_TITLE);
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_generic_fragment_host);
// performing fragment transaction when instance state is null...
onResume() is triggered twice, but when I remove requestWindowFeature(), it's only called once.
I think you should have a look at that question:
Nexus 5 going to sleep mode makes activity life cycle buggy
You should find leads
Basically a lot of stuff can trigger this. Some resume processes that loses focus can do it. A few apps will cause it to happen too. The only way to cope is to block the double running. Note, this will also have an errant pause thrown in for good measure.
boolean resumeblock = false;
#Override
protected void onResume() {
super.onResume();
sceneView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
sceneView.getViewTreeObserver().removeOnPreDrawListener(this);
if (resumeblock) return false;
resumeblock = true;
//Some code.
return false;
}
});
}
This is a solid way to prevent such things. It will block double resumes. But, it will also block two resumes that preserve the memory. So if you just lost focus and it doesn't need to rebuild your stuff. It will block that too. Which might be a benefit clearly, since if you're using the resume to control some changes over focus, you only actually care if you need to rebuild that stuff because of focus. Since the pre-draw listeners can only be called by the one thread and they must be called in sequence, the code here will only run once. Until something properly destroys the entire activity and sets resumeblock back to false.
as #TWL said
ES File Explorer
was the issue for me !
Uninstalling the app solved the problem.
When this ES File Explorer was installed, onStart() -> onResume() -> onPause() -> onResume() .. was the problem.
onResume() was called 2'ce.
I had the same problem. Mine was for this code in runtime
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_LANDSCAPE);
I just put it in manifest
android:screenOrientation="landscape"
no more problem about twice call to onCreate and onResume.
I didn't see an adequate answer to the question, so I decided this.
From My Notes:
"It seems that the activity runs onResume() onPause() then onResume again. The very last method that runs is the onSizeChanged(). So a good practice would be to start threads only after the onSizeChanged() method has been executed."
So you could: Make a log of each method that runs. Determine the last method that runs. Ensure that you have a Boolean that initializes false, and only changes to true after your last method runs. Then you can start all threading operations, once you check that the Boolean is true.
-For anyone wondering: I am using a surfaceview that has a onSizeChanged() method that executes very last.
I had the same problem because of setting the UiMode in the onCreate() of MainActivity. Changing the theme triggered activity recreation and made two calls to onPause() and onStart().
I was sure this was happening in my app until I realized I had planted two of Jake Wharton's Timber trees, and onResume() was just being logged twice, not called twice.
i also faced this issue this is because of fragments..
the number of fragments you have in activity onResume() will call that number of times. to overcome i used flag variables in SharedPrefrences

savedInstanceState always null

so i have this code in my OnsavedInstanceState
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
super.onSaveInstanceState(savedInstanceState);
String [] a={"haha"};
savedInstanceState.putStringArray("MyStringarray", a);
Toast.makeText(context, "Saved array", Toast.LENGTH_SHORT).show();
}
and i have this code in my onCreate
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
if(savedInstanceState==null){
Toast.makeText(this, "not there", Toast.LENGTH_SHORT).show();
}else{
Toast.makeText(this, "is there", Toast.LENGTH_SHORT).show();
}
}
how come the toast always says not there? i opened the app then switched to another app and it showed the toast saved array but when i reopen the app it says not there even though the bundle should have the string array containing "haha".
Many thanks!
In onSaveInstanceState() you're modifying savedInstanceState and not saving this modified object. If super does a copy of your Bundle, then it will not save this modification.
Try calling super.onSaveInstanceState(savedInstanceState); at the end of the method instead.
#Override
public void onSaveInstanceState(Bundle savedInstanceState) {
String [] a={"haha"};
savedInstanceState.putStringArray("MyStringarray", a);
super.onSaveInstanceState(savedInstanceState);
Toast.makeText(context, "Saved array", Toast.LENGTH_SHORT).show();
}
The problem might be in how you have your activities defined in your manifest. For instance if your activity has the setting android:clearTaskOnLaunch="true" I don't think you will receive the saved bundle. See http://developer.android.com/guide/topics/manifest/activity-element.html for details on the various activity settings.
You might also check the other overridden methods. For example in you override one and do something odd you could mess the activity stack up. Do you call finish() anywhere in you code, if so remove it and see what happens.
Do not confuse this method with activity lifecycle callbacks such as onPause(), which is always called when an activity is being placed in the background or on its way to destruction, or onStop() which is called before destruction. One example of when onPause() and onStop() is called and not this method is when a user navigates back from activity B to activity A: there is no need to call onSaveInstanceState(Bundle) on B because that particular instance will never be restored, so the system avoids calling it. An example when onPause() is called and not onSaveInstanceState(Bundle) is when activity B is launched in front of activity A: the system may avoid calling onSaveInstanceState(Bundle) on activity A if it isn't killed during the lifetime of B since the state of the user interface of A will stay intact.

Android: Using onPause() Selectively

I have a single activity timer application in which I have overridden the onPause() method to pause the timer when the user presses the home or back button. However, I would like the timer to keep moving in the case that the user manually turns off his screen, but I know this will also call the onPause() method. Is there any way to get around this?
You can override onBackPressed to allow you to put some extra logic when the back button is pressed. However, a better approach might be to put your code in onStop(), which is only called when another Activity is moved to the foreground.
See the Android Docs for more detail
I ended up doing this by detecting and ignoring a screen turn off event inside the onPause() method. Instructions on how to do this can be found here: http://thinkandroid.wordpress.com/2010/01/24/handling-screen-off-and-screen-on-intents/
Specifically, I used this code from the comments (courtesy of Kyle):
#Override
protected void onCreate() {
// initialize receiver
IntentFilter filter = new IntentFilter(Intent.ACTION_SCREEN_ON);
filter.addAction(Intent.ACTION_SCREEN_OFF);
BroadcastReceiver mReceiver = new ScreenReceiver();
registerReceiver(mReceiver, filter);
//NEW
PowerManager pm =(PowerManager) getSystemService(Context.POWER_SERVICE);
// your code
}
#Override
protected void onPause() {
// when the screen is about to turn off
// Use the PowerManager to see if the screen is turning off
if (pm.isScreenOn() == false) {
// this is the case when onPause() is called by the system due to the screen turning off
System.out.println(“SCREEN TURNED OFF”);
} else {
// this is when onPause() is called when the screen has not turned off
}
super.onPause();
}

Android: Mediaplayer plays multiple times if I keep on pressing the back button and launch the app again

When I play my song and press the back button to return to return to home, the music continues playing. When I launch the app again, the music plays twice. I think it's the onResume method because I commented out the method and the problem stopped. How do I get onResume work properly? I tried using if(backgroundMusic.isplaying()) inside the onResume, but the app crashes when I resume from another activity. What am I doing wrong?
//global mediaplayer
MediaPlayer backgroundMusic;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
loadBackgroundMusic();
}
private void loadBackgroundMusic() {
//load mp3 into object and start it
backgroundMusic = MediaPlayer.create(this,R.raw.backgrounmusic);
backgroundMusic.setLooping(true);
backgroundMusic.start();
}
#Override
protected void onPause() {
super.onPause();
backgroundMusic.release();
}
#Override
protected void onResume() {
super.onResume();
loadBackgroundMusic();
}
#Override
protected void onStop() {
super.onStop();
backgroundMusic.release();
}
I'm not really sure about the behavior you want. As I see it, it's one of two:
Music should be played only while my Activity is visible
If this is the case, you should look closer on the documentation for the Activity Lifecycle. This will for example tell you that onResume() will also be called the first time the Activity is created.
So the solution would be to start the music in onResume() and stop on onPause() or similar.
After starting my activity once, music should be played even if i return to home screen
In this case you really want a Service.

Categories

Resources