Android Framework切换主题后应用Activity生命周期变化分析

零.前言

​   在工作遇到了系统切换主题后,应用页面出现重叠错乱,播放音频的时候出现了点击图标后出现声音停顿1S

后继续播放的问题…

一.生命周期流程

在这里插入图片描述
  此时,Activity经历了销毁到创建,状态保存到恢复状态的过程,不同的手机有一定的差别。

二.源码分析(Android M)

 protected void onSaveInstanceState(Bundle outState) {
    
    
        outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState()); // 保存Window
        Parcelable p = mFragments.saveAllState();
        if (p != null) {
    
    
            outState.putParcelable(FRAGMENTS_TAG, p);// 保存Fragment
        }
        getApplication().dispatchActivitySaveInstanceState(this, outState);
 }
  protected void onRestoreInstanceState(Bundle savedInstanceState) {
    
    
        if (mWindow != null) {
    
    
            Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG);
            if (windowState != null) {
    
    
                mWindow.restoreHierarchyState(windowState);// 恢复Window
            }
        }
 }
  protected void onCreate(@Nullable Bundle savedInstanceState) {
    
    
        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onCreate " + this + ": " + savedInstanceState);
        if (mLastNonConfigurationInstances != null) {
    
    
            mFragments.restoreLoaderNonConfig(mLastNonConfigurationInstances.loaders);
        }
        if (mActivityInfo.parentActivityName != null) {
    
    
            if (mActionBar == null) {
    
    
                mEnableDefaultActionBarUp = true;
            } else {
    
    
                mActionBar.setDefaultDisplayHomeAsUpEnabled(true);
            }
        }
        // 恢复Fragment
        if (savedInstanceState != null) {
    
    
            Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
            mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
                    ? mLastNonConfigurationInstances.fragments : null);
        }
        mFragments.dispatchCreate();
        getApplication().dispatchActivityCreated(this, savedInstanceState);
        if (mVoiceInteractor != null) {
    
    
            mVoiceInteractor.attachActivity(this);
        }
        mCalled = true;
  }

三.引起的Fragment页面重叠错乱问题

​    1.原因:在activity onSaveInstanceState执行时activity保存了Window和Fragment的状态

​        onCreate时我们初始化并添加Fragment

​       onCreate和onRestoreInstanceState时恢复了保存的Fragment,综上造成了Fragment
页面重叠错乱

​    2.解决方式:

​     (1).如果在切换主题后没有必要恢复我们应用之前的状态,可以在onSaveInstanceState时直接不保存Fragment状态即可

   static final String FRAGMENTS_TAG = "android:fragments";
    @Override
    protected void onSaveInstanceState(Bundle outState) {
    
    
        super.onSaveInstanceState(outState);
        outState.putParcelable(FRAGMENTS_TAG, null);// 不保存Fragment状态
    }

​ ​      (2).如果需要恢复我们应用之前的状态,可以通过FragmentManager找到保存的Fragment进行复用

    private void showFragment(int index) {
    
    
        FragmentTransaction ft = getSupportFragmentManager().beginTransaction();
        // 找到保存的Fragment进行复用。
        Fragment fragmentByTag = getSupportFragmentManager().findFragmentByTag(TAGS[index]);
        // 执行了onDestory后mFragments数组对象被系统回收了
        if (fragmentByTag != null && mFragments[index] == null) {
    
    
            mFragments[index] = (AbstractMainFragment) fragmentByTag;
        }
        if (mFragments[index] == null) {
    
    
            if (index == PLAYBACK) {
    
    
                mFragments[index] = new PlaybackFragment();
            } else if (index == LIBRARY) {
    
    
                mFragments[index] = new LibraryFragment();
            } else {
    
    
                mFragments[index] = new MixFragment();
            }
            ft.add(R.id.fl_main, mFragments[index], TAGS[index]);
        }
        for (int i = 0; i < mFragments.length; i++) {
    
    
            if (mFragments[i] != null && i != index) {
    
    
                ft.hide(mFragments[i]);
            }
        }
        ft.show(mFragments[index]).commitAllowingStateLoss();
        mCurrentTab = index;
    }

四.API说明

​   其实相应方法的API说明介绍的很清楚,要多看API( ̄. ̄)

/**
 * Called when the activity is starting.  This is where most initialization
 * should go: calling {@link #setContentView(int)} to inflate the
 * activity's UI, using {@link #findViewById} to programmatically interact
 * with widgets in the UI, calling
 * {@link #managedQuery(android.net.Uri , String[], String, String[], String)} to retrieve
 * cursors for data being displayed, etc.
 *
 * <p>You can call {@link #finish} from within this function, in
 * which case onDestroy() will be immediately called without any of the rest
 * of the activity lifecycle ({@link #onStart}, {@link #onResume},
 * {@link #onPause}, etc) executing.
 *
 * <p><em>Derived classes must call through to the super class's
 * implementation of this method.  If they do not, an exception will be
 * thrown.</em></p>
 *
 * @param savedInstanceState If the activity is being re-initialized after
 *     previously being shut down then this Bundle contains the data it most
 *     recently supplied in {@link #onSaveInstanceState}.  <b><i>Note: Otherwise it is null.</i></b>
 *
 * @see #onStart
 * @see #onSaveInstanceState
 * @see #onRestoreInstanceState
 * @see #onPostCreate
 */
protected void onCreate(@Nullable Bundle savedInstanceState) {}
/**
 * Called to retrieve per-instance state from an activity before being killed
 *      * so that the state can be restored in {@link #onCreate} or
 *      * {@link #onRestoreInstanceState} (the {@link Bundle} populated by this method
 *      * will be passed to both).
 *
 * <p>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.  For example,
 * if activity B is launched in front of activity A, and at some point activity
 * A is killed to reclaim resources, activity A will have a chance to save the
 * current state of its user interface via this method so that when the user
 * returns to activity A, the state of the user interface can be restored
 * via {@link #onCreate} or {@link #onRestoreInstanceState}.
 *
 * <p>Do not confuse this method with activity lifecycle callbacks such as
 * {@link #onPause}, which is always called when an activity is being placed
 * in the background or on its way to destruction, or {@link #onStop} which
 * is called before destruction.  One example of when {@link #onPause} and
 * {@link #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 {@link #onSaveInstanceState}
 * on B because that particular instance will never be restored, so the
 * system avoids calling it.  An example when {@link #onPause} is called and
 * not {@link #onSaveInstanceState} is when activity B is launched in front of activity A:
 * the system may avoid calling {@link #onSaveInstanceState} 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.
 *
 * <p>The default implementation takes care of most of the UI per-instance
 * state for you by calling {@link android.view.View#onSaveInstanceState()} on each
 * view in the hierarchy that has an id, and by saving the id of the currently
 * focused view (all of which is restored by the default implementation of
 * {@link #onRestoreInstanceState}).  If you override this method to save additional
 * information not captured by each individual view, you will likely want to
 * call through to the default implementation, otherwise be prepared to save
 * all of the state of each view yourself.
 *
 * <p>If called, this method will occur before {@link #onStop}.  There are
 * no guarantees about whether it will occur before or after {@link #onPause}.
 *
 * @param outState Bundle in which to place your saved state.
 *
 * @see #onCreate
 * @see #onRestoreInstanceState
 * @see #onPause
 */
protected void onSaveInstanceState(Bundle outState) {}
/**
 * This method is called after {@link #onStart} when the activity is
 * being re-initialized from a previously saved state, given here in
 * <var>savedInstanceState</var>.  Most implementations will simply use {@link #onCreate}
 * to restore their state, but it is sometimes convenient to do it here
 * after all of the initialization has been done or to allow subclasses to
 * decide whether to use your default implementation.  The default
 * implementation of this method performs a restore of any view state that
 * had previously been frozen by {@link #onSaveInstanceState}.
 *
 * <p>This method is called between {@link #onStart} and
 * {@link #onPostCreate}.
 *
 * @param savedInstanceState the data most recently supplied in {@link #onSaveInstanceState}.
 *
 * @see #onCreate
 * @see #onPostCreate
 * @see #onResume
 * @see #onSaveInstanceState
 */
protected void onRestoreInstanceState(Bundle savedInstanceState) { }

猜你喜欢

转载自blog.csdn.net/wangadping/article/details/108458151