android.os.TransactionTooLargeException异常
2016-04-07 14:38
585 查看
一. 背景
输入法在V2.30(185)和V2.35(196)两个版本中都碰到了大量的TransactionTooLargeException的崩溃问题,其中崩溃的堆栈有所不同:
V2.30:android.app.ApplicationPackageManager.getInstalledPackages(ApplicationPackageManager.java:464)
V2.35:android.view.inputmethod.InputMethodManager.getEnabledInputMethodList(InputMethodManager.java:602)
最终通过查找代码中的改动点,发现其中的原因就是:多个线程同时调用了以下的接口:
List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
List<RunningTaskInfo> tasksInfo = activityManager.getRunningTasks(1);
List<PackageInfo> appInfoList = pkgManager.getInstalledPackages(0);
那么为什么调用这些接口会出现这个异常呢,我们从异常出现的原因为出发点进行讲解。
二. TransactionTooLargeException的原因
从android的开发文档(http://developer.android.com/reference/android/os/TransactionTooLargeException.html)中我们了解到该异常的描述:
因为Binder太大了导致传输失败。
当调用远程(跨进程)方法时,方法所带的参数以及返回值多会以parcel对象保存在Binder传输缓冲区进行传输的。如果参数或者返回值所占的内存超过传输缓冲区,调用将会失败同时会抛出TransactionTooLargeException异常。
Binder传输缓冲区是同一进程中所有传输操作所共享的,大小为1Mb。因此当进程中同一时刻,如果有大量的跨进程方法调用时,就要注意了。
从以上异常的描述,可以总结出现该异常的原因:
跨进程方法调用
调用的方法带的参数或者返回值占用较多内存
同一时刻方法调用次数太多
三. 输入法为何出现TransactionTooLargeException
从TransactionTooLargeException出现的原因可知:
跨进程方法调用
查看android的框架原理机制了解android的框架机制是通过IPC的机制去实现各个服务的管理,所有服务管理对象都是跨进程的调用,如:
PackageManager,InputMethodManager,ActivityManager都是通过binder传输进行跨进程调用
调用的方法带的参数或者返回值占用较多内存
获取用户所有安装应用列表,如果用户安装大量应用的情况下,数据量还是比较大
同一时刻方法调用次数太多
输入法启动时会调用2次getInstalledPackages,广告sdk智能预加载每隔10s会调用一次getRunningAppProcesses或者getRunningTasks,调用5-6次getInstalledPackages
四. 如何避免
了解问题出现的条件后,该问题就迎刃而解,同时在项目开发过程中就需要避免问题的发生,整理的方法如下:
跨进程方法调用时尽量减少参数或者返回值的内存占用
如:getInstalledPackages使用过滤参数减少返回结果的内存占用
不要多个线程同时调用跨进程方法,尽量减少调用次数或者重复利用调用的结果
如: 整个项目中共用一份安装列表,减少getInstalledPackages的调用次数; 如果同一时刻需要调用getInstalledPackages,getRunningAppProcesses,getRunningTasks等方法,请使用同一个线程进行操作
输入法在V2.30(185)和V2.35(196)两个版本中都碰到了大量的TransactionTooLargeException的崩溃问题,其中崩溃的堆栈有所不同:
V2.30:android.app.ApplicationPackageManager.getInstalledPackages(ApplicationPackageManager.java:464)
V2.35:android.view.inputmethod.InputMethodManager.getEnabledInputMethodList(InputMethodManager.java:602)
最终通过查找代码中的改动点,发现其中的原因就是:多个线程同时调用了以下的接口:
List<RunningAppProcessInfo> appProcesses = activityManager.getRunningAppProcesses();
List<RunningTaskInfo> tasksInfo = activityManager.getRunningTasks(1);
List<PackageInfo> appInfoList = pkgManager.getInstalledPackages(0);
那么为什么调用这些接口会出现这个异常呢,我们从异常出现的原因为出发点进行讲解。
二. TransactionTooLargeException的原因
从android的开发文档(http://developer.android.com/reference/android/os/TransactionTooLargeException.html)中我们了解到该异常的描述:
因为Binder太大了导致传输失败。
当调用远程(跨进程)方法时,方法所带的参数以及返回值多会以parcel对象保存在Binder传输缓冲区进行传输的。如果参数或者返回值所占的内存超过传输缓冲区,调用将会失败同时会抛出TransactionTooLargeException异常。
Binder传输缓冲区是同一进程中所有传输操作所共享的,大小为1Mb。因此当进程中同一时刻,如果有大量的跨进程方法调用时,就要注意了。
从以上异常的描述,可以总结出现该异常的原因:
跨进程方法调用
调用的方法带的参数或者返回值占用较多内存
同一时刻方法调用次数太多
三. 输入法为何出现TransactionTooLargeException
从TransactionTooLargeException出现的原因可知:
跨进程方法调用
查看android的框架原理机制了解android的框架机制是通过IPC的机制去实现各个服务的管理,所有服务管理对象都是跨进程的调用,如:
PackageManager,InputMethodManager,ActivityManager都是通过binder传输进行跨进程调用
调用的方法带的参数或者返回值占用较多内存
获取用户所有安装应用列表,如果用户安装大量应用的情况下,数据量还是比较大
同一时刻方法调用次数太多
输入法启动时会调用2次getInstalledPackages,广告sdk智能预加载每隔10s会调用一次getRunningAppProcesses或者getRunningTasks,调用5-6次getInstalledPackages
四. 如何避免
了解问题出现的条件后,该问题就迎刃而解,同时在项目开发过程中就需要避免问题的发生,整理的方法如下:
跨进程方法调用时尽量减少参数或者返回值的内存占用
如:getInstalledPackages使用过滤参数减少返回结果的内存占用
不要多个线程同时调用跨进程方法,尽量减少调用次数或者重复利用调用的结果
如: 整个项目中共用一份安装列表,减少getInstalledPackages的调用次数; 如果同一时刻需要调用getInstalledPackages,getRunningAppProcesses,getRunningTasks等方法,请使用同一个线程进行操作
相关文章推荐
- android中sharedPreferences的用法
- Android studio For Mac快捷键
- Android实战技巧之五十一:libjpeg与Android
- 自定义控件给子View分配点击事件
- Android 获得联系人并排序
- ionic新建项目
- Android开发者应该深入学习的10个开源应用项目
- Android中dp和px之间进行转换
- ionic打包apk
- 工作中的积累
- AndroidDev站点推荐-zz
- ionic兼容title居中和tab栏放在底部
- android在activity中禁止下拉状态栏的方法
- Android进程间通信
- android:Activity中切换不同状态页:加载中,加载失败,数据页,空页面……
- Android Battery 开发(二)
- Android-按钮效果
- Android 蓝牙相关的东西
- 在Android library中不能使用switch-case语句访问资源ID的原因分析及解决方案
- (Kevin笔记三)用AtomicInteger来解决数据表异步操作的问题