简体   繁体   English

OnResume / OnPause多次调用

[英]OnResume / OnPause called multiple times

My MainActivity is loading different Fragments. 我的MainActivity正在加载不同的片段。 Furthermore, a Settings-Activity can be opened from the MainActivity. 此外,可以从MainActivity中打开Settings-Activity。

If the user is only switching between Fragments, everything is fine. 如果用户仅在片段之间切换,那么一切都很好。

When opening the Settings-Activity and going back to MainActivity, onResume and onPause gets called twice. 当打开Settings-Activity并返回MainActivity时,onResume和onPause会被调用两次。 If the user opens Settings-Activity and goes back again to MainActivity, onResume and onPause get called three times. 如果用户打开Settings-Activity并再次返回MainActivity,则会调用onResume和onPause 3次。 This increases each time the user opens Settings-Activity and going back to MainActivity. 每次用户打开Settings-Activity并返回MainActivity时,这种情况都会增加。

MainActivity 主要活动

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

SettingsActivity 设置活动

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 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 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>

How can I avoid these multiple calls? 如何避免这些多次通话?

Seems it was a bug in the Android SDK Build Tool. 似乎是Android SDK构建工具中的错误。 After updating it works as a charme! 更新后,它可以作为一个魅力!

I faced the same issue where onResume() of one of my Activities was getting called thrice. 我遇到一个相同的问题,其中我的一个活动的onResume()被称为三次。

I fixed it by seting a boolean in onCreate() of the corresponding activity as false. 我通过将相应活动的onCreate()中的布尔值设置为false来解决此问题。 For example: 例如:

boolean onResumeCalled = false

and every time the activity is created, I keep onResumeCalled as false. 并且每次创建活动时,我都会将onResumeCalled保留为false。

In onResume(), I set a check 在onResume()中,我设置了一个检查

if(!onResumeCalled)

in the start of onResume(). 在onResume()的开头。

Now, when the activity is created, onResumeCalled is false. 现在,当创建活动时,onResumeCalled为false。 Then, once the methods inside onResume() are called, I change the value of onResumeCalled to true, so that the second time when onResume() is called, the methods inside onResume() will not be accessed because the value of onResumeCalled is now true. 然后,一旦调用了onResume()内部的方法,我便将onResumeCalled的值更改为true,以便第二次调用onResume()时将不再访问onResume()内部的方法,因为现在onResumeCalled的值真正。

I found here some reason of that behaviour on Android. 我在这里找到在Android上发生这种行为的一些原因。 For me this was the reason. 对我来说,这就是原因。

onPause-onResume-onPause-onResume just happens every time, when app is starting first time after installation. 在安装后首次启动应用程序时,onPause-onResume-onPause-onResume只会在每次发生。 You can simply invoke this behavior by doing any change in code and rerunning (which includes recompiling) the app from your IDE. 您可以通过在代码中进行任何更改并从IDE重新运行(包括重新编译)应用程序来简单地调用此行为。

No matter if you use AppCompat libs or not. 无论您是否使用AppCompat库。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM