Why is my onResume being called twice?

39,133

Solution 1

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.

  1. Activity:onCreate
  2. Fragment:onAttach
  3. Activity:onAttachFragments
  4. Fragment:onCreate
  5. Activity: onStart
  6. Activity: onResume
  7. Fragment: onResume
  8. Activity: onResume

Solution 2

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

Solution 3

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.

Solution 4

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()");
        }
    }

}

Solution 5

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());
    . . .
}
Share:
39,133
Huy T
Author by

Huy T

Updated on March 01, 2021

Comments

  • Huy T
    Huy T over 3 years

    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?