Android源码分析 - onSaveInstanceState、onRestoreInstanceState 状态保存与恢复

本文详细分析了Android8.0源码中onSaveInstanceState的调用过程,解释了在Activity的生命周期中何时会触发该方法,以及保存的数据内容和去向。在暂停、停止和销毁Activity时,系统都会尝试保存状态,这些状态信息最终存储在AMS的内存中,用于后续Activity的恢复。此外,文章还讨论了如何通过onSaveInstanceState保存额外数据,并提供了实验示例验证回调顺序和数据恢复过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

本文基于 Android8.0 源码

0. 相关分享

Android源码分析 - Parcel 与 Parcelable

Android特别的数据结构(二)ArrayMap源码解析

Android源码分析 —— Activity栈管理(基于Android8)

Android-全面理解Binder原理

Android从屏幕刷新到View的绘制(一)之 Window、WindowManager和WindowManagerService之间的关系

1. 何时会调用 onSaveInstanceState?

onSaveInstanceState(Bundle savedInstance) 是 Android 用来保存一些异常情况下(例如由横竖屏切换等)而导致 Activity 销毁的数据。通过这个方式来保持 Activity 状态的方式,可以在下次再次打开此 Activity 时恢复数据。当然,如果用户主动返回,例如 finish() 掉 Activity,或者按了 Home键,这是不会走 onSaveInstanceState() 方法的。

我们从源码的角度来看一下是在哪里发起 onSaveInstance() 的,来到 ActivityThread.java,AMS(ActivityManagerService)通过ApplicationThread给APP进程发送通知,调度Activity,关于Activity销毁,可能会走 onPause(),onStop(),onDestroy()。在performPauseActivity()和performStopActivity()中,在异常退出的情况下,会回调 onSaveInstanceState()进行状态保存.

1.1 handlePauseActivity() -> performPauseActivity()

//ActivityThread.java
final Bundle performPauseActivity(ActivityClientRecord r, boolean finished,boolean saveState, String reason) {
    //...
    //如果finished为true,说明是用户主动退出的Activity,例如finish()方法,或者按了Home键。
    if (finished) {
        r.activity.mFinished = true;
    }
	
    if (!r.activity.mFinished && saveState) {
        //如果不是用户主动发起关闭的,而且需要保存状态,就调用保存方法
        callCallActivityOnSaveInstanceState(r);
    }
	//回调Activity的onPause()方法
    performPauseActivityIfNeeded(r, reason);
	//...
    return !r.activity.mFinished && saveState ? r.state : null;
}

private void performPauseActivityIfNeeded(ActivityClientRecord r, String reason) {
    if (r.paused) {
        //如果已经pause了,不用再回调onPause()了
        return;
    }
    try {
        r.activity.mCalled = false;
        //通过Instrumentation回调Activity组件的onPause()方法
        mInstrumentation.callActivityOnPause(r.activity);
    } catch (Exception e) {
        throw e;
    }
    r.paused = true;
}

可以看到,当 ActivityThread.java 收到对某个 Activity 的onPause()请求时,首先会判断 finished 变量,它表示了 Activity 是用户主动退出的,还是尤其其他情况导致的onPaused。如果是因为后者,也就是异常因素,就会进入到 callCallActivityOnSaveInstanceState(r) 方法保存状态,然后再进入到 Activity 的 onPause() 回调。

关注到 callCallActivityOnSaveInstanceState() 的内容:

//ActivityThread.java
private void callCallActivityOnSaveInstanceState(ActivityClientRecord r) {
    //将数据存到 Bundle 中
    r.state = new Bundle();
    r.state.setAllowFds(false);
    //这个 persistable 是在配置文件中可以设置的属性,这个是持久化存储的能力,可以实现系统关机后重启的数据恢复能力。而普通的 savedInstanceState 只是存在了系统的内存中。
    if (r.isPersistable()) {
        r.persistentState = new PersistableBundle();
        mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state,
                                                         r.persistentState);
    } else {
        mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);
    }
}

其中,persistable是Android 5.0 提供的新的配置,在Manifest配置文件中,可以为 Activity 设置一个属性

android:persistableMode="persistAcrossReboots|persistRootOnly|persistNever"
  • persistNever:总不起作用
  • persistRootOnly:默认值,当ActivityRecord是TaskRecord的最底层时生效。
  • persistAcrossReboots:标志了的Activity都会进行持久化状态数据保存。如果所在TaskRecord之上的ActivityRecord也设置了这个值,同时也会被持久化。

如果设置了这个值,在保存状态信息的时候除了保存在 r.state 这个 Bundle对象里,还会保存在 r.persistentState 这个 PersistableBundle对象中。简单来看一下是如何持久化存储的,显然要通过文件存储:

//PersistableBundle
public void saveToXml(XmlSerializer out) throws IOException, XmlPullParserException {
    unparcel();
    XmlUtils.writeMapXml(mMap, out, this);
}

public static PersistableBundle restoreFromXml(XmlPullParser in) throws IOException,
XmlPullParserException {
    final int outerDepth = in.getDepth();
    final String startTag = in.getName();
    final String[] tagName = new String[1];
    int event;
    while (((event = in.next()) != XmlPullParser.END_DOCUMENT) &&
           (event != XmlPullParser.END_TAG || in.getDepth() < outerDepth)) {
        if (event == XmlPullParser.START_TAG) {
            return new PersistableBundle((ArrayMap<String, Object>)
                                         XmlUtils.readThisArrayMapXml(in, startTag, tagName,
                                                                      new MyReadMapCallback()));
        }
    }
    return EMPTY;
}

@Override
public void writeUnknownObject(Object v, String name, XmlSerializer out)
    throws XmlPullParserException, IOException {
    if (v instanceof PersistableBundle) {
        out.startTag(null, TAG_PERSISTABLEMAP);
        out.attribute(null, "name", name);
        ((PersistableBundle) v).saveToXml(out);
        out.endTag(null, TAG_PERSISTABLEMAP);
    } else {
        throw new XmlPullParserException("Unknown Object o=" + v);
    }
}

查看到其源码,发现是通过xml文件来进行的数据持久化存储。它相比Bundle额外实现了 XmlUtils.WriteMapCallback 接口。

1.2 handleStopActivity() -> performStopActivityInner()

三个结束Activity的生命周期中,都有保存状态的尝试,onStop也不例外。

//ActivityThread.java
private void performStopActivityInner(ActivityClientRecord r,StopInfo info, boolean keepShown, boolean saveState, String reason) {
    //...
    if (r != null) {
        //如果stop的时候发现activity连pause都还没有,会先进行pause,然后继续stop任务
        performPauseActivityIfNeeded(r, reason);
        //尝试保存状态信息
        if (!r.activity.mFinished && saveState) {
            if (r.state == null) {
                //如果不是用户主动退出的Activity,且之前没有保存过状态信息,这里会调用 onSaveInstanceState()进行保存。
                callCallActivityOnSaveInstanceState(r);
            }
        }
		//如果仍然可见,但是位于下方,则不会调用onStop
        if (!keepShown) {
            try {
                //回调onStop()方法
                r.activity.performStop(false /*preserveWindow*/);
            } catch (Exception e) {
                //...
            }
            r.stopped = true;   
        }
    }
}

这里和onPause生命周期类似,都会尝试对状态信息进行保存。不同的是,如果之前已经保存过状态信息了(performPauseActivity()中已经保存过了),这里就不会再次保存,浪费资源。

1.3 handleDestroyActivity() -> performDestroyActivity()

在Destroy()的回调过程中,并没有执行状态保存,只是健壮性判断,如果之前没有调用过pause或者stop,就会调用,而在pause和stop过程中,就已经有过状态保存了。

在 handleDestroyActivity() 中,首先调用了 performDestroyActivity(),之后就开始了Activity的关闭,与WMS通信,通知当前ActivityWindow的关闭。接下来也会通过 ActivityManager.getService().activityDestroyed(token) 通知 AMS,同时将状态数据(ActivityClientRecord的数据)回传给AMS(中的ActivityRecord)

//ActivityThread.java
private ActivityClientRecord performDestroyActivity(IBinder token, boolean finishing,
            int configChanges, boolean getNonConfigInstance) {
    if (finishing) {
        r.activity.mFinished = true;
    }
	//如果还没pause,先pause
    performPauseActivityIfNeeded(r, "destroy");
    //如果还没stop,先stop
    r.activity.performStop(r.mPreserveWindow);
    //最后回调onDestory
    mInstrumentation.callActivityOnDestroy(r.activity);
}

也就是说,只要Activity要进行关闭,不论到stop还是Destroy,都会先尝试将pause的情况走完,也就是总会调用到 performPauseActivity(),而其中也总会尝试将state状态数据进行保存。

2. onSaveInstanceState 存了什么内容?

上文可以看到,最后通过Instrumentation发起了Activity的 onSaveInstanceState() , 它最终会保存:

  1. Window下,有id且需要保存数据的View的数据信息
  2. Fragment数据信息
  3. Dialog数据信息
  4. 其他数据信息

我们首先看到调用入口 callCallActivityOnSaveInstanceState()

//ActivityThread.java
private void callCallActivityOnSaveInstanceState(ActivityClientRecord r) {
    r.state = new Bundle();
    r.state.setAllowFds(false);
    if (r.isPersistable()) {
        r.persistentState = new PersistableBundle();
        mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state,
                                                         r.persistentState);
    } else {
        mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);
    }
}
//Instrumentation.java
public void callActivityOnSaveInstanceState(Activity activity, Bundle outState) {
    activity.performSaveInstanceState(outState);
}

接下来就来到了Activity的 performSaveInstanceState()

//Activity.java
final void performSaveInstanceState(Bundle outState) {
    //保存窗口信息、以及Fragment信息
    onSaveInstanceState(outState);
    //通知所有Dialog进行状态保存
    saveManagedDialogs(outState);
    mActivityTransitionState.saveState(outState);
    storeHasCurrentPermissionRequest(outState);
}

protected void onSaveInstanceState(Bundle outState) {
    //保存窗口信息(保存View)
    outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
    outState.putInt(LAST_AUTOFILL_ID, mLastAutofillId);
    //保存所有Fragmet信息
    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);
}

我们主要关注保存了哪些数据,首先看到 mWindow.saveHierarchyState(),Activity的Window只有PhoneWindow实现,我们直接看到PhoneWindow:

//PhoneWindow.java

//这个是window content,要么是DecorView(没设置setContentView(),默认DecorView),要么是DecorView的孩子(setContentView())
ViewGroup mContentParent;

@Override
public Bundle saveHierarchyState() {
    Bundle outState = new Bundle();
    if (mContentParent == null) {
        return outState;
    }
	//SparseArray来临时保存信息,这是一种Key为integer类型,Value为任意类型的数据结构,是Google为Android设计的内存优化的数据结构。
    SparseArray<Parcelable> states = new SparseArray<Parcelable>();
    //来到了ViewGroup的保存,显然这里只会保存DecorView,或者setContentView设置的视图
    mContentParent.saveHierarchyState(states);
    //包存到outState中
    outState.putSparseParcelableArray(VIEWS_TAG, states);

    //还需要保存获得焦点的是哪个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);
    }
	//ToolBar的信息也要保存
    if (mDecorContentParent != null) {
        SparseArray<Parcelable> actionBarStates = new SparseArray<Parcelable>();
        mDecorContentParent.saveToolbarHierarchyState(actionBarStates);
        outState.putSparseParcelableArray(ACTION_BAR_TAG, actionBarStates);
    }

    return outState;
}

PhoneWindow会保存View的数据、Panel的数据、ToolBar的数据。我们关注到View数据的保存。它首先会通过 ViewGroup,这个要么是 DecorView,要么是用户通过 setContentView() 设置的一个 ViewGroup,调用其 mContentParent.saveHierarchyState(),这在 View.java 中实现:

//View.java
public void saveHierarchyState(SparseArray<Parcelable> container) {
    dispatchSaveInstanceState(container);
}

protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
    //只要View有id,并且没有取消状态保存的标志,就可以被保存
    if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) {
        //回调View的onSaveInstanceState()
        Parcelable state = onSaveInstanceState();
       
        if (state != null) {
            //将结果放到container中
            container.put(mID, state);
        }
    }
}

对于View本身而言,就是通过onSaveInstanceState()保存自身的状态,但是只看View.java本身的代码并没有保存什么信息,通常View级别的子类会将保存逻辑写在重写的onSaveInstanceState()中。我们关注到它的实现类,例如TextView:

//TextView.java
@Override
public Parcelable onSaveInstanceState() {
    //先调用父类View的onSaveInstanceState()方法,拿到一个Parcelable
    Parcelable superState = super.onSaveInstanceState();
	//这个boolean来自配置文件的 freezesText 标签设置
    final boolean freezesText = getFreezesText();
    boolean hasSelection = false;
    int start = -1;
    int end = -1;

    //CharSequence类型的mText
    if (mText != null) {
        //如果有选择的起始点、终止点,说明之前有光标,记录光标和选中状态
        start = getSelectionStart();
        end = getSelectionEnd();
        if (start >= 0 || end >= 0) {
            hasSelection = true;
        }
    }
	//如果设置了freezesText标志,或者有选中状态,就进行文字的状态保存
    if (freezesText || hasSelection) {
        SavedState ss = new SavedState(superState);

        if (freezesText) {
            //如果是富文本的内容,按富文本的方式进行保存
            if (mText instanceof Spanned) {
                final Spannable sp = new SpannableStringBuilder(mText);

                if (mEditor != null) {
                    removeMisspelledSpans(sp);
                    sp.removeSpan(mEditor.mSuggestionRangeSpan);
                }

                ss.text = sp;
            } else {
                //如果是普通文本,直接存为String类型
                ss.text = mText.toString();
            }
        }

        //保存光标信息
        if (hasSelection) {
            ss.selStart = start;
            ss.selEnd = end;
        }

        if (isFocused() && start >= 0 && end >= 0) {
            ss.frozenWithFocus = true;
        }

        ss.error = getError();

        if (mEditor != null) {
            //如果有编辑器,同时也记录编辑器的状态信息
            ss.editorState = mEditor.saveInstanceState();
        }
        return ss;
    }

    return superState;
}

TextView的状态存储,首先调用了父类View的默认onSaveInstanceState()实现,然后将自己的数据填入其中,包括文本信息、光标选中状态、编辑器Editor。

View的子类ViewGroup则是重写了dispatchSaveInstanceState()方法,就是收集其下所有子View的状态,进行综合保存。

@Override
protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
    super.dispatchSaveInstanceState(container);
    final int count = mChildrenCount;
    final View[] children = mChildren;
    for (int i = 0; i < count; i++) {
        View c = children[i];
        if ((c.mViewFlags & PARENT_SAVE_DISABLED_MASK) != PARENT_SAVE_DISABLED) {
            c.dispatchSaveInstanceState(container);
        }
    }
}

3. 保存的数据何去何从?

显然保存的数据存在Bundle中的,Bundle实现了Parcelable接口,我们能猜到最终这个数据会包存到某个内存中。继续猜测,APP进程可能会被杀,而且Activity的发起实际是通过AMS,我们也能够猜到这个数据是存在AMS所在进程的内存空间中。后续代码跟踪也证实了这一点:

  • 保存的数据存在AMS所在进程(SystemServer)的内存空间中(写在ActivityRecord中)。
  • 启动Activity的时候,可以通过binder通信,将保存的数据传递回去。

我们回顾到最初发起 onSaveInstanceState 的地方:

//ActivityThread.java
private void callCallActivityOnSaveInstanceState(ActivityClientRecord r) {
    r.state = new Bundle();
    r.state.setAllowFds(false);
    if (r.isPersistable()) {
        r.persistentState = new PersistableBundle();
        mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state,
                                                         r.persistentState);
    } else {
        mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);
    }
}

显然,我们最终将所有状态信息写到了这个 ActivityClientRecord 对象中。最后通过AMS上报生命周期状态(同时也上报了状态信息)

//ActivityThread.java
private void handlePauseActivity(IBinder token, boolean finished,
            boolean userLeaving, int configChanges, boolean dontReport, int seq) {
    //...
    ActivityClientRecord r = mActivities.get(token);
    //...
    performPauseActivity(token, finished, r.isPreHoneycomb(), "handlePauseActivity");
    //...
    ActivityManager.getService().activityPaused(token);
}

可以看到,最后将存储后的内容交给了AMS,所有的信息保存在了AMS的ActivityRecord之中。假设Activity所在的进程被杀了,或者旋转屏幕了,再次启动这个Activity的时候,AMS复用之前的ActivityRecord,并从其中得到之前保存的数据。换句话说,存的这些状态数据,保存在了SystemServer进程中。

留存疑问,如果Activity的启动模式是SingleTask,是否会复用之前的ActivityRecord?如果是,那么保存的状态信息是否丢失了?

4. 保存的数据通过 onRestoreInstanceState() 进行恢复

Activity的 onRestoreInstanceState()方法,在ActivityThread.java中,通过 performLaunchActivity() 方法进行回调:

//ActivityThread.java
private Activity performLaunchActivity(ActivityClientRecord r, Intent customIntent) {
    //1.activity.attach主要是创建Window
    activity.attach(...);
    //2.activity.onCreat(),分为是否persistable
    if(r.isPersistable()){
        mInstrumentation.callActivityOnCreate(activity, r.state, r.persistentState);
    }else{
        mInstrumentation.callActivityOnCreate(activity, r.state);
    }
    //onStart()方法
    if (!r.activity.mFinished) {
        activity.performStart();
        r.stopped = false;
    }
    //r.state!=null的话,说明之前异常退出,会回调onRestoreInstanceState()
    if(!r.activity.mFinished){
        if (r.isPersistable()) {
            if (r.state != null || r.persistentState != null) {
                mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state,
                                                                    r.persistentState);
            }
        } else if (r.state != null) {
            mInstrumentation.callActivityOnRestoreInstanceState(activity, r.state);
        }
    }
}

如果这个Activity是第一次进入,之前并没有异常退出,那么r.state就是空的,调用到 onCreate() 时传入的 Bundle savedInstanceState 也就是空的。同样的,如果之前没有异常退出,r.persistentState也是空的。

如果之前异常退出了(或者屏幕旋转了),那么r.state就非空,在onCreate()中可以获取到其内容,接下来也将回调 onRestoreInstanceState()

onRestoreInstanceState() 默认实现是恢复window的信息:

//Activity.java
protected void onRestoreInstanceState(Bundle savedInstanceState) {
    if (mWindow != null) {
        Bundle windowState = savedInstanceState.getBundle(WINDOW_HIERARCHY_TAG);
        if (windowState != null) {
            //恢复window
            mWindow.restoreHierarchyState(windowState);
        }
    }
}

PhoneWindow.restoreHierarchyState()也是通过DecorView或者ViewGroup来进行视图数据恢复:

//PhoneWindow.java
@Override
public void restoreHierarchyState(Bundle savedInstanceState) {
    if (mContentParent == null) {
        return;
    }

    SparseArray<Parcelable> savedStates
        = savedInstanceState.getSparseParcelableArray(VIEWS_TAG);
    if (savedStates != null) {
        //View数据恢复
        mContentParent.restoreHierarchyState(savedStates);
    }

    //焦点View恢复
    int focusedViewId = savedInstanceState.getInt(FOCUSED_ID_TAG, View.NO_ID);
    if (focusedViewId != View.NO_ID) {
        View needsFocus = mContentParent.findViewById(focusedViewId);
        if (needsFocus != null) {
            needsFocus.requestFocus();
        }
    }

    //Panels恢复
    SparseArray<Parcelable> panelStates = savedInstanceState.getSparseParcelableArray(PANELS_TAG);
    if (panelStates != null) {
        restorePanelState(panelStates);
    }
	//Toolbar数据恢复
    if (mDecorContentParent != null) {
        SparseArray<Parcelable> actionBarStates =
            savedInstanceState.getSparseParcelableArray(ACTION_BAR_TAG);
        if (actionBarStates != null) {
            doPendingInvalidatePanelMenu();
            mDecorContentParent.restoreToolbarHierarchyState(actionBarStates);
        }
    }
}

5. 保存额外信息

通过重写 onSaveInstanceState() 方法,往bundle中存入额外数据,需要注意的是,这个bundle最后也是要通过binder通信发送到AMS的,所以数据量不能太多:

//MyActivity.java
@Override
public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState){
    //调用父类的方法(父类默认实现了View视图的状态保存)
    super.onSaveInstanceState(outState,outPersistentState);
    outStte.putString("test",str);
}

可以在 onRestoreInstanceState()中进行恢复:

@Override
public void onRestoreInstanceState(Bundle savedInstanceState,PersistableBundle persistentState){
    //调用父类的方法(父类默认实现了View状态的恢复)
    super.onRestoreInstanceState(savedInstanceState,persistentState);
    str = savedInstanceState.getString("temp");
}

也可以在 onCreate() 中进行恢复(检查Bundle是否为空):

@Override
protected void onCreate(Bundle savedInstanceState){
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    if(savedInstance != null){
        //之前有状态数据信息保存,可能还有自己额外保存的数据
        str = savedInstanceState.getString("temp");
    }
}

6. 实验:

MainActivity如下

public class MainActivity extends AppCompatActivity {
    private static final String TAG = "Fy_MainActivity";
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Log.e(TAG,"onCreate");
    }
    //所有生命周期都打印
    //...
    @Override
    protected void onSaveInstanceState(@NonNull Bundle outState) {
        super.onSaveInstanceState(outState);
        Log.e(TAG,"onSaveInstanceState");
        outState.putString("test","im Tu Fengyi");
    }

    @Override
    protected void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
        super.onRestoreInstanceState(savedInstanceState);
        String s = savedInstanceState.getString("test");
        Log.e(TAG,"onRestoreInstanceState gets s:"+s);
    }
}

旋转屏幕后,打印结果为:(Android8.0):

onCreate
onStart
onResume

onPause
onSaveInstanceState
onStop
onDestroy

onCreate
onStart
onRestoreinstanceState gets s:im Tu Fengyi
onResume

旋转屏幕后,打印结果为:(Android9.0 之后改了onSaveInstance()回调的位置位置)

2023-03-14 20:04:08.859 12301-12301/? E/Fy_MainActivity: onCreate
2023-03-14 20:04:08.874 12301-12301/? E/Fy_MainActivity: onStart
2023-03-14 20:04:08.898 12301-12301/? E/Fy_MainActivity: onResume
2023-03-14 20:06:14.853 12301-12301/? E/Fy_MainActivity: onPause
2023-03-14 20:06:14.855 12301-12301/? E/Fy_MainActivity: onStop
2023-03-14 20:06:14.858 12301-12301/? E/Fy_MainActivity: onSaveInstanceState
2023-03-14 20:06:14.859 12301-12301/? E/Fy_MainActivity: onDestroy
2023-03-14 20:06:14.922 12301-12301/? E/Fy_MainActivity: onCreate
2023-03-14 20:06:14.926 12301-12301/? E/Fy_MainActivity: onStart
2023-03-14 20:06:14.927 12301-12301/? E/Fy_MainActivity: onRestoreInstanceState gets s:im Tu Fengyi
2023-03-14 20:06:14.927 12301-12301/? E/Fy_MainActivity: onResume
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值