横竖屏切换时,activity数据保存问题

文章详细介绍了Android中onSaveInstanceState和onRestoreInstanceState方法的作用,它们在Activity被系统销毁时保存和恢复状态的场景,如用户按下HOME键、屏幕旋转等。文章还提供了保存和恢复数据的示例代码,并分析了这两个方法的源码,展示了View如何保存和恢复状态。最后,通过一个例子展示了横竖屏切换时方法的调用顺序和数据恢复过程。
摘要由CSDN通过智能技术生成

1. onSaveInstanceState简介
如果系统由于系统约束(而不是正常的应用程序行为)而破坏了Activity,那么尽管实际 Activity实例已经消失,但是系统还是会记住它已经存在,这样如果用户导航回到它,系统会创建一个新的实例的Activity使用一组保存的数据来描述Activity在被销毁时的状态。系统用于恢复以前状态的已保存数据称为“实例状态”,是存储在Bundle对象中的键值对的集合。

1.1 onSaveInstanceState简介
a. onSaveInstanceState(Bundle outState)
保存Acticivity被销毁前的状态:在离开页面的时候用onSaveInstanceState中的outState可以保存你所需要的值
b. onRestoreInstanceState(Bundle savedInstanceState)
恢复Acticivity被销毁前的状态:在重新回到该页面的时候可以使用onRestoreInstanceState从saveInstanceState中获取保存过得值来重新初始化界面
onSaveInstanceState是在OnStop之前执行,onRestoreInstanceState在OnStart后执行
注意:onSaveInstanceState()是用来保存UI状态,onPause()适合用于数据的持久化保存

1.2 onSaveInstanceState被调用的情况
1.2.1 onSaveInstanceState什么时候会被调用
a. 当用户按下HOME键
b. 长按HOME键,选择运行其他的程序
c. 按下电源按键(关闭屏幕显示)
d. 从activity A中启动一个新的activity
e. 屏幕方向切换时,例如从竖屏切换到横屏
在屏幕切换之前,系统会销毁activity A,在屏幕切换之后系统又会自动地创建activity A,所以onSaveInstanceState一定会被执行
注意:当用户主动去销毁一个Activity时,例如在应用中按返回键,onSaveInstanceState()就不会被调用。因为在这种情况下,用户的行为决定了不需要保存Activity的状态
1.2.2 onRestoreInstanceState什么时候会被调用
onRestoreInstanceState被调用的前提:Activity确实被系统销毁了,并不是和onSaveInstanceState成对出现
例如,当正在显示activity A的时候,用户按下HOME键回到主界面,然后用户紧接着又返回到activity A,这种情况下activity A一般不会因为内存的原因被系统销毁,故activity A的onRestoreInstanceState方法不会被执行

2. onSaveInstanceState使用方法
2.1 保存销毁前状态

@Override
public void onSaveInstanceState(Bundle outState) {
	outState.putInt("newsCenter_position", newsCenterPosition);
	outState.putInt("smartService_position", smartServicePosition);
	outState.putInt("govAffairs_position", govAffairsPosition);
	super.onSaveInstanceState(outState);
}

2.2 恢复销毁前状态

a. 恢复销毁前保存的数据

@Override
public void onCreate(Bundle savedInstanceState) {
	if (savedInstanceState != null && savedInstanceState.containsKey("newsCenter_position")) {
		newsCenterPosition   = savedInstanceState.getInt("newsCenter_position");
		smartServicePosition = savedInstanceState.getInt("smartService_position");
		govAffairsPosition   = savedInstanceState.getInt("govAffairs_position");
	}
    super.onCreate(savedInstanceState);
}

b. 根据保存的数据恢复销毁前的状态

public void switchMenu(int type) {
	switch (type) {
		case NEWS_CENTER:
			if (newsCenterAdapter == null) {
				newsCenterAdapter = new MenuAdapter(ct, newsCenterMenu);
				newsCenterclassifyLv.setAdapter(newsCenterAdapter);
			} else {
				newsCenterAdapter.notifyDataSetChanged();
			}
			newsCenterAdapter.setSelectedPosition(newsCenterPosition);
			break;
		case SMART_SERVICE:
			if (smartServiceAdapter == null) {
				smartServiceAdapter = new MenuAdapter(ct, smartServiceMenu);
				smartServiceclassifyLv.setAdapter(smartServiceAdapter);
			} else {
				smartServiceAdapter.notifyDataSetChanged();
			}
			smartServiceAdapter.setSelectedPosition(smartServicePosition);
			break;
		case GOV_AFFAIRS:
			if (govAffairsAdapter == null) {
				govAffairsAdapter = new MenuAdapter(ct, govAffairsMenu);
				govAffairsclassifyLv.setAdapter(govAffairsAdapter);
			} else {
				govAffairsAdapter.notifyDataSetChanged();
			}
			govAffairsAdapter.setSelectedPosition(govAffairsPosition);
			break;
	}
}

3. onSaveInstanceState源码分析

3.1 onSaveInstanceState源码分析

MainActivity.java:
@Override
public void onSaveInstanceState(Bundle outState) {
	super.onSaveInstanceState(outState);
	outState.putString("octopus", "www.baidu.com");
}

Activity.java (frameworks\base\core\java\android\app)	321500	2017/8/25
public class Activity extends ContextThemeWrapper
        implements LayoutInflater.Factory2,
        Window.Callback, KeyEvent.Callback,
        OnCreateContextMenuListener, ComponentCallbacks2,
        Window.OnWindowDismissedCallback, WindowControllerCallback,
        AutofillManager.AutofillClient {
    protected void onSaveInstanceState(Bundle outState) {
        outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());

        outState.putInt(LAST_AUTOFILL_ID, mLastAutofillId);
        Parcelable p = mFragments.saveAllState();
        if (p != null) {
            outState.putParcelable(FRAGMENTS_TAG, p);
        }
        if (mAutoFillResetNeeded) {
            outState.putBoolean(AUTOFILL_RESET_NEEDED, true);
            getAutofillManager().onSaveInstanceState(outState);
        }
        getApplication().dispatchActivitySaveInstanceState(this, outState);
    }
}

PhoneWindow.java (frameworks\base\core\java\com\android\internal\policy)	143971	2017/8/25
public class PhoneWindow extends Window implements MenuBuilder.Callback {
    @Override
    public Bundle saveHierarchyState() {
        Bundle outState = new Bundle();
        if (mContentParent == null) {
            return outState;
        }

        SparseArray<Parcelable> states = new SparseArray<Parcelable>();
        mContentParent.saveHierarchyState(states);
        outState.putSparseParcelableArray(VIEWS_TAG, states);

        // Save the focused view ID.
        final View focusedView = mContentParent.findFocus();
        if (focusedView != null && focusedView.getId() != View.NO_ID) {
            outState.putInt(FOCUSED_ID_TAG, focusedView.getId());
        }

        // save the panels
        SparseArray<Parcelable> panelStates = new SparseArray<Parcelable>();
        savePanelState(panelStates);
        if (panelStates.size() > 0) {
            outState.putSparseParcelableArray(PANELS_TAG, panelStates);
        }

        if (mDecorContentParent != null) {
            SparseArray<Parcelable> actionBarStates = new SparseArray<Parcelable>();
            mDecorContentParent.saveToolbarHierarchyState(actionBarStates);
            outState.putSparseParcelableArray(ACTION_BAR_TAG, actionBarStates);
        }

        return outState;
    }
}

View.java (frameworks\base\core\java\android\view)	1045455	2017/8/25
public class View implements Drawable.Callback, KeyEvent.Callback,
        AccessibilityEventSource {
    public void saveHierarchyState(SparseArray<Parcelable> container) {
        dispatchSaveInstanceState(container);
    }
    protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
        if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) {  //mID用来指定当前view的id,如果view没有指定id则默认为NO_ID
            mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
            Parcelable state = onSaveInstanceState();					//保存view当前的状态到state
            if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) {
                throw new IllegalStateException(
                        "Derived class did not call super.onSaveInstanceState()");
            }
            if (state != null) {
                // Log.i("View", "Freezing #" + Integer.toHexString(mID)
                // + ": " + state);
                container.put(mID, state);	//将view的状态state以键值对的形式和mID绑定,并保存到SparseArray中
            }
        }
    }
}

onSaveInstanceState分析结论:
view会调用onSaveInstanceState保存当前状态state,并将view的状态state以键值对的形式和mID绑定,并保存到SparseArray中

3.2 onRestoreInstanceState源码分析

View.java (frameworks\base\core\java\android\view)	1045455	2017/8/25
public class View implements Drawable.Callback, KeyEvent.Callback,
        AccessibilityEventSource {
    public void restoreHierarchyState(SparseArray<Parcelable> container) {
        dispatchRestoreInstanceState(container);
    }
    protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
        if (mID != NO_ID) {
            Parcelable state = container.get(mID);	//根据mID从SparseArray中取出当前view的状态state
            if (state != null) {
                // Log.i("View", "Restoreing #" + Integer.toHexString(mID)
                // + ": " + state);
                mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
                onRestoreInstanceState(state);		//调用View.onRestoreInstanceState恢复当前view的状态
                if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) {
                    throw new IllegalStateException(
                            "Derived class did not call super.onRestoreInstanceState()");
                }
            }
        }
    }
    @CallSuper
    protected void onRestoreInstanceState(Parcelable state) {
        mPrivateFlags |= PFLAG_SAVE_STATE_CALLED;
        if (state != null && !(state instanceof AbsSavedState)) {
            throw new IllegalArgumentException("Wrong state class, expecting View State but "
                    + "received " + state.getClass().toString() + " instead. This usually happens "
                    + "when two views of different type have the same id in the same hierarchy. "
                    + "This view's id is " + ViewDebug.resolveId(mContext, getId()) + ". Make sure "
                    + "other views do not use the same id.");
        }
        if (state != null && state instanceof BaseSavedState) {
            BaseSavedState baseState = (BaseSavedState) state;

            if ((baseState.mSavedData & BaseSavedState.START_ACTIVITY_REQUESTED_WHO_SAVED) != 0) {
                mStartActivityRequestWho = baseState.mStartActivityRequestWhoSaved;
            }
            if ((baseState.mSavedData & BaseSavedState.IS_AUTOFILLED) != 0) {
                setAutofilled(baseState.mIsAutofilled);
            }
            if ((baseState.mSavedData & BaseSavedState.AUTOFILL_ID) != 0) {
                mAutofillViewId = baseState.mAutofillViewId;
            }
        }
    }
}

onRestoreInstanceState分析结论:
view根据mID从SparseArray中取出当前view的状态state,并调用View.onRestoreInstanceState恢复当前view的状态

4. 用法总结

public class MainActivity extends Activity {  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
        if(savedInstanceState != null)  
            System.out.println("onCreate() : " + savedInstanceState.getString("octopus"));  
    }  
    @Override  
    protected void onRestoreInstanceState(Bundle savedInstanceState) {  
        super.onRestoreInstanceState(savedInstanceState);  
        System.out.println("onRestoreInstanceState() : " + savedInstanceState.getString("octopus"));  
    }  
    @Override  
    protected void onSaveInstanceState(Bundle outState) {  
        super.onSaveInstanceState(outState);  
          
        outState.putString("octopus", "www.baidu.com");  
        System.out.println("onSaveInstanceState() : save date www.baidu.com");  
    }  
}

横竖屏切换,打印结果如下:

I/System.out( 8167): onSaveInstanceState() : save date www.baidu.com
I/System.out( 8167): onCreate() : www.baidu.com
I/System.out( 8167): onRestoreInstanceState() : www.baidu.com

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值