一、 log文件的产生(Fatal/ANR)

1. 程序异常退出(fatal)

2. 程序强制关闭(fatal)

3. 程序无响应(Application No Response--ANR)

4. native层:Tombstone crash

5. Kernel层:kernel panic

出现情况有一下两种:

1. 界面操作按钮的点击等待时间超过5s

2. HandleMessage回调函数执行超过10s,BroadcasterReciver里的onRecive()方法超过10s

二、 log文件包含内容

1. 系统基本信息,包括内存,cpu,进程队列,虚拟内存,垃圾回收等信息

2. 事件信息,即主要分析的信息

3. 虚拟机信息,包括进程的、线程的跟踪信息

三、 观看log文件的步骤

1. 如果是ANR问题,搜索ANR IN定位到关键事件信息

2. 如果是Force closed或其他异常信息,搜索fatal exception,定位到关键事件信息

3.      定位到关键事件信息后,如果信息不明确,在去搜索应用程序包的虚拟机信息,查看具体的进程和线程跟踪日志来定位到代码。
 

一、java.lang.IllegalArgumentException
解决方案:

参数不匹配异常,通常由于传递了不正确的参数导致。

常见于:

Activity、Service 状态异常;
非法 URL;
UI 线程操作;
Fragment 中嵌套了子 Fragment,Fragment 被销毁,而内部 Fragment 未被销毁,所以导致再次加载时重复,在 onDestroyView() 中将内部Fragment 销毁即可
在请求网络的回调中使用了 glide.into(view),view 已经被销毁会导致该错误。
二、java.lang.NullPointerException
解决方案:

该异常表示尝试去调用 virtual method,使用了一个空对象引用,建议您检查引用的对象是否为空。

这种异常通常是调用一个对象的方法抛出的,凡是调用一个对象的方法之前,一定要进行判空或者进行 try-catch,这样基本可以规避大部分空指针异常。

三、java.util.ConcurrentModificationException
解决方案:

该异常表示迭代器迭代过程中,迭代的对象发生了改变,如数据项增加或删除。

由于迭代对象不是线程安全,在迭代的过程中,会检查 modCount 是否和初始 modCount 即 expectedModCount 一致,如果不一致,则认为数据有变化,迭代终止并抛出异常。常出现的场景是,两个线程同时对集合进行操作,线程1对集合进行遍历,而线程2对集合进行增加、删除操作,此时将会发生 ConcurrentModificationException 异常。

具体方法:多线程访问时要增加同步锁,或者建议使用线程安全的集合:

使用 ConcurrentHashMap 替换 HashMap,CopyOnWriteArrayList 替换 ArrayList;
或者使用 Vector 替换 ArrayList,Vector 是线程安全的。Vector 的缺点:大量数据操作时,由于线程安全,性能比 ArrayList 低
实战案例:

四、java.lang.IllegalStateException
java.lang.IllegalStateException 异常产生的原因及解决办法

错误类型大致为以下几种:
java.lang.IllegalStateException:Cannot forward a response that is already committed

IllegalStateException:response already commited

IllegalStateException:getOutputStream() has already been called for this request

IllegalStateException: Can not perform this action after onSaveInstanceState:
解决办法:onSaveInstanceState 方法是在该 Activity 即将被销毁前调用,来保存 Activity 数据的,如果在保存玩状态后再给它添加 Fragment 就会出错。解决办法就是把 commit() 方法替换成 commitAllowingStateLoss()

补充另一种异常情况:
java.lang.IllegalStateException
Can’t change tag of fragment d{e183845 #0 d{e183845}}: was d{e183845} now d{e183845 #0 d{e183845}}
经查,我在显示 fragment 的代码中使用了:
fragment.show(getSupportFragmentManager, fragment.toString());
而这里是因为两次 toString() 结果不同,导致不同的 tag 指向的是同一个 fragment。获取 fragment 的 tag 的正确方法应该是使用其提供的 fragment.getTag() 方法。

补充另一种异常情况:
java.lang.IllegalStateException
Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 37 path $.data
错误原因:该异常是由于服务器错误返回的 JSON 字符串和服务器正常时返回的 JSON 字符串结构不同,导致利用 Gson 解析的时候报了一个异常:本该去解析集合却强制去解析对象所致。
解决办法:在使用 Gson 解析 JSON 时 try cash 一下,不报错按照正常逻辑继续解析,报异常则处理为请求失败逻辑即可。

五、android.content.res.Resources$NotFoundException
解决方案:

该异常表示找不到字符串资源 ID,检查引用的字符串资源 ID 是否在 R.java 文件中定义,或者检查传递的 ID 参数是否正确。

这种报错通常是因为将 int 等整型变量作为了参数传给了 View.setText() 调用,这种情况下该整型变量将被认为是一个资源ID号去资源列表中查找对应的资源,导致找不到对应资源错误。

解决方法是把 int 型数据改成 String 类型,如 setText(Integer.toString(value)) 或 setText("" + value)。另外,建议在使用 inflate() 方法的时候,传入的布局资源最好使用 R.layout.xxx 来指定,这样可以降低出错的概率。