[Android] Activity状态保存与恢复

Android Activity的生命周期和启动模式 参考:《Android开发艺术探索》 1. Activity 的正常生命周期 完整的activity生命周期如下所示 生命周期的几点注意事项: Activity 第一次启动:onCreate->onStart->onResume。 Activity 切换到后台( 用户打开新的 Activity 或者切换到桌面) ,onPause->onStop(如果新 Activity 采用了透明主题,则当前 Activity 不会回调 onstop)。 Activity 从后台到前台,重新可见,o 阅读详情

Activity状态保存与恢复


之前没太明白视图在什么时候可以保存状态,在什么时候状态可以被恢复,想了想还是得琢磨琢磨源码,虽然干的活离Android越来越远,但毕竟老本行,还是需要花精力琢磨的。


在不同的版本中,Activity保存状态的时机是不一样的,在Android 3之前,把Activity状态的保存是在onPause之前被调用onSaveInstanceState(ActivityThread#performPauseActivity),而在Android 9之前,把Activity状态的保存后置到了onStop之前,在Android 9之后,把Activity的状态保存后置到了onStop之后(ActivityThread#callActivityOnStop)。

而通过前面的分析:

Android Activity启动流程

Android UI工作流程1

Android UI工作流程2

我们可以知道在AMS创建Activity的时候,通过Binder事务,调用到客户端进程,执行LaunchActivityItem#execute,其中就包括ActivityClientRecord的创建。

 public void execute(ClientTransactionHandler client, IBinder token,
            PendingTransactionActions pendingActions) {
        Trace.traceBegin(TRACE_TAG_ACTIVITY_MANAGER, "activityStart");
        ActivityClientRecord r = new ActivityClientRecord(..., mState,...);
        client.handleLaunchActivity(r, pendingActions, null /* customIntent */);
        Trace.traceEnd(TRACE_TAG_ACTIVITY_MANAGER);
    } 

而一个ActivityClientRecord代表着用户进程的一个Activity实例记录。其中的Bundle类型的mState字段就代表着这个Activity的状态。

回看到ActivityThread#callActivityOnStop,最终的逻辑都是调用到ActivityThread#callActivityOnSaveInstanceState方法:

 private void callActivityOnSaveInstanceState(ActivityClientRecord r) {
        // 给ActivityClientRecord#state创建一个新的Bundle对象。
        r.state = new Bundle();
        r.state.setAllowFds(false);// 序列化底层对于是否支持文件描述符的逻辑是两套,这里设置为false,因为这个bundle是不需要保存fd的
        if (r.isPersistable()) { // 如果是系统内置的应用
            r.persistentState = new PersistableBundle();
            mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state,
                    r.persistentState);
        } else {
            // 对于普通App而言,通过下面这里调用保存状态
            mInstrumentation.callActivityOnSaveInstanceState(r.activity, r.state);
        }
    } 

-> Instrumentation#callActivityOnSaveInstanceState

-> activity.performSaveInstanceState

 final void performSaveInstanceState(@NonNull Bundle outState) {
        dispatchActivityPreSaveInstanceState(outState);// 可以注册ActivityLifecycleCallbacks给Application获取这个hook回调。
        onSaveInstanceState(outState);// 执行Activity实例的onSaveInstanceState方法。
        saveManagedDialogs(outState);// 保存关联了当前Activity的Dialog状态。
        mActivityTransitionState.saveState(outState);// 保存Activity转场动画相关的状态
        storeHasCurrentPermissionRequest(outState);// 保存当前Activity是否正在申请权限
        if (DEBUG_LIFECYCLE) Slog.v(TAG, "onSaveInstanceState " + this + ": " + outState);
        dispatchActivityPostSaveInstanceState(outState);// 和上面的pre类似,也是分发一个hook回调。
    } 

那么核心就是Activity的onSaveInstanceState,我们知道,我们可以通过重写这个方法来实现一些额外的状态保存的逻辑,当然即便我们不重写Activity实例的onSaveInstanceState方法,也有一些Activity的默认逻辑,默认的实现是:

 protected void onSaveInstanceState(@NonNull Bundle outState) {
        // 核心通过Window的saveHierarchyState保存视图状态。
        outState.putBundle(WINDOW_HIERARCHY_TAG, mWindow.saveHierarchyState());
        outState.putInt(LAST_AUTOFILL_ID, mLastAutofillId);
        // 内部通过FragmentManager保存Activity持有的所有Fragment状态
        Parcelable p = mFragments.saveAllState();
        if (p != null) {
            outState.putParcelable(FRAGMENTS_TAG, p);
        }
        // 自动填充服务相关的逻辑
        if (mAutoFillResetNeeded) {
            outState.putBoolean(AUTOFILL_RESET_NEEDED, true);
            getAutofillManager().onSaveInstanceState(outState);
        }
        dispatchActivitySaveInstanceState(outState);
    } 

View的状态保存和恢复:

View的状态保存:

而Window实例自然就是PhoneWindow:

 public Bundle saveHierarchyState() {
        Bundle outState = new Bundle();
        // 如果Window没有内容,就无需保存什么
        // 而mContentParent其实就是Activity结构中的R.id.content的FrameLayout
        if (mContentParent == null) {
            return outState;
        }
        // 创建一个稀松数组结构的散列表
        SparseArray<Parcelable> states = new SparseArray<Parcelable>();
        // 见下文:
        mContentParent.saveHierarchyState(states);
        // 把视图树的状态保存结果放到Activity传入的Bundle中
        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());
        }
        // ...
        return outState;
    } 

mContentParent.saveHierarchyState(states),实现就是View啦:

// View.dispatchSaveInstanceState实现如下:
    protected void dispatchSaveInstanceState(SparseArray<Parcelable> container) {
        // 只要view有id,并且没有关闭掉状态保存功能,就会被保存
        if (mID != NO_ID && (mViewFlags & SAVE_DISABLED_MASK) == 0) {
            mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
            // 回调View的onSaveInstanceState实现
            // 在View.java中的实现其实就是返回一个空的Parcelable对象(和一些Autofill相关的逻辑)
            Parcelable state = onSaveInstanceState();
            if ((mPrivateFlags & PFLAG_SAVE_STATE_CALLED) == 0) {
                throw new IllegalStateException(
                        "Derived class did not call super.onSaveInstanceState()");
            }
            if (state != null) {
                // 在上面创建的稀松数组中,存放的key就是View的id。
                container.put(mID, state);
            }
        }
    } 

所以可以看到,对于View而言,其实就是保存自身的状态,而VierGroup则不难猜到,肯定是遍历子View进行状态保存:

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

如此以来,视图树的状态就保存完了,我们可以看一下比如Switch这个开关组件的状态保存,因为Switch继承自CompoundButton,其并没有实现自己的onSaveInstanceState方法,在父类CompoundButton中:

 public Parcelable onSaveInstanceState() {
        Parcelable superState = super.onSaveInstanceState();
        SavedState ss = new SavedState(superState);
        ss.checked = isChecked();// 保存按钮的checked选中态。
        return ss;
    } 

View的状态恢复:

那视图的状态保存完了,接下来就是考虑在恰当的时候进行恢复,还是以Switch开关这个控件为例子:

 @Override
    public void onRestoreInstanceState(Parcelable state) {
        SavedState ss = (SavedState) state;
        super.onRestoreInstanceState(ss.getSuperState());
        // 恢复是否被选中的状态。
        setChecked(ss.checked);
        requestLayout();
    } 

而在Activity进行Start的时候,会主动回调到相关逻辑:

-> Activity#handleStartActivity

-> Instrumentation#callActivityOnRestoreInstanceState

-> activity.performRestoreInstanceState

 final void performRestoreInstanceState(@NonNull Bundle savedInstanceState) {
        // 回调onRestoreInstanceState
        onRestoreInstanceState(savedInstanceState);
        // 恢复Dialog的状态
        restoreManagedDialogs(savedInstanceState);
    } 

视图状态的保存开始自PhoneWindow,恢复自然也一样,在onRestoreInstanceState的默认实现中,先获取到之前保存的Window状态的Bundle对象,然后mWindow.restoreHierarchyState进行恢复,其实和序列化的过程很类似,状态的恢复其实就是状态保存过程的逆向,视图树状态的恢复关键代码:

mContentParent.restoreHierarchyState(savedStates); 

mContentParent是FrameLayout实例,其本身没有实现restoreHierarchyState,在View中:

-> View#restoreHierarchyState

-> View#dispatchRestoreInstanceState

 protected void dispatchRestoreInstanceState(SparseArray<Parcelable> container) {
        if (mID != NO_ID) {
            Parcelable state = container.get(mID);
            // 如果有当前View的状态
            if (state != null) {
                mPrivateFlags &= ~PFLAG_SAVE_STATE_CALLED;
                // 有的话调用onRestoreInstanceState
                onRestoreInstanceState(state);
            }
        }
    } 

onRestoreInstanceState在子View中的实现就如上面Switch的实现。

Fragment状态的保存与恢复:

Fragment状态保存:

在Activity的onSaveInstanceState中,我们看到了Fragment状态相关的保存逻辑:

-> mFragments.saveAllState()

-> mHost.mFragmentManager.saveAllState()

FragmentManagerImpl的实现如下:

 Parcelable saveAllState() {
        // 强制执行一些前置任务,比如提交的事务全部执行掉,以此保证状态是最新的。
        // 嗅到了一些不好的味道
        forcePostponedTransactions();
        endAnimatingAwayFragments();
        execPendingActions();

        mStateSaved = true;
        mSavedNonConfig = null;
        // 如果当前没有活跃状态的Fragment,就不保存
        if (mActive == null || mActive.size() <= 0) {
            return null;
        }
        // First collect all active fragments.
        int N = mActive.size();
        FragmentState[] active = new FragmentState[N];
        boolean haveFragments = false;
        for (int i=0; i<N; i++) {
            Fragment f = mActive.valueAt(i);
            if (f != null) {
                if (f.mIndex < 0) {
                    throwException(new IllegalStateException(
                            "Failure saving state: active " + f
                            + " has cleared index: " + f.mIndex));
                }
                haveFragments = true;
                FragmentState fs = new FragmentState(f);
                active[i] = fs;
                
                if (f.mState > Fragment.INITIALIZING && fs.mSavedFragmentState == null) {
                    // 保存Fragment对象的状态
                    // 在这其中主要做两件事,第一个是调用Fragment自身的onSave方法保存自身的状态
                    // 第二个是调用Fragment的mChildFragmentManager去递归保存子Fragment的状态。
                    fs.mSavedFragmentState = saveFragmentBasicState(f);
                    if (f.mTarget != null) {
                        // 保存Fragment的TargetFragment的在mActive中记录的索引。
                        if (f.mTarget.mIndex < 0) {
                            throwException(new IllegalStateException(
                                    "Failure saving state: " + f
                                    + " has target not in fragment manager: " + f.mTarget));
                        }
                        if (fs.mSavedFragmentState == null) {
                            fs.mSavedFragmentState = new Bundle();
                        }
                        putFragment(fs.mSavedFragmentState,
                                FragmentManagerImpl.TARGET_STATE_TAG, f.mTarget);
                        if (f.mTargetRequestCode != 0) {
                            fs.mSavedFragmentState.putInt(
                                    FragmentManagerImpl.TARGET_REQUEST_CODE_STATE_TAG,
                                    f.mTargetRequestCode);
                        }
                    }
                } else {
                    fs.mSavedFragmentState = f.mSavedFragmentState;
                }
                if (DEBUG) Log.v(TAG, "Saved state of " + f + ": "
                        + fs.mSavedFragmentState);
            }
        } 
        if (!haveFragments) {
            if (DEBUG) Log.v(TAG, "saveAllState: no fragments!");
            return null;
        }
        
        int[] added = null;
        BackStackState[] backStack = null;
        
        // Build list of currently added fragments.
        N = mAdded.size();
        if (N > 0) {
            added = new int[N];
            for (int i=0; i<N; i++) {
                added[i] = mAdded.get(i).mIndex;
                if (added[i] < 0) {
                    throwException(new IllegalStateException(
                            "Failure saving state: active " + mAdded.get(i)
                            + " has cleared index: " + added[i]));
                }
                if (DEBUG) Log.v(TAG, "saveAllState: adding fragment #" + i
                        + ": " + mAdded.get(i));
            }
        }

        // 保存Fragment的回退栈的状态
        if (mBackStack != null) {
            N = mBackStack.size();
            if (N > 0) {
                backStack = new BackStackState[N];
                for (int i=0; i<N; i++) {
                    backStack[i] = new BackStackState(this, mBackStack.get(i));
                    if (DEBUG) Log.v(TAG, "saveAllState: adding back stack #" + i
                            + ": " + mBackStack.get(i));
                }
            }
        }
        // 创建Fragment状态对象,并将上面收集到的所有的状态数据全部写入到fms中,然后交给Activity保存。
        FragmentManagerState fms = new FragmentManagerState();
        fms.mActive = active;
        fms.mAdded = added;
        fms.mBackStack = backStack;
        fms.mNextFragmentIndex = mNextFragmentIndex;
        if (mPrimaryNav != null) {
            fms.mPrimaryNavActiveIndex = mPrimaryNav.mIndex;
        }
        saveNonConfig();
        return fms;
    } 

其实从上面代码,尤其是活跃状态Fragment状态的保存那一块,也可以看出,Fragment的状态管理确实很复杂。。。

除了Activity中调用FM进行Fragment的状态保存,FragmentManager还提供了public方法: saveFragmentInstanceState(fragment), 可以对单个Fragment进行状态保存。

以及在FragmentManager的moveToState进行Fragment状态变更的时候,当Fragment的状态回退到ACTIVITY_CREATE之前,其实也就是初始化状态(Fragment执行onDestroy之前会置为这一状态)和不合法状态。

Fragment状态恢复:

按照Google的编码习惯,状态的恢复也一定是在FragmentManagerImpl中,并且api叫做restoreAllState,并且和上文的三种状态保存是对应的,API设计的很合理。

而Activity中对于Fragment的状态恢复入口在Acitvity的onCreate中:

 if (savedInstanceState != null) {
            // ...
            Parcelable p = savedInstanceState.getParcelable(FRAGMENTS_TAG);
            // 调用到Fragment的restoreAllState方法。
            mFragments.restoreAllState(p, mLastNonConfigurationInstances != null
                    ? mLastNonConfigurationInstances.fragments : null);
        }
        mFragments.dispatchCreate(); 

restoreAllState方法主要分为一下几步:

  1. 先把受Activity重建影响的Fragment实例状态进行恢复。
  2. 把所有之前位于mActive中的Fragment实例进行重新创建实例和状态恢复。
  3. 更新Fragment的mTarget索引。
  4. 把上面搞出来的一堆Fragment添加到FragmentManager中的mAdded容器中。
  5. 如有需要的话,恢复Fragment的返回栈状态。

而对于外部主动使用saveFragmentInstanceState进行状态保存的方法,对应的恢复状态方法是Fragment的setInitialSavedState,这个方法其实就是把状态对象赋值给Fragment,而后FragmentManager执行到Fragment对应的声明周期的时候,会主动去把Fragment已经存在的状态对象传递给对应的方法比如onCreateView。

对于通过moveToState触发的状态恢复,会在Fragment的newState > Fragment.CREATED的时候,触发视图的恢复,而保存状态的Bundle也会在onCreateView,onViewCreated,onActivityCreated中传递给Fragment。以及通过FragmentLifecycleCallbacks暴露给外部。在之后是调用Fragment的restoreViewState,进行视图状态的恢复,开始的起点就是Fragment的mView字段,而这个字段,就是我们通过onCreateView返回的对象,当Fragment通过onCreateView完成Fragment视图的创建之后,fm会将其赋值给Fragment的mView字段。

Dialog状态的保存和恢复:

Dialog状态的保存:

看Activity.java中这一部分的源码的提交记录已经是2009年了,相关的逻辑其实就是调用当前Activity的所有Dialog实例,一次进行保存和恢复,相关的逻辑官方推荐是用DialogFragment来弹Dialog,不妨看下DialogFragment的实现(DialogFragment本身也是一个Fragment实例,通过FragmentManager进行管理,所以状态的保存和恢复和Fragment没什么太大的差异,只不过DialogFragment实现了自定义的onSaveInstanceState方法):

 public void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        if (mDialog != null) {
            // 调用当前DialogFragment关联的mDialog的onSaveInstanceState方法
            Bundle dialogState = mDialog.onSaveInstanceState();
            if (dialogState != null) {
                outState.putBundle(SAVED_DIALOG_STATE_TAG, dialogState);
            }
        }
        if (mStyle != STYLE_NORMAL) {
            outState.putInt(SAVED_STYLE, mStyle);
        }
        if (mTheme != 0) {
            outState.putInt(SAVED_THEME, mTheme);
        }
        if (!mCancelable) {
            outState.putBoolean(SAVED_CANCELABLE, mCancelable);
        }
        // 如果当前DialogFragment正在展示Dialog,要把这个标记位记录下来
        if (!mShowsDialog) {
            outState.putBoolean(SAVED_SHOWS_DIALOG, mShowsDialog);
        }
        if (mBackStackId != -1) {
            outState.putInt(SAVED_BACK_STACK_ID, mBackStackId);
        }
    } 

Dialog中的实现和其它组件相比比较简单,就是是否正在展示dialog的标记位保存和视图状态的保存:

 public @NonNull Bundle onSaveInstanceState() {
        Bundle bundle = new Bundle();
        // 保存当前Dialog是否正在展示态
        bundle.putBoolean(DIALOG_SHOWING_TAG, mShowing);
        if (mCreated) {
            // Dialog关联的PhoneWindow视图状态保存
            bundle.putBundle(DIALOG_HIERARCHY_TAG, mWindow.saveHierarchyState());
        }
        return bundle;
    } 

状态的恢复如下:

 public void onRestoreInstanceState(@NonNull Bundle savedInstanceState) {
        final Bundle dialogHierarchyState = savedInstanceState.getBundle(DIALOG_HIERARCHY_TAG);
        if (dialogHierarchyState == null) {
            // dialog has never been shown, or onCreated, nothing to restore.
            return;
        }
        // 如果之前Dialog还没有执行到onCreate,执行一下onCreate。
        dispatchOnCreate(savedInstanceState);
        // 恢复Dialog关联的视图树状态。
        mWindow.restoreHierarchyState(dialogHierarchyState);
        // 如果之前Dialog是正在展示,这里重新show出来
        if (savedInstanceState.getBoolean(DIALOG_SHOWING_TAG)) {
            show();
        }
    } 


  

ull) {
            // dialog has never been shown, or onCreated, nothing to restore.
            return;
        }
        // 如果之前Dialog还没有执行到onCreate,执行一下onCreate。
        dispatchOnCreate(savedInstanceState);
        // 恢复Dialog关联的视图树状态。
        mWindow.restoreHierarchyState(dialogHierarchyState);
        // 如果之前Dialog是正在展示,这里重新show出来
        if (savedInstanceState.getBoolean(DIALOG_SHOWING_TAG)) {
            show();
        }
    } 

最后

在技术领域内,没有任何一门课程可以让你学完后一劳永逸,再好的课程也只能是“师傅领进门,修行靠个人”。“学无止境”这句话,在任何技术领域,都不只是良好的习惯,更是程序员和工程师们不被时代淘汰、获得更好机会和发展的必要前提。

**如果你觉得自己学习效率低,缺乏正确的指导,可以扫码,加入我们资源丰富,学习氛围浓厚的技术圈一起学习交流吧!


加入我们吧!群内有许多来自一线的技术大牛,也有在小厂或外包公司奋斗的码农,我们致力打造一个平等,高质量的Android交流圈子,不一定能短期就让每个人的技术突飞猛进,但从长远来说,眼光,格局,长远发展的方向才是最重要的。

35岁中年危机大多是因为被短期的利益牵着走,过早压榨掉了价值,如果能一开始就树立一个正确的长远的职业规划。35岁后的你只会比周围的人更值钱。

Activity onSaveInstanceState 状态保存和恢复机制实战之ManagedDialog应用 Activity自动管理Dialog的状态 阅读详情

相关推荐

手把手教你解决Ubuntu 20.04虚拟机桥接模式下的网络问题:DHCP与静态IP配置全指南

本文详细解析了Ubuntu 20.04虚拟机在桥接模式下的网络配置问题,包括DHCP与静态IP的配置方法及常见故障排查技巧。通过深入讲解桥接模式原理和提供实战操作指南,帮助用户解决无法访问外网、ping不通等典型网络问题,实现虚拟机与物理网络的无缝连接。

weixin_29256771的博客 542

android.os.TransactionTooLargeException,android.app.servertransaction.PendingTransactionActions的解决

Binder传输的数据太大导致的异常。 如果Binder的参数或返回值太大,不适合的事务缓冲区,然后调用将失败,并将被抛出TransactionTooLargeException。 解决方法:不要将大量数据传入Binder 最近在我们的页面中有5个fragment,然后会保存大量数据,跳转到下一个activity的时候,等2-3秒就会直接闪退,经过查找文档,确认需要以下方案: 于是我仔细分析...

平_sir的博客 2208

团队管理中最棘手的6个问题

研发团队的管理棘手问题,大多集中在。

xiaolyuh的专栏 742

android中保存Activity的状态

1.onSaveInstanceState和onRestoreInstanceState基本作用    onSaveInstanceState是用来保存UI状态的,你可以使用它保存你所想保存的东西,在Activity杀死之前,它一般在onStop或者onPause之前触发,onRestoreInstanceState则是在onResume之前触发回复状态,至于复写这个方法后onCreate方法是

1万+

2025华东杯A/B/C题解题思路+可运行代码参考

这些因素包括但不限于:助滑坡的坡度、运动员的质量、滑雪板的接触面与雪地的摩擦力、空气阻力系数、运动员的体型和衣物形态等。助滑坡是运动员滑行至起跳台前的最后一段坡道,这一段坡道的坡度、长度和运动员的姿势会直接影响到起跳时的初始速度。运动员的滑行速度不仅受助滑坡的坡度影响,还受到摩擦力、空气阻力和重力等多方面因素的影响。通过合理的姿势调整,运动员能够有效减少空气阻力,增加身体的重力加速度,进而提升滑行速度。助滑坡的角度通常介于10°到12°之间,而运动员的滑行速度将受到重力、摩擦力和空气阻力的共同作用。

qq_52590045的博客 1796

VFIO框架源码分析(二十一)- IOMMUFD 模式下的 DMA 映射机制

在虚拟化 I/O 的世界里,无论上层管理面(如对象模型、设备绑定)如何重构,数据面最核心的任务始终未变——DMA 映射(DMA Mapping)。即如何建立 Guest Physical Address (GPA) 到 Host Physical Address (HPA) 的映射关系,并将其填入 IOMMU 的硬件页表中,使得直通设备能够正确访问虚拟机内存。在 Legacy VFIO (Type1) 时代,这一职责由承担,它通过ioctl 操作 Container。

qq_36071928的博客 1007

Android之Activity状态的保存和恢复

系统在某些情况下会调用onSaveInstanceState()和onRestoreInstanceState() 这两个方法来保存和恢复Activity的状态。 一句话:Activity在“非正常”情况下退出都会调用onSaveInstanceState()方法来保存Activity的状态。 关于系统调用这两个方法的时机参考这里:http://www.cn...

weixin_30919235的博客 180

完美解决 mysql 报错ERROR 1524 (HY000): Plugin ‘mysql_native_password‘ is not loaded

mysql 报错ERROR 1524 (HY000): Plugin 'mysql_native_password' is not loaded

xiaohua616的博客 4万+

android重新创建Activity时状态的保存和恢复

在有些情况下,您的Activity会因正常应用行为而销毁,比如当用户按 返回按钮或您的Activity通过调用 finish()示意自己的销毁。 如果Activity当前被停止或长期未使用,或者前台Activity需要更多资源以致系统必须关闭后台进程恢复内存,系统也可能会销毁Activity。 当您的Activity因用户按了返回 或Activity自行完成而被销毁时,系统的 Activ

想飞的企鹅 3188

Ubuntu系统等保3级配置核查与加固

虽然这种方法在某些老旧的系统中仍然有效,但现代Linux发行版通常不推荐使用hosts.deny和hosts.allow文件来管理防火墙规则,因为它们的功能已经被更现代的防火墙管理工具(如iptables或firewalld)所取代。如果你想禁止特定的环境变量,可以从这个列表中移除它们,或者如果你想完全阻止所有环境变量的传递,可以将其设置为空。你可以通过ssh-keygen生成密钥对,并将公钥添加到用户的~/.ssh/authorized_keys文件中。修改配置后,需要重启SSH服务以使更改生效。

悦分享 183

【数据分享】12.5米分辨率DEM地形数据(分省)

该数据来源于NASA地球科学数据网站(https://nasadaacs.eos.nasa.gov/),是ALOS卫星获取的高精度地形数据。该数据由于精度高,包括全省范围的数据和省内每个城市范围的数据!

JData_Engineer的博客 2171

android保存activity状态,Android保存及恢复Activity的状态

Android保存Activity状态有两种方式:activity保存以及持久化保存。这里主要介绍activity保存。保存Activity状态基于Activity保存状态需要重写onSaveInstanceState(BundlesavedInstanceState)方法。示例:@OverridepublicvoidonSaveInstanceState(BundlesavedInsta...

weixin_42099302的博客 544

华为od 面试八股文_Spring_03_含答案

控制反转IOC是一个很大的概念,可以用不同的方式来实现。其主要实现方式有两种:依赖注入和依赖查找依赖注入;

MISAYAONE的博客 2341

安卓项目实战之:Activity和Fragment重新创建时状态的保存和恢复

前言 安卓应用中一个activity的销毁大致分为两种,正常销毁和异常销毁。 正常销毁比如:当用户按 返回按钮或您的Activity通过调用 finish()示意自己的销毁, 异常销毁通俗的说就是指未经过你同意的销毁,比如: 1、当用户按下HOME键时:此时如果按下HOME键后,打开了很多其他的应用程序,那么在前台应用需要更多内存的情况下,该Activity就有可能被系统销毁。 2,长按HOME键...

智玲君 1267

数学建模模型总结

这是本人在两年内准备参加数学建模竞赛搜集到的模型资料,已经经过了本人的筛选和整理,希望能够对准备参加数学建模竞赛的学弟学妹们提供一些帮助!

visio安装包

Microsoft Office Visio 是一款专业的制图软件。利用经过更新的形状、协作工具和数据链接图表,创建专业级图表以简化复杂的信息。

Android:保存 & 恢复Activity 状态缓存 - onSaveInstanceState()、onRestoreInstanceState()

手把手教你使用onSaveInstanceState()、onRestoreInstanceState()

Carson带你学Android 1万+

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

大厂Android面试秘籍: Android Activity 状态保存与恢复机制(六)

想在Android面试中脱颖而出?这篇超3万字的深度剖析不容错过!从Activity状态保存与恢复的触发时机、源码级流程,到特殊场景处理与性能优化,全维度拆解。精准命中面试高频考点,助你吃透底层原理,

Android开发领域创作者 1086

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

android activity数据保存,android笔记--保存和恢复activity的状态数据

一般来说, 调用onPause()和onStop()方法后的activity实例仍然存在于内存中, activity的所有信息和状态数据不会消失, 当activity重新回到前台之后, 所有的改变都会得到保留. 但是当系统内存不足时, 调用onPause()和onStop()方法后的activity可能会被系统摧毁, 此时内存中就不会存有该activity的实例对象了. 如果之后这个activit...

weixin_42525637的博客 550

Android Activity 和 Fragment 状态保存与恢复的最佳实践

Android Activity 和 Fragment 状态保存与恢复的最佳实践

贵公子丶笔记 1306

android笔记--保存和恢复activity的状态数据

一般来说, 调用onPause()和onStop()方法后的activity实例仍然存在于内存中, activity的所有信息和状态数据不会消失, 当activity重新回到前台之后, 所有的改变都会得到保留.  但是当系统内存不足时, 调用onPause()和onStop()方法后的activity可能会被系统摧毁, 此时内存中就不会存有该activity的实例对象了. 如果之后这个act

qq_25474979的博客 478

android保存activity状态,android:Activity-状态恢复

Activity状态恢复的成因1、onCreate和onDestroy并非完全因为用户操作才会触发--例如在横竖屏切换时2、当一个Activity遇到状态切换时,就会重构--Activity将被系统自动销毁,并再次自动创建,事实上已经不是同一个Activity的实例了,系统并不会为我们保存任何数据3、我们的代码需要为这种情况做准备--保存相关的数据4、系统config的改变--横竖屏的切换--语言...

weixin_35766215的博客 343

Android Activity数据保存机制与状态恢复实践

Activity作为Android四大组件之一,其生命周期管理是应用开发的核心基础。通过onSaveInstanceState()和onRestoreInstanceState()机制,系统能在配置变更或内存回收时自动保存和恢复UI状态。这种基于Bundle的序列化方案,配合ActivityThread中的mActivities映射表实现底层状态维护,有效解决了用户数据丢失问题。在电商、表单等场景中,合理运用ViewModel持久化与Bundle存储的组合策略,既能保证关键数据不丢失,又能避免过度序列化带来

weixin_29182481的博客 243

Android开发中Activity状态的保存与恢复

当置于后台的Activity因内存紧张被系统自动回收的时候,再次启动它的话他会重新调用onCretae()从而丢失了之前置于后台前的状态。 这时候就要重写Activity的两个方法来保存和恢复状态,具体用途举个例子:你正在编辑短信,这时候来了一个电话,打完电话回到短信界面, 短信刚好被系统回收重启,这时原先编辑了一半的内容总不能丢失了吧,这样影响用户体验。所以解决办法如下: 1 ...

weixin_30768661的博客 144

Android中Activity状态的保存和恢复:onSaveInstanceState和onRestoreInstanceState方法

先看图: Android中的activity通过onSaveInstanceState()方法保存activity的状态,在onCreate或者onRestoreInstanceState方法恢复状态,如果是通过onRestart方法前端运行的话,只会执行onSaveinstanceState方法。直接看代码: package com.hebaijun.savestate; impo

小何才露尖尖角 1万+

saveInstallState参数使用详解(android activity状态保存和恢复)

转自:http://my.oschina.net/zhangqingcai/blog/30348 写过Android程序的都知道Activity中有一个名称叫onCreate的方法。该方法是在Activity创建时被系统调用,是一个Activity生命周期的开始。可是有一点容易被忽视,就是onCreate方法的参数saveInstallState。因为在一般的程序开发中,很少用到这个参数。onC...

weixin_34283445的博客 130

模拟Android内存不足 activity回收 值保存 状态恢复

作者简介 微信公众号(高质量文章推送):陈博易 作者:陈博易 声明:本文是个人原创,未经允许请勿转载 商业合作请在微信公众号回复:联系方式 前言1.我记得我实习的那会,面试官问我关于acitivity的现场如何恢复,我当时也就知道保存和取值的方法,今天就当复习了。2.同时也希望大家帮小编一起分享给其他人,让小编的文章可以让更多人看到环境以及工具 Android项目:And

u013777094的博客 5645
上一篇: Android Framework重要服务之InputManagerService(二) inputReader
下一篇: 【Kotlin学习】Lambda编程——序列、使用Java函数式接口、with和apply函数
不秃头de程序猿
博客等级 码龄5年 4089粉丝 1475原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值