Anroid开发中遇到的异常收集汇总

开发Android过程中,我们可能已经接触过成百上千个异常了。
但,有时候我们可能同样的问题,再出现或许我们还是不知道如何解决。

嗯,于是,我决定用这篇文章把这些经历记录下来,
就算暂时不会用上,但难保证以后不会,毕竟好记性不如烂笔头。

后面还有查bug的一些实用技巧,我觉得我们都应该走出自己的舒适圈!


各种异常及解决方案

java.lang.RuntimeException: Canvas: trying to use a recycled bitmapandroid.graphics.Bitmap@40536868

问题导致原因

比如ImageView 调用了setImageBitmap(bitmap),但此时的bitmap已被回收了

解决方案

可用isRecycled()判断图片是否被回收。(在特殊情况下,可两份bitmap轮换使用,bitmap数量少,占用内存不多的情况下)

注意:图片被回收了,不代表Bitmap 为空。

IllegalArgumentException: View not attached to window manager.

常出现地点:Activity里面显示弹框。

问题导致的原因:当前activity已经被销毁,然后在该activity显示弹框。

解决方案:使用Activity.isFinishing()方法,判断当前activity是否被销毁。(方式2:使用LiveData监听数据,显示弹框,无需判断)

java.util.ConcurrentModificationException

异常原因:ArrayList是非线程安全的,当同时在遍历和修改ArrayList时,就会出现该异常

解决方法:使用Vector替换ArrayList,Vector是线程安全的。Vector的缺点:大量数据操作时,由于线程安全,性能比ArrayList低 (方式2:倒序遍历的时候,才作remove操作)

java.lang.StackOverflowError

异常原因:当前线程的栈满了(可导致的情况:死循环操作 或 无限递归)

java.lang.ArithmeticException: divide by zero

异常原因:该异常最有可能出现在代码运行时分母为0,long数据类型转int,也有可能导致该异常。超过int存储的最大值时

java.lang.NoSuchMethodError

异常原因:该异常表示找不到指定方法
解决方案:这种问题主要是由于Android系统和Rom厂商定制化导致的碎片化问题,很难根治,建议做好机型适配,解决top机型问题:
1.如果是机型相关问题,则看下是否添加了该崩溃机型cpu架构的so库;
2.如果是系统API方法,使用时要注意API Level,如果设置的target version过高,调用低于设置版本的API方法将会报错。
3.setBackground方法在API >= 16才生效

Caused by: android.os.TransactionTooLargeException

异常原因:Binder传输的数据太大
解决方案:不要将大量数据传入Binder

android.view.WindowManager$BadTokenException: Unable to add window – token

异常原因:使用getApplicationContext()获得的Context,而必须使用Activity,因为只有一个Activity才能添加一个窗体。
解决方案:采用当前Activity的Context

安装APK出现异常 Failure [INSTALL_FAILED_TEST_ONLY: installPackageLI]

解决方案:解决:gradle.properties中加入android.injected.testOnly=false(当然adb install -t 肯定也是可以解决的,不想麻烦用这种方法)

app不能抓包

  • 在debug模式下抓包的一种方案

    • AndroidManifest.xml

      1
      2
      3
      4
      5
      <application
      android:name="xx.xx.application"
      android:icon="@mipmap/ic_launcher"
      android:label="@string/app_name"
      android:networkSecurityConfig="@xml/network_security_config"/>
    • xml/network_security_config.xml

      1
      2
      3
      4
      5
      6
      7
      8
      <?xml version="1.0" encoding="utf-8"?>
      <network-security-config>
      <debug-overrides>
      <trust-anchors>
      <certificates src="@raw/debug_cas"/>
      </trust-anchors>
      </debug-overrides>
      </network-security-config>
  • 其他相关配置了解

特别注意:其他不好找的问题

这类问题,超级简单,也是超级不好找的。比如:

  • == 写成 =
  • 大括号写错位
  • 嗯,还有一些字符超级像的。(闻所未闻)

图片下载中途中断,如何保证图片完整性

嗯,so easy! 下载文件的时候,可以给个临时文件目录,比如加.temp后缀;然后下载完成后,再把文件目录修改回来。

  • 重命名操作
    1
    OldFile.renameTo(new File(NewFilePath));

java.lang.IllegalStateException

java.lang.IllegalStateException: Cannot invoke setValue on a background thread

MutableLiveData 数据在子线程:
请调用postValue,使用setValue则会出现该异常

No such property: FOR_RUNTIME for class: org.gradle.api.attributes.Usage

bintray 版本较低,需要升级

1
2
3
dependencies {
classpath 'com.novoda:bintray-release:0.8.0'
}

Glide OOM问题解决方法汇总

1、引入largeHeap属性,让系统为App分配更多的独立内存。
2、禁止Glide内存缓存。设置skipMemoryCache(true)。
3、自定义GlideModule。设置MemoryCache和BitmapPool大小。
4、升级到Glide4.0,使用asDrawable代替asBitmap,drawable更省内存。
5、ImageView的scaleType为fitXY时,改为fitCenter/centerCrop/fitStart/fitEnd显示。
6、不使用application作为context。当context为application时,会把imageView是生命周期延长到整个运行过程中,imageView不能被回收,从而造成OOM异常。
7、使用application作为context。但是对ImageView使用弱引用或软引用,尽量使用SoftReference,当内存不足时,将及时回收无用的ImageView。
8、当列表在滑动的时候,调用Glide的pauseRequests()取消请求,滑动停止时,调用resumeRequests()恢复请求。
9、Try catch某些大内存分配的操作。考虑在catch里面尝试一次降级的内存分配操作。例如decode bitmap的时候,catch到OOM,可以尝试把采样比例再增加一倍之后,再次尝试decode。
10、BitmapFactory.Options和BitmapFactory.decodeStream获取原始图片的宽、高,绕过Java层加载Bitmap,再调用Glide的override(width,height)控制显示。
11、图片局部加载。参考:SubsamplingScaleImageView,先将图片下载到本地,然后去加载,只加载当前可视区域,在手指拖动的时候再去加载另外的区域。

todo 遇到再加

查bug的一些实用技巧

  • 优先解决那些可重现的,可重现的bug很好找,反复调试测试就好了(debug或log输出查找等),先把好解决的干掉,这样最节约时间。
  • 对于自己不熟悉的业务,最好先问前辈,毕竟有可能是他埋的
  • 对于有些bug现象不太明显的,那就想办法增大它的破坏性,把现象放大。这只是个思路,具体怎么放大只能根据具体的代码来定。(有点极端测试的样子)
  • 二分法定位,把程序逻辑一点点注释掉,看看还会不会出问题,类似二分查找的方法,逐步缩小问题范围。
  • 通过口述文字,模拟还原现场。这个可能需要口述人和开发默契配合。
  • 制作工具,针对某些bug编写一些调试辅助工具。(比如:利用第三方工具在浏览器查看sqlite数据库)
  • 掩盖问题(不到万不得已,千万不要尝试。比如:try catch 一下,然后catch中什么都没做)