多次调用 OnResume / OnPause

OnResume / OnPause called multiple times

我的 MainActivity 正在加载不同的片段。此外,可以从 MainActivity.

打开 Settings-Activity

如果用户只是在片段之间切换,一切都很好。

打开设置-Activity 并返回主Activity 时,onResume 和 onPause 被调用两次。如果用户打开 Settings-Activity 并再次返回 MainActivity,onResume 和 onPause 将被调用 3 次。每次用户打开 Settings-Activity 并返回 MainActivity.

时都会增加

主要Activity

 public class MainActivity extends AppCompatActivity implements MyFragment.OnListFragmentInteractionListener, AsyncResponse {


                    private FragmentA fragmentA = new FragmentA();

                    private DatabaseHandler databaseHandler = new DatabaseHandler(this);

                    private NavigationView navigationView;
                    private DrawerLayout drawer;
                    private Toolbar toolbar;

                    // index to identify current nav menu item
                    private static int navItemIndex = 0;

                    public static String CURRENT_TAG = MyConstants.TAG_FRAGMENT_A;

                    // toolbar titles respected to selected nav menu item
                    private String[] activityTitles;

                    // flag to load home fragment when user presses back key
                    private Handler mHandler;

                    @Override
                    protected void onCreate(Bundle savedInstanceState) {

                        super.onCreate(savedInstanceState);

                        setContentView(R.layout.activity_main);

                        fragmentA.setDatabaseHandler(this.databaseHandler);

                        // Init UI
                        toolbar = (Toolbar) findViewById(R.id.toolbar);
                        setSupportActionBar(toolbar);

                        mHandler = new Handler();

                        drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
                        navigationView = (NavigationView) findViewById(R.id.nav_view);

                        fabSendButton = (FloatingActionButton) findViewById(R.id.fab);

                        // Navigation view header
                        navHeader = navigationView.getHeaderView(0);


                        // load toolbar titles from string resources
                        activityTitles = getResources().getStringArray(R.array.sliding_menu_item_activity_titles);


                        // initializing navigation menu
                        setUpNavigationView();

                        if (savedInstanceState == null) {
                            navItemIndex = 0;
                            CURRENT_TAG = MyConstants.TAG_FRAGMENT_A;
                            loadHomeFragment();
                        }
                    }

                    /***
                     * Returns respected fragment that user
                     * selected from navigation menu
                     */
                    private void loadHomeFragment() {

                        // set toolbar title
                        setToolbarTitle();

                        // if user select the current navigation menu again, don't do anything
                        // just close the navigation drawer
                        if (getSupportFragmentManager().findFragmentByTag(CURRENT_TAG) != null) {
                            drawer.closeDrawers();
                            return;
                        }

                        // Sometimes, when fragment has huge data, screen seems hanging
                        // when switching between navigation menus
                        // So using runnable, the fragment is loaded with cross fade effect
                        // This effect can be seen in GMail app
                        Runnable mPendingRunnable = new Runnable() {
                            @Override
                            public void run() {
                                // update the activity_main_header_with_item content by replacing fragments
                                Fragment fragment = getFragment();
                                FragmentTransaction fragmentTransaction = getSupportFragmentManager().beginTransaction();
                                fragmentTransaction.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out);
                                fragmentTransaction.replace(R.id.frame, fragment, CURRENT_TAG);
                                fragmentTransaction.commit();
                            }
                        };

                        // If mPendingRunnable is not null, then add to the message queue
                        if (mPendingRunnable != null) {
                            mHandler.post(mPendingRunnable);
                        }

                        //Closing drawer on item click
                        drawer.closeDrawers();

                        // refresh toolbar menu
                        invalidateOptionsMenu();
                    }

                    private Fragment getFragment() {
                        switch (navItemIndex) {
                            case 0:
                                return this.fragmentA;
                            case 1:
                                Fragment B fragmentB = new FragmentB();
                                fragmentB.setDatabaseHandler(this.databaseHandler);
                                return fragmentB;
                            default:
                                return this.fragmentA;
                        }
                    }

                    private void setToolbarTitle() {
                        getSupportActionBar().setTitle(activityTitles[navItemIndex]);
                    }

                    private void setUpNavigationView() {
                        //Setting Navigation View Item Selected Listener to handle the item click of the navigation menu
                        navigationView.setNavigationItemSelectedListener(new NavigationView.OnNavigationItemSelectedListener() {

                            // This method will trigger on item Click of navigation menu
                            @Override
                            public boolean onNavigationItemSelected(MenuItem menuItem) {

                                //Check to see which item was being clicked and perform appropriate action
                                switch (menuItem.getItemId()) {
                                    //Replacing the activity_main_header_with_item content with ContentFragment Which is our Inbox View;
                                    case R.id.nav_A:
                                        navItemIndex = 0;
                                        CURRENT_TAG = MyConstants.TAG_FRAGMENT_A;
                                        break;
                                    case R.id.nav_B:
                                        navItemIndex = 1;
                                        CURRENT_TAG = MyConstants.TAG_FRAGMENT_B;
                                        break;
                                    default:
                                        navItemIndex = 0;
                                }

                                loadHomeFragment();

                                return true;
                            }
                        });

                        ActionBarDrawerToggle actionBarDrawerToggle = new ActionBarDrawerToggle(this, drawer, toolbar, R.string.openDrawer, R.string.closeDrawer) {

                            @Override
                            public void onDrawerClosed(View drawerView) {
                                // Code here will be triggered once the drawer closes as we dont want anything to happen so we leave this blank
                                super.onDrawerClosed(drawerView);
                            }

                            @Override
                            public void onDrawerOpened(View drawerView) {
                                // Code here will be triggered once the drawer open as we dont want anything to happen so we leave this blank
                                super.onDrawerOpened(drawerView);
                            }
                        };

                        //Setting the actionbarToggle to drawer layout
                        drawer.setDrawerListener(actionBarDrawerToggle);

                        //calling sync state is necessary or else your hamburger icon wont show up
                        actionBarDrawerToggle.syncState();
                    }

                    @Override
                    public boolean onCreateOptionsMenu(Menu menu) {
                        getMenuInflater().inflate(R.menu.activity_main_header_with_item, menu);
                        return true;
                    }

             @Override
                public boolean onCreateOptionsMenu(Menu menu) {
                    getMenuInflater().inflate(R.menu.activity_main_header_with_item, menu);
                    // Disable Player Icon in case no player is found on device
                    Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, ScrobblOrDroidConstants.MUSIC_APP);
                    List<ResolveInfo> activities = getPackageManager().queryIntentActivities(intent, 0);
                    if(activities == null || activities.size() <= 0) {
                        MenuItem player = menu.findItem(R.id.player);
                        if(player != null){
                            player.setVisible(false);
                        }
                    }
                    return true;
                }

                @Override
                public boolean onOptionsItemSelected(MenuItem item) {
                    // Handle action bar item clicks here. The action bar will
                    // automatically handle clicks on the Home/Up button, so long
                    // as you specify a parent activity in AndroidManifest.xml.
                    int id = item.getItemId();

                    //noinspection SimplifiableIfStatement
                    if (id == R.id.player) {
                        Timber.i( "Added onClick listener to ImageView ivPlayer.");
                        Intent intent = Intent.makeMainSelectorActivity(Intent.ACTION_MAIN, ScrobblOrDroidConstants.MUSIC_APP);
                        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                        startActivity(intent);
                        return true;
                      } else if (id == R.id.settings) {
                        // launch settings activity
                        startActivity(new Intent(MainActivity.this, SettingsActivity.class));
                        return true;
                    }
                    return super.onOptionsItemSelected(item);
                }

            @Override
            public void onResume() {
                Timber.i("MainActivity.onResume-called.");
                activityVisible = true;
                updateHomeFragment();
                callLongUserOperation();
                super.onResume();
            }

            @Override
            public void onPause() {
                Timber.i("MainActivity.onPause-called.");
                activityVisible = false;
                super.onPause();
            }
         }

  public void updateHomeFragment() {
        if (CURRENT_TAG == MyConstants.TAG_HOME) {
            Timber.i( "updating HomeFragment");
            fragmentA.swap();
        }
    }

设置Activity

public class SettingsActivity extends AppCompatPreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setupActionBar();
        getFragmentManager().beginTransaction().replace(android.R.id.content, new MainPreferenceFragment()).commit();
    }

    private void setupActionBar() {
        ViewGroup rootView = (ViewGroup)findViewById(R.id.action_bar_root);
        View view = getLayoutInflater().inflate(R.layout.pref_toolbar, rootView, false);
        rootView.addView(view, 0);
        Toolbar toolbar = (Toolbar)findViewById(R.id.pref_toolbar);
        setSupportActionBar(toolbar);
        ActionBar actionBar = getSupportActionBar();
        if (actionBar != null) {
            // Show the Up button in the action bar.
            actionBar.setDisplayHomeAsUpEnabled(true);
        }
    }

    public static class MainPreferenceFragment extends PreferenceFragment {
        @Override
        public void onCreate(final Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.pref_main);

            // gallery EditText change listener
            bindPreferenceSummaryToValue(findPreference(MyConstants.RECENTLY_SCROBBLED_KEY));

            bindPreferenceSummaryToValue(findPreference(MyConstants.SCROBBLE_DURATION_KEY));

            // feedback preference click listener
            Preference myPref = findPreference("key_send_feedback");
            myPref.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
                public boolean onPreferenceClick(Preference preference) {
                    sendFeedback(getActivity());
                    return true;
                }
            });

            // rating preference click listener
            Preference myPrefRate = findPreference("key_send_rate");
            myPrefRate.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
                public boolean onPreferenceClick(Preference preference) {
                    sendRating(getActivity());
                    return true;
                }
            });
        }
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (item.getItemId() == android.R.id.home) {
            onBackPressed();
        }
        return super.onOptionsItemSelected(item);
    }

    private static void bindPreferenceSummaryToValue(Preference preference) {
        preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
        sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
                PreferenceManager.getDefaultSharedPreferences(preference.getContext()).getString(preference.getKey(), ""));
    }

    /**
     * A preference value change listener that updates the preference's summary
     * to reflect its new value.
     */
    private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            String stringValue = newValue.toString();

            if(preference.getKey().equalsIgnoreCase(MyConstants.RECENTLY_SCROBBLED_KEY)){
                preference.setSummary(stringValue + " " + preference.getContext().getResources().getString(R.string.pref_recently_scrobbled_summary));
            }
            if(preference.getKey().equalsIgnoreCase(MyConstants.SCROBBLE_DURATION_KEY)){
                preference.setSummary(preference.getContext().getResources().getString(R.string.pref_scrobble_percentage_summary, stringValue));
            }
            return true;
        }
    };

    /**
     * Email client intent to send support mail
     * Appends the necessary device information to email body
     * useful when providing support
     */
    public static void sendFeedback(Context context) {
        String body = null;
        try {
            body = context.getPackageManager().getPackageInfo(context.getPackageName(), 0).versionName;
            body = "\n\n-----------------------------\nPlease don't remove this information\n Device OS: Android \n Device OS version: " +
                    Build.VERSION.RELEASE + "\n App Version: " + body + "\n Device Brand: " + Build.BRAND +
                    "\n Device Model: " + Build.MODEL + "\n Device Manufacturer: " + Build.MANUFACTURER;
        } catch (PackageManager.NameNotFoundException e) {
        }
        Intent intent = new Intent(Intent.ACTION_SEND);
        intent.setType("message/rfc822");
        intent.putExtra(Intent.EXTRA_EMAIL, new String[]{MyConstants.E_MAIL_ADDRESS});
        intent.putExtra(Intent.EXTRA_SUBJECT, "Feedback for " + context.getResources().getString(R.string.app_name));
        intent.putExtra(Intent.EXTRA_TEXT, body);
        context.startActivity(Intent.createChooser(intent, context.getString(R.string.pref_choose_email_client)));
    }

    public static void sendRating(Context context) {
        Intent i = new Intent(Intent.ACTION_VIEW, Uri.parse(MyConstants.PLAY_STORE_URL));
        context.startActivity(i);;
    }

    @Override
    public void onResume() {
        super.onResume();
        PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).registerOnSharedPreferenceChangeListener(this);
    }

    @Override
    public void onPause() {
        PreferenceManager.getDefaultSharedPreferences(getApplicationContext()).registerOnSharedPreferenceChangeListener(this);
        super.onPause();
    }

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        if(key.equalsIgnoreCase(MyConstants.NOTIFICATION_ENABLED_KEY)){
            EventBus.getDefault().post(new NotificationEvent());
            Timber.i( "NotificationEvent Posted");
        }
    }
}

AppCompatPreferenceActivity

 public class AppCompatPreferenceActivity extends PreferenceActivity {

        private AppCompatDelegate mDelegate;

        @Override
        protected void onCreate(Bundle savedInstanceState) {
            getDelegate().installViewFactory();
            getDelegate().onCreate(savedInstanceState);
            super.onCreate(savedInstanceState);
        }

        @Override
        protected void onPostCreate(Bundle savedInstanceState) {
            super.onPostCreate(savedInstanceState);
            getDelegate().onPostCreate(savedInstanceState);
        }

        public ActionBar getSupportActionBar() {
            return getDelegate().getSupportActionBar();
        }

        public void setSupportActionBar(@Nullable Toolbar toolbar) {
            getDelegate().setSupportActionBar(toolbar);
        }

        @Override
        public MenuInflater getMenuInflater() {
            return getDelegate().getMenuInflater();
        }

        @Override
        public void setContentView(@LayoutRes int layoutResID) {
            getDelegate().setContentView(layoutResID);
        }

        @Override
        public void setContentView(View view) {
            getDelegate().setContentView(view);
        }

        @Override
        public void setContentView(View view, ViewGroup.LayoutParams params) {
            getDelegate().setContentView(view, params);
        }

        @Override
        public void addContentView(View view, ViewGroup.LayoutParams params) {
            getDelegate().addContentView(view, params);
        }

        @Override
        protected void onPostResume() {
            super.onPostResume();
            getDelegate().onPostResume();
        }

        @Override
        protected void onTitleChanged(CharSequence title, int color) {
            super.onTitleChanged(title, color);
            getDelegate().setTitle(title);
        }

        @Override
        public void onConfigurationChanged(Configuration newConfig) {
            super.onConfigurationChanged(newConfig);
            getDelegate().onConfigurationChanged(newConfig);
        }

        @Override
        protected void onStop() {
            super.onStop();
            getDelegate().onStop();
        }

        @Override
        protected void onDestroy() {
            super.onDestroy();
            getDelegate().onDestroy();
        }

        public void invalidateOptionsMenu() {
            getDelegate().invalidateOptionsMenu();
        }

        private AppCompatDelegate getDelegate() {
            if (mDelegate == null) {
                mDelegate = AppCompatDelegate.create(this, null);
            }
            return mDelegate;
        }
    }

AndroidManifest.xml

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.ordroid.My"
    android:versionCode="1"
    android:versionName="1.0">

    <uses-sdk
        android:minSdkVersion="15"
        android:targetSdkVersion="25" />

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <application
        android:allowBackup="true"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme">
        <activity
            android:name=".ui.activity.MainActivity"
            android:label="@string/app_name"
            android:screenOrientation="portrait">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <activity
            android:name=".ui.activity.LoginActivity"
            android:excludeFromRecents="true"
            android:label="@string/app_name"
            android:screenOrientation="portrait"></activity>
        <activity
            android:name=".ui.activity.SettingsActivity"
            android:label="@string/settings">
            <!-- Parent activity meta-data to support 4.0 and lower -->
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value=".ui.activity.MainActivity" />
        </activity>

        <!-- start service on device boot complete -->
        <receiver
            android:name=".util.receiver.MyBroadcastReceiver"
            android:enabled="true"
            android:exported="true"
            android:label="StartMyServiceAtBootReceiver">
            <intent-filter>
                <action android:name="com.android.music.metachanged" />
                <action android:name="com.android.music.playstatechanged" />
                <!-- <action android:name="android.intent.action._BOOT_COMPLETED" /> -->
            </intent-filter>
        </receiver>
        <receiver android:name=".util.receiver.MyInternetConnectionBroadcastReceiver">
            <intent-filter>
                <action android:name="android.net.conn.CONNECTIVITY_CHANGE" />
            </intent-filter>
        </receiver>

    </application>

</manifest>

如何避免这些多次调用?

似乎是 Android SDK 构建工具中的错误。更新后效果很好!

我遇到了同样的问题,其中一个活动的 onResume() 被调用了三次。

我通过将相应 activity 的 onCreate() 中的布尔值设置为 false 来修复它。例如:

boolean onResumeCalled = false

并且每次创建 activity 时,我都会将 onResumeCalled 保持为 false。

在onResume()中,我设置了一个检查

if(!onResumeCalled)

在 onResume() 的开始。

现在,当创建 activity 时,onResumeCalled 为 false。然后,一旦onResume()里面的方法被调用,我把onResumeCalled的值改成true,这样第二次调用onResume()的时候,onResume()里面的方法就不会被访问了,因为onResumeCalled的值现在是是的。

我在 Android 上发现 here 这种行为的某些原因。对我来说,这就是原因。

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.