通过与 Jira 对比,让您更全面了解 PingCode

  • 首页
  • 需求与产品管理
  • 项目管理
  • 测试与缺陷管理
  • 知识管理
  • 效能度量
        • 更多产品

          客户为中心的产品管理工具

          专业的软件研发项目管理工具

          简单易用的团队知识库管理

          可量化的研发效能度量工具

          测试用例维护与计划执行

          以团队为中心的协作沟通

          研发工作流自动化工具

          账号认证与安全管理工具

          Why PingCode
          为什么选择 PingCode ?

          6000+企业信赖之选,为研发团队降本增效

        • 行业解决方案
          先进制造(即将上线)
        • 解决方案1
        • 解决方案2
  • Jira替代方案

25人以下免费

目录

onSaveInstanceState 的数据存在哪里

对于 Activity 的 onSaveInstanceState 方法大家都不会陌生,当 Activity 在不正常销毁的情况下,就会调用 onSaveInstanceState 方法,并将 Activity 中需要保存的数据(比如 View 状态 或者我们自己的数据)保存到这个方法的参数 Bundle 中。

一、onSaveInstanceState 的数据

对于 Activity 的 onSaveInstanceState 方法大家都不会陌生,当 Activity 在不正常销毁的情况下,就会调用 onSaveInstanceState 方法,并将 Activity 中需要保存的数据(比如 View 状态 或者我们自己的数据)保存到这个方法的参数 Bundle 中。

但是在实际使用的时候你可能会发现当保存的数据过大的时候就会看到如下的 log 日志

javabinder !!! FAILED BINDER TRANSACTION !!!

甚至可能发生异常(在高版本下会抛出异常,低版本直接打印日志)

android.os.TransactionTooLargeException

上面的信息都是表示 Bundle 传输的数据过大,那么问题来了, onSaveInstanceState 中 Bundle 的数据是存放在哪里,为什么又限制?

Binder 传输缓冲区是一个限制的大小的区域,大小为 1MB,这块缓冲区用于所有进程间的通信,也就是 Binder 通信。这些传输包括 onSaveInstanceState , startActivity 和其他与系统的交互,当传输的数据超过这个大小的时候就会抛出异常。

特别是 onSaveInstanceState 方法,因其需要在 Activity 返回的时候提供数据,官网建议是数据大小不大于 50K。

在追 onSaveInstanceState 的方法源码的时候,想要找到关于 Binder 方面的内容,就顺着Activity 的方法追,很多人都是到 Application 的 接口中就迷路了.

public interface ActivityLifecycleCallbacks {

        void onActivityCreated(Activity activity, Bundle savedInstanceState);

        void onActivityStarted(Activity activity);

        void onActivityResumed(Activity activity);

        void onActivityPaused(Activity activity);

        void onActivityS较好ped(Activity activity);

        void onActivitySaveInstanceState(Activity activity, Bundle outState);

        void onActivityDestroyed(Activity activity);

    }

其实这是一个错误的方向,其实只要想到 onSaveInstanceState 有点类似于 Activity 中其他生命周期的方法,就可以发现 onSaveInstanceState 最开始也是有 ActivityThread 做统一管理的,那么 onSaveInstanceState 的调用 也就和 ActivityThread 有关。

Bundle 的创建

在 ActivityThread 的源码中可以看到有这么个方法

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

        }

    }

其中最后调用了 mInstrumentation.callActivityOnSaveInstanceState 那么就到 mInstrumentation 类中查找

public void callActivityOnSaveInstanceState(Activity activity, Bundle outState,

            PersistableBundle outPersistentState) {

        activity.performSaveInstanceState(outState, outPersistentState);

    }

这个方法中又调用了 activity.performSaveInstanceState 的方法

final void performSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {

        onSaveInstanceState(outState, outPersistentState);

        saveManagedDialogs(outState);

        storeHasCurrentPermissionRequest(outState);

        if (DEBUG_LIFECYCLE) Slog.v(TAG, “onSaveInstanceState ” + this + “: ” + outState +

                “, ” + outPersistentState);

    }

    …

      public void onSaveInstanceState(Bundle outState, PersistableBundle outPersistentState) {

        onSaveInstanceState(outState);

    }

最后调用的是 Activity onSaveInstanceState 方法 ,显然 callCallActivityOnSaveInstanceState 的 r.state 就是 onSaveInstanceState 的方法的中的参数 Bundle .而 r 就是 ActivityThread 的内部类 ActivityClientRecord

static final class ActivityClientRecord {

        IBinder token;

        int ident;

        Intent intent;

        String referrer;

        IVoiceInteractor voiceInteractor;

        Bundle state; // 这个就是 r.state 也就是 onSaveInstanceState 的 Bundle

}

延伸阅读:

二、什么是Activity的生命周期

简单来说,Activity的生命周期是指一个Activity从其从创建到销毁的过程中会处于不同的状态,每个状态也有其对应的回调方法,这些回调会让 Activity 知晓某个状态已经更改:系统正在创建、停止或恢复某个 Activity,或者正在销毁该 Activity 所在的进程。

相关文章