6.6 资源相关的异常
资源相关的异常,基本都容易解决。但是有一种情况非常恶心,就是明明apk包中有这个资源文件,但是仍然抛出该资源找不到的异常,对此我们也只好认为是内存溢出(OOM)了。
6.6.1 Resources$NotFoundException
异常中的关键字:
android.content.res.Resources$NotFoundException:String resource ID#0x1
发生频率:★★★
这种异常一般是因为参数int resId错误,我们把String赋值给int的resId,所以编译器找不到正确的resource而报错。
最简单的例子,检查一下项目中以下语句的使用:
Toast.makeText(); textView1.setText();
类似还有一些,这里不列举出来了。这样的函数通常有几个重载,如TextView的重载函数如下:
TextView.setText(CharSequence text); TextView.setText(int resId);
如果不小心将一个int值传给了它,那它不会显示该int值,而是跑到工程下去找一个对应的resource的id,那当然是找不到的,于是就报错了。
比如我这里是这样的:
count.setText(incall.getCount());
incall.getCount();返回的是一个int值,直接执行setText方法是肯定不行的,就会发生上述的Crash。
解决办法如下:
count.setText(String.valueOf(incall.getCount()));
或者
count.setText(incall.getCount() + "");
6.6.2 StackOverfiowError
异常中的关键字:
StackOverfiowError
发生频率:★★★
发生这种事情,主要是因为Layout布局文件结构嵌套层次太深。我们应尽量控制在5层以下。要经常使用Hierarchy View对其进行优化,移除不必要的视图。
产生这种Crash的第二种原因是,在App退出的时候,如果App中有多个线程,那么在退出App的时候可能不能完全关闭App,即使使用finish方法也做不到,必须使用System.exit(0)这样的语句才可以。
这是因为finish方法只能退出当前Activity,但还可能有其他Activity未关闭,这些Activity中有没结束的线程,从而会有一些资源没有释放。
而exit(int code)方法可以使进程退出能保证把所有线程的栈空间释放,否则残留的线程栈空间无法回收,将会导致该进程新建线程时栈空间不足,而发生StackOverfiowError的异常。
无论是哪种情况导致的StackOverFlowError,都是由无限递归引起的。在JVM中有一个栈,预设了一个深度,当超出这个深度时,就会抛出StackOverFlowError。我们上述种种解决方案,都是在避免无限循环调用。
6.6.3 UnsatisfiedLinkError
异常中的关键字:
java.lang.UnsatisfiedLinkError:dalvik.system.PathClassLoader[DexPathList[[zip file"/data/app/appname-1.apk"]……."
发生频率:★★★★★
遇到这个Crash,肯定是so格式的文件没有加载到。检查libs的armeabi目录下的so文件是否存在。
此外,不能只看armeabi下是否有so文件,还要看x86目录下so文件是否存在,如果没有,在x86的设备上仍然是加载不到。
由此而上升到CPU指令集,Android上一共有4种,armeabi、armeabi-v7a、mips和x86。处理so文件时要格外小心。 [1]
如图6-3所示,armeabi和armeabi-v7a的so数量不一致,是典型的会导致UnsatisfiedLinkError的场景。
图6-3 某App下的so文件
6.6.4 InfiateException之FileNotFoundException
异常中的关键字:
Caused by:android.view.InfiateException:Binary XML file line#18:Error infiating class<unknown>at android.view.LayoutInfiater.createView(LayoutInfiater.java:518)
Caused by:java.io.FileNotFoundException:res/drawable-hdpi/add.png at android.content.res.AssetManager.openNonAssetNative(Native Method)
发生频率:★★★★★
咋一看,还以为是资源找不到,于是去相应的drawable目录下去寻找,就发现这个add.png文件确实存在啊。
我在网上找了好久好久关于这个Crash的描述,但大都不满意。目前看到的一种比较靠谱的说法是GC导致的。Activity销毁了,但是里面涉及的资源并没有被回收,于是便产生内存泄露了,但是表现为FileNotFoundException。
对此,相应的解决方案是,在Activity的onStop方法中,手动释放每一张图片资源。 [2]
6.6.5 InfiateException之缺少构造器
异常中的关键字:
android.view.InfiateException:Binary XML file line#:Error infiating class com.example.activity1.TestButton
发生频率:★★★
创建自定义view的时候,碰到上述这个异常,反复研究后发现是缺少一个构造器造成。其中第二个参数用来将xml文件中的属性初始化。
自定义控件若需要在xml文件中使用,就必须重写带如上两个参数的构造方法。添加后即可正常使用了:
public MyView(Context context, AttributeSet paramAttributeSet) { super(context, paramAttributeSet); }
补齐这个构造器,异常就消失了。
6.6.6 InfiateException之style与android:textStyle的区别
异常中的关键字:
android.view.InfiateException:Binary XML file line#14:Error infiating class
发生频率:★★
在一个xml布局文件中,对于实现已经定义好的样式:
<style name="NormalText"> <item name="android:textSize">14sp</item> <item name="android:textStyle">normal</item> <item name="android:textColor">@color/Gray1</item> </style>
去引用:
<TextView android:id="@+id/tvUserName" android:text="@string/hello_world" android:layout_width="230dp" android:layout_height="30dp" android:layout_marginLeft="10dp" android:layout_marginTop="10dp" android:textStyle="@style/NormalText" />
结果发现运行时出错,抛出android.view.InfiateException:Binary XML file line#14异常。
按图索骥,我们找到资源文件的第14行,发现是style的问题,后来去参考Android官方文档,感觉应该是把:
android:textStyle="@style/NormalText"
改为:
style="@style/NormalText"
修改后的布局文件如下所示:
<TextView android:id="@+id/tvUserName" android:text="@string/hello_world" android:layout_width="230dp" android:layout_height="30dp" android:layout_marginLeft="10dp" android:layout_marginTop="10dp" />
6.6.7 TransactionTooLargeException
异常中的关键字:
android.view.InfiateException:Binary XML file line#14:Error infiating class
发生频率:★★★
官方文档里的解释是,Binder最大通常限制为1MB,如果大于1MB的话,就会抛出TransactionTooLargeException的异常。
相应的解决方法是:不要将大量数据传入Binder,比如说图片。
这个Crash经常出现在图片分享的功能中,因为我们要给第三方分享SDK传递很大的图片。此外,使用采集打点数据时也会看到这类Crash,因为打点的机制不是每点击一次按钮就发一次,而是数据积累到一定量后再发,这个阀值太大就会导致抛出TransactionTooLargeException异常。
[1] 详细情况请参见“Androidndk开发打包时我们应该如何注意平台的兼容”,文章地址:http://www.cnblogs.com/devinzhang/archive/2012/02/29/2373729.html。
[2] 关于这个Crash的详细描述,请参见http://blog.csdn.net/yiding_he/article/details/38597703。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论