异常分析 (空间太小)
- 出现 异常的原因:
- 碎片化 。
- MobileAPI脏数据
- 混淆时没有Keep 要使用的类或者方法 。
本地开发要与线上分开
异常信息中提示 “方法名”unknown source 内容 ,会加大我们准确定位的crash的难度 。
导致unknown source 的原因
1.执行javac时丢失文件名和行号
我们要在javac编译时保留debug信息 <javac debug="true" debuglevel="source ,line" ....>
2. 执行了代码混淆丢失文件名个行号
在proguard文件中增加 -keeparttributes SourceFile,LineNumberTable
名称 关键字 发生频率 发生原因 解决方式
名称 | 关键字 | 发生频率 | 发生场景 | 解决方式 |
空指针 | NullPointException | 1.调用接口时,过于信息返回数据 ,一旦为空的Json,引发崩溃 2.在使用asyncTask调用接口返回数据,在asyncTask的doInBackGround中,会因为有空而崩溃 3.页面跳转前后,跳转前的数据没有准备好 , 4.APP过多的使用全局变量 ,一旦发生内存回收,这些全局变量会被设置为空,而又没有考虑这种情况 。 |
1.方法需要对传入的参数判空或者try...catch后再继续使用 2. 3.调用外部接口确保返回值不为空,甚至确保执行该接口不会抛异常,导致程序的退出。 4.避免使用全局变量,不到万不得已不要使用全局变量,也要使全局支持序列号本地机制,一旦为空就通过fang |
|
角标越界 | IndexOutOfBoundsException(基类) StringIndexOutOfBoundsException(字符串截取越界) ArrayIndexOutOfBoundsException(数组越界) |
1.由于程序不严谨导致 2.在使用字符串时,经常使用subString(start ,end) 。start ,end超过字符串长度,就会崩溃 。 |
1.在遍历一个数组/集合时要预判数组集合是否为空 ,长度是否大于0; 2.在使用数组、集合中的元素时,要预判数组集合长度是否有那么长 。 |
|
试图调用一个空对象的方法 | Attempt to invoke virtual method on a null object reference 试图在一个空对象引用调用虚方法 |
1.在一个activity中,调用另一个activity的方法 ,为此在B中建立一个static 变量 ,当这个static 变量被回收时 ,便会有异常。 2.推送 ,点击推送消息根据事先定好的协议,跳过首页直接进入二级甚至三级 。这时二级界面要是有首页的某个对象是,该对象势必为空。 |
没实例化 | |
类型转换异常 | ClassCastException:classA cannot be cast to classB | Object x =new Integer(0) ; String str =(String)x; |
将安全类型转换函数 把字符串转换为整数 小数或布尔类型时,我们要为指定转换失败时的默认值。否则,就会得到一个空值。 |
|
数字转换错误 | NumberFormatException | 在数据类型转换过程中 ,如果转换不成功,一般会抛出ClassCastException的异常 。有一个例外 ,字符型转换为数字失败时 ,时Android系统会抛出NumberFormatException异常 ( 如String abc ="123****45" int result =Integer.parseInt(abc) ; ) |
这种情况发生在服务器返回数据没有按照约定返回整数而是字符串 ,客户端必须考虑到这种情况,如果转换失败,必须有默认值否则直接崩溃 | |
声明数组长度为-1 | NegativeArraySizeException | 数组大小为负值异常 ,单前使用负数大小创建数组时抛出该异常。场景 String[] arg1 =new String[args.length -1] ; args没有元素时 。 |
如果数组长度是由另一个变量动态得到时 ,要保证中括号[] 中的值必须大于0 | |
遍历集合的同时删除其中的元素 | ConcurrModificationException | 1.遍历一个集合不能删除该集合中的元素 2.多线程中删除同一个集合的元素(线程安全) |
解决方案:需要再定义一个列表结合delList ,来保存需要删除的对象 | |
比较器使用不当 | comparsion method violates its general contrac | 因为Comparator 的compare的方法使用的姿势不对(他是基于插入排序与归并排序算法相结合的产物 ,要比日常所用的冒泡排序算法快很多) | (单元测试) | |
当除数为0 | Java.lang.ArithmeticException:divide by zero | 当程序中执行一个除法时 ,如果除数为0 ,就会发生该情况 . |
||
不能随便使用aslist | AbstractList (add remove) 子类 ArrayList (add remove) Arrays$Arraylist (没有实现 (add he remove)) |
|||
找不到类(一) | classNotFoundException | 当我们动态加载一个类时候 ,如果该类运行时找不到,就会抛异常 如 class.forName("com.company.package.class") ; 由于类的全名称是字符串形式 ,这个很有可能是不正确 。 还有 findSystemClass("classname") loadClass("classname") ; |
||
找不到类(二) | NoClassDefFoundError | ClassA obj= new ClassA() ; 打包B和A分别位于不同的dex中 ,这时在A所在的dex中把A类删除了 通常插件化编程会扯出这个异常因为要使用DexClassLOder。 |
||
activity 相关异常 |
||||
找不到Activity | Android content,activityNotFoundException:NO activty found to handle Intent{....} | 1.错误原因 URL 不是以http开头 Uri uti =Uri.parse("www.baidu.com"); Intent intent =new Intent ........ 2.打开SD卡上的一个html页面时 ,没有为Intent指定打开Html页面所需要的浏览器 3.调用百度地图时openBaiduMapNavi 手机没有安装百度地图客户端 。(要判读是否安装) |
||
不能实例化activity | java.lang.RuntimeException:Unable to instantiate to activity ComponentInfo | 1.通常没有AndroidManifext.xml 清单中注册activity 。 2.系统处于异常状态(内存不足)导致部件初始化 。 |
||
找到service | Java.lang.RuntimeException:Unable to instance receiver | 1.检查代码中是否有Class.forName("Class1") 2.ProGuard 会将class1 混淆 ,从而找不到这个类 。 |
||
不能启动BroadcastRece | unable to start reciver | 1.在推送时,会和APP事先定义好协议,点击推送消息就跳过首页直接进入二级页面。 2.Content中有一个startActivity方法 ,Activity继承自Content ,重载startActivity方法,如果activity使用startActivity方法,不会有任何限制,如果使用Context的startActivity方法的话,就需要开启一个新的task,就需要开启一个新的task ,就会出现异常需要添加一个fiag |
使用activity以外的content来startActivity ,比如BroadCastReceiver,就必须为Intent.FLAG_ACTIVITY_NEW_TASK,否则就会抛异常 。 intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); |
|
startActivityForResult不能回传 | failure delivering result ResultInfo{who=null ,request =0 ;result=-1} | startActivityForResult,传回来的可key是A ,但按照B这个Key来取值 | ||
猴急的fragment | Fragment not attacher to Activity | 因为fragment在还没有Attach到activity时,调用诸如getResource这样的方法 。 如getResource.getString(R.string.app_name) ; |
解决方案 if(isAdded){ getResources().getString(R.string.app_name)} isAdd方法是Android系统提供的,它只有在fragment被添加到所属activity后才会返回ture。 |
|
序列号相关异常 |
||||
实体对象不支持序列号 | Parcelable encountered IOEXception writing serializable object(name=xx) | 如 :该类里面存在自定义实体 ,而该自定义实体未序列化。。。。 | ||
序列化时未指定ClassLoader | BadParcelableException:ClassNotFoundException when unmarshalling | 在使用Parcelable 机制时 。 a =in.readParcelable(null) ; |
private MyParcelable(Parcel in){ mStr =in.readString() ; a=in.readParcelable(ClassA.class.getClassLoader()) } |
|
ClassLoader | classNotFoundException 。 | 当ClassLoader为空时系统采取默认的ClassLoader。 Android有两种ClassLoader:framework classLoader和apk ClassLoader ,其中framework ClassLoader知道怎么加载Android的系统的内部的类 ;apk ClassLoader知道怎么加载我们自己写的类 ,也知道怎么加载Android系统的内部的类 。在APP刚启动时,默认的ClassLoader是apk ClassLoader ,但在系统内存不足应用会被系统回收再次启动的,这个默认的ClassLoader会变成framework ClassLoader ,所以对于我们自己的类会报classNotFoundException 。 |
||
反序列化时发现类找不到:被ProGuard混淆导致的崩溃 | parcelable encountered ClassNotFoundException reading a Serializable object .. | ProGuard 对于Class.forName(className)中的class无能为力,他会将这个class混淆的面目全非,于是在反序列化时找不到这个类。 | 在ProGuard中keep这个类 | |
反序列化时发现类找不到:传入畸形数据 (安全漏洞) |
Parcelable encountered ClassNotFoundException reading a Serializable object(name =某个类名称) | 1.由于正APP中使用getSeriaizableExtra() 的 api, APP开发人员没有对传入的数据做异常判断,别的有企图的人可以通过传入畸形数据,导致本地拒绝服务 2.传入简单数据,比如Integer ,就会抛出类型转换异常classCastException 2.当传入自定义的可序列化对象时,就会抛出上述带有ClassNotException 的异常信息 |
||
反序列化时出错 | Could not read input channel file description from parcel | 一般是因为Intent 传递的数据太大 ,貌似大于1MB 就会崩溃。也有可能是fileDescripter太多而且没有关闭 ,或者looper太多没有退出导致的 | ||
列表相关异常 |
||||
adpter数据变化但是没有通知listview | adapter的内容变化了 ,但是相应的listview并不知情 | 1.保证adapter的数据在在主线程中修改 2.及时的调用notifyDataSetChange方法 |
||
listview滚动时点击刷新按钮后崩溃 | 滚动时调用getCount ,回调用getView,这时将数据clear了 。会报IndexOutOfBoundsException:Invalid index 30 ,size is 1 ; | 在listview滚动时将刷新按钮设置为不可点击 |
||
Abslilstview 的obtainView 返回空指针 。 | Abslilstview 的obtainView 方法获取不到view ,其原因在于getview方法在某些时候返回null | getView的第二个常数convertView是不会为null ; 在getView返回值得时候,判断一下是否为null ,如果为null ,则放回convertView 。 |
||
Adapter数据源发生变化但是没有notifyDataSetChanged | pageAdapter对于notifyDataSetChanged()和getCount()的执行顺序是非常严格的才,系统跟踪count的值 ,如果这个值和getCount返回值不一致,就会抛出这个异常 。 | 为了保证getCount总是返回一个正确的值 ,那么在初始化viewpage时应该先给adapter初始化内容后再将该adapter传递给viewpage ,如果不这样处理 ,在更新adapter的内容后 ,应该调用一下adapter的 notifyDataSetChanged 。 | ||
窗体相关的异常:基本上都是dissmiss方法销毁对话框的时候 ,activty已经不存在。 |
||||
窗口句柄泄露 | 非主线程中的某些操作不当而引起的异常,从而导致强制关闭当前activity。而还未及时的调用dismss来解除Dialog等引用 。 | 在onDestroy()方法中调用dismiss来解除对dialog的引用 。 dialog.dismiss() ; |
||
view not attached to widow manager | 在一个费时的线程,在任务开始时显示对话框,任务结束时再销毁对话框,在期间如果activity因为某种原因有重新启动,那么Dialog调度dismiss方法的时候windowManager检查发现Dialog所属Activity已经不存在,所以会报 view not attached to widow manager |
要正确使用对话框 , (1)不要在非UI线程中使用对话框创建显示和取消对话框 。,那么对于异步操作显示对话框怎么办? Activty都要有相应的操作对话框回调 ,比如: .onCreateDialog .showDialog .dimissDialog .removeDialog . (2)一定要让对话框对象在activty的可控制范围内核生命周期之内。如对话框一定要是Activty的成员变量,并且再让对话框变量活跃在activty的Oncreat和OnDestory的方法之间 。 |
||
窗体在不恰当的时候获取了焦点。 | 在popoupWindow显示之前,就把焦点赋予它。 一般发生在Android2.3时出现 |
进行兼容。。。 |
||
token null is not for an application | 在实现Android浮窗时 ,Context不正确 AlertDialog.Builder(mcontext)所接的getAPPAction——Context()获取的Context,而应该是activty的实例,因为只有一个activty才能添加一个窗体。 |
|||
permission denied for this windown type | 在使用WindowMagnager.Layout.TYPE_SYSTEM_ALERT涉及window type 权限问题 。 | 解救办法的在配置文件中添加权限 <!---显示系统窗口权限--> _ALERT_WINDOW <!---在屏幕最顶部显示addview--> _OVERLAY_WINDOW |
||
is your activty running | 1.当我回来,你已不在 。这种Crash 与弹窗密切相关 ,由于 。 2.在 onCreate 方法中 ,想要弹出PopupWindow,当参数parent为空时 ,就会报上述的错误,因为PopupWindow依赖于activty ,而activty的OnCreate还没执行完 ,那么肯定会报错。 |
2.可以通过延迟(handle)来实现这个效果。。。 | ||
添加窗体失败 | ||||
AlertDialog.resolveDialogTheme | 1.在B页写了一个show方法 ,控制AlertDialog的弹出和隐藏 。在A页面却要调用页面B页面的show方法,于是就崩溃了。 2.在TabActivty中切换Tab ,容易产生这个Crash ,因为在new对话框时,参数content指定成了this ,即指向当前子activty的content,但是子activty是动态创建的 ,不能保证一直存在,其父activity的content则是隐藏的,所以将this替换为getParent()即可, |
1. | ||
this specifiied childed already has a parent | 在使用儿子时要先要调用其父的remove -view 方法,解除父子关系 。 | |||
子线程不能修改UI | ||||
不能再子线程操作AlterDialog和Toast | ||||
资源相关的异常() |
||||
Resources$NotFoundException | 因为参数int resID 错误 。我们把String 赋值给int的ResId ,所以编译器找不到正确的resource而报错误 。 | |||
StackOverefiowError | Layout布局文件结构嵌套太深 ,我们应该尽量控制在5层以上 。要经常使用Hierarchy View对其进行优化,移除不必要的试图。 在APP退出的时候APP有多个线程,那么在退出APP的时候可能不能完全关闭APP,及时使用finish方法也无法做到 ,必须使用System.exit(0)这样的语句才可以。这是因为finish方法只能退出当前的activity ,但是还有其他activty未关闭,这些activty中没有结束的线程,从而还有一些资源没有释放。而exit(int code)方法可以使进程退出能保证把所有的线程的栈空间释放,否则会有线程残留空间无法释放从而无法回收。将会导致该进程新建时栈空间不足,从而发生StackOverefiowError异常。 |
无论哪种StackOverefiowError异常都是由于无线递归引起的,在JVM中有一个栈,预设了一个深度,当超出这个深度时就会抛出StackOverefiowError。 | ||
unstatisfiedLinkError | .so格式的文件没有加载到 ,检查libs的aremeabi目录下的.so文件是否存在 。不能只看aremeabi 还要看x86下.so文件是否存在,如果没有,在x86的设备上依然是加载不到的。 | cpu指令集在Android aremeabi aremeabi-v7a mips 和 x86 ,所以处理so文件要格外小心 。 aremeabi 与 aremeabi-v7a 的so数量不一致,是典型的会导致UnsatisfiedLinkError的场景 |
||
infiateException之FileNotFoundException | GC导致 ,activty被销毁但涉及的资源没有被回收,便产生内存泄露,但是表现为FileNotFoundException | 在activty的onStop方法中手动释放每一张图片的资源 | ||
infiateException之缺少构造器 | 在创建自定义View的时候,会可能产生。 是其中第二个参数用来将xml文件中的属性初始化。 |
在自定义控件若需要xml文件中使用,就必须重写带上两个参数的构造方法 。 | ||
infiateException之style与android:textstyle的区别 | style中定义 要用 style=“@style/NomalText” | |||
TransactionTooLargeException | Binder最大通常为1MB ,如果大于1MB就会抛出TransactionTooLargeException 异常 。 这个异常经常出现在图片的分享功能中。 在采集打点数据时也会看到这类异常 ,(数据积累到一定量后才发生的) |
不要将大量的数据传入Binder 不如说图片 | ||
系统碎片化化异常(一是版本差异 二是不同的ROM) |
||||
NosuchMethodError | java.lang.NoSuchMethErroor | 方法被放弃,谨慎使用 。 | 在开发阶段Android Lint,里面又被废弃方法的警告。 如果使用要进行Android 系统版本的判断。 int sysVersion =Integer.paresInt(android.os.Build.VERDION.SDK) ; if..... |
|
RemoteViews | android.widget.RemoteView$Refiection.writeToParcel(Remote.java:763) | RemoteViews使用的地方有两个 , APPWidget ,Notification。对于APP类而言有机会用到的是后者。 Notification 有一个contentView属性,就是RemoteView类型 。给imageview设置图片 textVie 绑定资源ID 。 |
异常:当Bitmap为null时 当你的string 为""或者为null Android版本是4.1时 不会出现以上情况。只会表现出异常并不会大致程序崩溃 。 |
|
pointerIndex out of range | java.lang.IllegalArgumentException:pointerIndex out of rangeat android view .motionEvent.nationGetAxiValue(Native Method) | 在做多点触控放大缩小,操作自己所绘制的图形时发生这个异常,如果是操作图片的方法缩小,多点触控不会出现这个错误 。这个bug是Android系统原因导致的,所以简单有效的办法是在绘制时捕获这个异常 。 在用viewpage的话 ,onInterceptTouchEvent返回false 会导致viewpage翻页出现bug 。 方法一: public fioat spacing (MotionEvent event){ try{ x =event.getX(0) -event.getX(i) ; y=event.get(0)-event.getY(i); }catch(IllegalArgumentException){ e.printStackTrance() ; } } |
方法二:1.让view创建一个子view继承自它们中的某一个。 2.重写这个 view的onInterceptTouchEvent和onTouchEvent 3.为上述这个两个方法增加try。。catch语句,捕获已知的异常 。 try{ super.onIntercepttouchEvent(MotionEvent ev) }catch(IllegalArgumentException){ e.printStackTrance() ; } try{ super.onTouchEvent(MotionEvent ev) }catch(IllegalArgumentException){ e.printStackTrance() ; } 至少在4.1 上是好用的。 |
|
securityException 之一 Intent中的图片太大 | 在跳转的extra中有bitmap应该减少要传输的图片的体积大小,或者通过保存图片的SD卡中或者通过URI方式传递图片参数,否则,图片太大,就会有上述错误。1MB是一个临界点 。 | |||
SecurityException 之二 动态加载其他的apk的activity 。 | 如果在apk中动态的注册Broadcast ,那么Launcher动态加载该apk时 ,就有可能出现java.lang.secuityException异常 | 修改之前注册的BroadcastReceiver的地方 ,通过ContextHOder()来=注册BroadcastReceiver ,把apk重新部署验证即可 。 | ||
SecurityException 之三 No permission to modify thread | App经常会申请一些权限 ,而有些手机的ROM处于安全考虑,会禁止这些权限 ,那么当APP使用这些权限时 ,就会发生崩溃 。 | 在执行某些安全相关的操作时 ,要么加if语句跳过要么使用try...catch.. 捕获这类异常 ,宁肯点击无效也不能崩溃 。如电话拨打 有些手机会禁止 。即使在功能清单文件中配置了页不行 ,我们要先判断是否有打电话的权限,以确保不发生崩溃 。 | ||
view的getDrawingCache()返回null | 当背景图太大,超过屏幕的大小 ,就导致getDrawingCache()返回的结果是null ,从而抛出NullPointEXception 异常 | 控制图片的大小 ,剪裁或者等比缩放 。 | ||
DeadObjectException | ||||
anderoid 2.1 不支持SSL | 版本判断 | |||
viewFlipper | 横竖屏切换引发的异常是由于onDetachedFromWindow()在onAttachedToWindow() ; | 重写viewFlipper的OnDetachedFromWindow()方法 |
||
ActivtyNotFoundException | 发生在4.0 以上出现 。原因 ,是4.0 以上用来的网络设置方式舍弃了 。 |
|||
Android2.2 不支持xlargeScreens | NO resource identifier found for attribute ‘xlargeScreens’in package ‘Android’ | 在功能清单文件中supports-scress标记中 ,原因xlargeScreens 属性在API9(2.3)中才支持 。 | ||
package manager has died | Package manager has died at android.app.applicationPackageManager.getApplication(ApplicationPackageManager.java..) | |||
spannableString 与富文本字符串 | ||||
can not perfform this action after onSaveInstanceState | commit方法在activity的OnSaveInstanceState()之后调用 ,因为。。。 | |||
service Intent must be explicit | service Intent must be explicit | 在5.0系统后会产生这样的崩溃 ,直接通过action启动service ,就会导致这个问题 ,必须指定component 或者package 才能避免这类问题 。 | ||
SqLite相关异常 |
||||
No transaction is active | ||||
忘记关闭Cursor | ||||
数据库被锁定 | ||||
试图再打开已经关闭的对象 | ||||
文件加密了或无数据库 | ||||
webview中的Sqlite 缓存导致的崩溃 | ||||
webview中的cache数据 | ||||
磁盘读写错误 | ||||
android_metadata表不存在 | ||||
android_metadate表中的locale字段 | ||||
数据库或者磁盘满了 | ||||
不明错误 |
||||
内存溢出 | ||||
verify Failed | ||||
TimeOutException | ||||
json 解析异常 | ||||
jsonArray在初始化时为空 | ||||
第三方SDK 抛出的crash | ||||
两个不同类型的view有相同的id | ||||
LayoutInfiater.from().infitate()使用不当导致的崩溃 | ||||
viewgroup | ||||
monkey点击过快导致的崩溃 | ||||
图片缩放很多倍 | ||||
图片宽度为0 | ||||
不能重复添加组件 | ||||