Android实际开发bug大总结

目录介绍

  • 1.1 java.lang.UnsatisfiedLinkError找不到so库异常

  • 1.2 java.lang.IllegalStateException非法状态异常

  • 1.3 android.content.res.Resources$NotFoundException

  • 1.4 java.lang.IllegalArgumentException参数不匹配异常

  • 1.5 IllegalStateException:Can't compress a recycled bitmap

  • 1.6 java.lang.NullPointerException空指针异常

  • 1.7 android.view.WindowManager$BadTokenException异常

  • 1.8 java.lang.ClassCastException类转化异常

  • 1.9 Toast运行在子线程问题,handler问题

  • 2.1 java.lang.ClassNotFoundException类找不到异常

  • 2.2 java.util.concurrent.TimeoutException连接超时崩溃

  • 2.3 java.lang.NumberFormatException格式转化错误

  • 2.4 java.lang.IllegalStateException: Fragment not attached to Activity

  • 2.5 ArrayIndexOutOfBoundsException 角标越界异常

  • 2.6 IllegalAccessException 方法中构造方法权限异常

  • 2.7 android.view.WindowManager$BadTokenException,dialog弹窗异常

  • 2.8 java.lang.NoClassDefFoundError 找不到类异常

  • 2.9 Android出现:Your project path contains non-ASCII characters.

  • 3.1 OnErrorNotImplementedException【 Can't create handler inside thread that has not called Looper.prepare()】

  • 3.2 adb.exe,start-server' failed -- run manually if necessary

  • 3.3 java.lang.IllegalStateException: ExpectedBEGIN_OBJECT but was STRING at line 1 column 1 path $

  • 3.4 android.content.ActivityNotFoundException: No Activity found to handle Intent

  • 3.5 Package manager has died导致崩溃

  • 3.6 IllegalArgumentException View添加窗口错误

  • 3.7 IllegalStateException: Not allowed to start service Intent异常崩溃

  • 3.8 java.lang.IllegalStateException:Can not perform this action after onSaveInstanceState

  • 3.9 在Fragment中通过getActivity找不到上下文,报null导致空指针异常

  • 4.1 IllegalArgumentException导致崩溃【url地址传入非法参数,转义字符】

  • 4.2 ClassNotFoundException: Didn't find class "*****" on path: /data/app/**错误

  • 4.3 NoClassDefFoundError异常【该异常表示找不到类定义】

  • 4.4 公司之前项目使用客服udesk,sdk更新后初始化导致崩溃问题

  • 4.5 java.util.concurrent.ExecutionException: com.android.tools.aapt2.Aapt2Exception

  • 4.6 java.util.concurrent.ExecutionException: com.android.ide.common.process.ProcessException

  • 4.7 00768556 /vendor/lib/libllvm-glnext.so [armeabi-v8]无法加载so库导致崩溃

  • 4.8 Only the original thread that created a view hierarchy can touch its views

  • 4.9 NoSuchMethodException  android.support.v4.app.Fragment$InstantiationException

详解

1.1 java.lang.UnsatisfiedLinkError

A.详细崩溃日志信息

 

# main(1)
java.lang.UnsatisfiedLinkError
dalvik.system.PathClassLoader[DexPathList[[zip file "/data/app/com.paidian.hwmc-1/base.apk", dex file "/data/app/com.paidian.hwmc-1/base.apk"],nativeLibraryDirectories=[/data/app/com.paidian.hwmc-1/lib/arm64, /data/app/com.paidian.hwmc-1/base.apk!/lib/arm64-v8a, /vendor/lib64, /system/lib64]]] couldn't find "libijkffmpeg.so"

 

B.查看崩溃类信息

这个异常类的大意是:如果Java虚拟机找不到声明为本机的方法的适当本机语言定义,则引发。

 

public class UnsatisfiedLinkError extends LinkageError {
private static final long serialVersionUID = -4019343241616879428L;

public UnsatisfiedLinkError() {
super();
}

public UnsatisfiedLinkError(String s) {
super(s);
}
}

 

C.项目中异常分析

    • 根据实际项目可知,当准备播放视频时,找不到libijkffmpeg.so这个库,导致直接崩溃。

D.引发崩溃日志的流程分析

F.解决办法

    • 1.建议检查so在安装的过程中是否丢失,没有放入指定的目录下;

    • 2.调用loadLibrary时检查是否调用了正确的so文件名,并对其进行捕获,进行相应的处理,防止程序发生崩溃;

    • 3.检查下so的架构是否跟设备架构一至(如在64-bit架构下调用32-bit的so)。

    • 报这个错误通常是so库加载失败,或者找不到准备执行的JNI方法:

    • 代码展示

 

 

ndk {
//根据需要 自行选择添加的对应cpu类型的.so库。
//abiFilters 'armeabi', 'armeabi-v7a', 'arm64-v8a', 'x86', 'mips'
abiFilters 'armeabi-v7a'
}

dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
//这两个是必须要加的,其它的可供选择
compile 'tv.danmaku.ijk.media:ijkplayer-java:0.8.4'
compile 'tv.danmaku.ijk.media:ijkplayer-armv7a:0.8.4'
//其他库文件
//compile 'tv.danmaku.ijk.media:ijkplayer-armv5:0.8.8'
//compile 'tv.danmaku.ijk.media:ijkplayer-arm64:0.8.8'
//compile 'tv.danmaku.ijk.media:ijkplayer-x86:0.8.8'
//compile 'tv.danmaku.ijk.media:ijkplayer-x86_64:0.8.8'
}

 

G.知识延申

  • Android 应用开发者应该对 UnsatisfiedLinkError 这种类型的错误比较熟悉了,这个问题一直困扰着广大的开发者,那么有没有想过有可能你什么都没做错,也会出现这个问题呢?

  • 我们在 Android 应用开发测试过程中曾经碰到过这样的案例,apk 在某机型上安装完成之后运行即崩溃,报错 UnsatisfiedLinkError。

  • java.lang.UnsatisfiedLinkError: Couldn’t load mobsec from loader dalvik.system.PathClassLoader.....findLibrary returned null

  • 首先怀疑是在 apk 中相应的 libs\abi 目录下没有放置 libmobsec.so,然而检查发现这个 so 在所有的 libs\abi 下都有放置过,继续排查;

  • 然后的想法是放置的 so 不是对应 abi 的,比如由于粗心在 armeabi 目录下放置了 x86 指令集的 so,导致在 armeabi 指令集手机上加载出错,这个也被排除掉;

  • 就在没有头绪的时候,想到 System.loadLibrary 函数加载 so 时,系统是从指定的路径下加载的,那么这个路径下 so 是否存在呢?

  • 我们知道应用的私有 Native library 目录 /data/data/packagename/lib 是一个符号链接,链接到 /data/app-lib/ 目录,System.loadLibrary 是到这个目录去尝试加载 so 的。

  • adb shell 到这个路径下,使用命令 ls 查看,果然这个 libmobsec.so 是不存在的。那么是什么原因导致的呢?

  • 分析 Android 系统源码的实现,发现 /data/app-lib/ 这个目录下的 so ,是在系统安装 apk 时从 apk 的 lib 目录下去抽取的。

 

1.2 java.lang.IllegalStateException非法状态异常

A.详细崩溃日志信息

    • onSaveInstanceState方法是在该Activity即将被销毁前调用,来保存Activity数据的,如果在保存玩状态后 再给它添加Fragment就会出错。

 

IllegalStateException: Can not perform this action after onSaveInstanceState:

 

B.查看崩溃类信息

  • 在非法或不适当的时间调用方法的信号。换句话说,Java环境或Java应用程序没有处于请求操作的适当状态。

 

public class IllegalStateException extends RuntimeException {
public IllegalStateException() {
super();
}

public IllegalStateException(String s) {
super(s);
}

public IllegalStateException(String message, Throwable cause) {
super(message, cause);
}

public IllegalStateException(Throwable cause) {
super(cause);
}

static final long serialVersionUID = -1848914673093119416L;
}

 

C.项目中异常分析

    • 分析

D.引发崩溃日志的流程分析

F.解决办法

    • 解决办法就是把commit()方法替换成 commitAllowingStateLoss()

G.其他延申

    • 错误类型大致为以下几种:

 

java.lang.IllegalStateException:Can't change tag of fragment d{e183845 #0 d{e183845}}: was d{e183845} now d{e183845 #0 d{e183845}}
java.lang.IllegalStateException:Expected BEGIN_ARRAY but was BEGIN_OBJECT at line 1 column 37 path $.data

 

  • 第一种:我在显示fragment的代码中使用了:fragment.show(getSupportFragmentManager, fragment.toString());而这里是因为两次toString()结果不同,导致不同的tag指向的是同一个fragment。获取fragment的tag的正确方法应该是使用其提供的fragment.getTag()方法。

  • 第二种:该异常是由于服务器错误返回的JSON字符串和服务器正常下时返回的JSON字符串结构不同,导致利用Gson解析的时候报了一个异常:本该去解析集合却强制去解析对象所致.解决办法:在使用Gson解析JSON时try cash一下,不报错按照正常逻辑继续解析,报异常则处理为请求失败逻辑即可.

1.3 android.content.res.Resources$NotFoundException

A.详细崩溃日志信息

    • Android资源不是可绘制的(颜色或路径)

 

Resource is not a Drawable (color or path): TypedValue{t=0x2/d=0x7f040151 a=2}
android.view.LayoutInflater.createView(LayoutInflater.java:620)

 

B.查看崩溃类信息

  • 当找不到请求的资源时,资源API将引发此异常。

 

public static class NotFoundException extends RuntimeException {
public NotFoundException() {
}

public NotFoundException(String name) {
super(name);
}

public NotFoundException(String name, Exception cause) {
super(name, cause);
}
}

 

C.项目中异常分析

    • 由于将图片资源拷贝到了drawable-land-xhdpi目录下,本来应该拷贝到drawable-xhdpi目录下。

D.引发崩溃日志的流程分析

F.解决办法

    • 1.引用的资源ID 是否能匹配到R.java文件中定义的资源;

    • 2.是否因为缓存等原因导致编译APK时未把资源文件打包进去,可以把APK反编译检查下;

    • 3.是否使用了一个错误的类型来引用了某个资源或者配置资源时存在错误;

    • 4.是否将Int等整型变量作为了参数传给了View.setText调用,这种情况下该整型变量将被认为是一个资源ID号去资源列表中查找对应的资源,导致找不到对应资源错误;解决方法是做类型转换View.setText(String.valueOf(Int id))。

1.4 java.lang.IllegalArgumentException参数不匹配异常

  • A.详细崩溃日志信息

  • B.查看崩溃类信息

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

 

public class IllegalArgumentException extends RuntimeException {
public IllegalArgumentException() {
super();
}

public IllegalArgumentException(String s) {
super(s);
}

public IllegalArgumentException(String message, Throwable cause) {
super(message, cause);
}


public IllegalArgumentException(Throwable cause) {
super(cause);
}

private static final long serialVersionUID = -5365630128856068164L;
}

 

  • C.项目中异常分析

  • D.引发崩溃日志的流程分析

  • F.解决办法

  • G.常见的出现场景

    • Activity、Service状态异常;

    • 非法URL;

    • UI线程操作。

    • Fragment中嵌套了子Fragment,Fragment被销毁,而内部Fragment未被销毁,所以导致再次加载时重复,在onDestroyView() 中将内部Fragment销毁即可

    • 在请求网络的回调中使用了glide.into(view),view已经被销毁会导致该错误

1.5 IllegalStateException:Can't compress a recycled bitmap

  • A.详细崩溃日志信息

    • 无法压缩回收位图

 

Can't compress a recycled bitmap
com.paidian.hwmc.utils.i.a(FileUtils.java:75)

 

B.查看崩溃类信息

  • 如果位图已被回收,则希望抛出异常的方法将调用此值。知道了崩溃的具体位置,就该分析具体的原因呢!

 

public boolean compress(CompressFormat format, int quality, OutputStream stream) {
checkRecycled("Can't compress a recycled bitmap");
//省略代码
return result;
}

//如果位图已被回收,则希望抛出异常的方法将调用此值。
private void checkRecycled(String errorMessage) {
if (mRecycled) {
throw new IllegalStateException(errorMessage);
}
}

 

  • C.项目中异常分析

    • 使用了已经被释放过内存的对象。对于Bitmap:Bitmap  bitmap=一个bitmap对象。使用过程中调用bitmap.recycle(),之后再使用bitmap就会报错。

  • D.引发崩溃日志的流程分析

    • bitmap.recycle()解释如下所示,释放与此位图关联的本机对象,并清除对像素数据的引用。这将不会同步释放像素数据;它只允许在没有其他引用的情况下对其进行垃圾收集。位图被标记为“死”,这意味着如果调用getPixels()或setPixels(),它将抛出异常,而不会绘制任何内容。此操作不能反转,因此只有在确定没有进一步使用位图的情况下才应调用该操作。这是一个高级调用,通常不需要调用,因为当没有对此位图的引用时,普通GC进程将释放此内存。
       

 

Free the native object associated with this bitmap, and clear the reference to the pixel data

 

F.解决办法

  • 第一种:在使用bitmap前增加判断,if (mBitmap.isRecycled()) return null;

1.6 java.lang.NullPointerException空指针异常

  • A.详细崩溃日志信息

 

Please call the AutoSizeConfig#init() first
com.paidian.hwmc.base.BaseApplication.initAutoSizeConfig(BaseApplication.java:386)

 

B.查看崩溃类信息

  • 空指针异常,也是十分常见的一个异常

 

public class NullPointerException extends RuntimeException {
private static final long serialVersionUID = 5162710183389028792L;
public NullPointerException() {
super();
}
public NullPointerException(String s) {
super(s);
}
}

 

  • C.项目中异常分析

    • 空指针发生场景较多,是指某一个对象报null,这个使用去使用它的话就i会报该异常。

  • D.引发崩溃日志的流程分析

    • 查看Log信息看第一行导致空指针发生的代码,直接双击打开报空指针的类

    • 查看该行代码中有几处调用了方法,则有几个对象可能是空的,找出哪个对象是空的

    • 查看这些对方在哪里赋值了

    • 如果没赋值,则给她赋值,问题解决

    • 如果有地方赋值了,则看这个方法有没有被调用(Ctrl + Shift + G)

    • 如果没有调用(可能没调用或可能调用时机太晚),在使用她前先调用赋值,问题解决

    • 如果有调用,则看是不是有其它地方又给她赋值为null了,如果没有设置为null,则要看赋值的变量和我们使用时的变量是否是同一个变量。

    • 导致出现空指针的原因:必须满足两个条件才会发生空指针:引用变量指向了空,并且调用了这个引用的方法

    • 空指针问题解决思路:

  • F.解决办法

    • 1.方法形参要判空后才使用;

    • 2.全局变量容易被系统回收或者更改,使用全局变量前建议判空;

    • 3.第三方接口的调用,对返回值进行判空。

    • 4.请注意线程安全

    • 空指针最为常见,也最容易规避,使用的时候一定要进行null check,采取不信任原则:

1.7 android.view.WindowManager$BadTokenException异常,Toast报错Unable to add window

  • A.详细崩溃日志信息

    • 报错日志,是不是有点眼熟呀?

 

android.view.WindowManager$BadTokenException
Unable to add window -- token android.os.BinderProxy@7f652b2 is not valid; is your activity running?

 

B.查看崩溃类信息

  • 查询报错日志是从哪里来的

  • C.项目中异常分析

  • D.引发崩溃日志的流程分析

    • 这个异常发生在Toast显示的时候,原因是因为token失效。通常情况下,一般是不会出现这种异常。但是由于在某些情况下, Android进程某个UI线程的某个消息阻塞。导致 TN 的 show 方法 post 出来 0 (显示) 消息位于该消息之后,迟迟没有执行。这时候,NotificationManager 的超时检测结束,删除了 WMS 服务中的 token 记录。删除 token 发生在 Android 进程 show 方法之前。这就导致了上面的异常。

    • 测试代码。模拟一下异常的发生场景,其实很容易,只需要这样做就可以出现上面这个问题

 

 

Toast.makeText(this,"潇湘剑雨-yc",Toast.LENGTH_SHORT).show();
try {
Thread.sleep(20000);
} catch (InterruptedException e) {
e.printStackTrace();
}

 

  • F.解决办法

    • 按照源码分析,异常是发生在下一个UI线程消息中,因此在上一个ui线程消息中加入try-catch是没有意义的。而且用到吐司地方这么多,这样做也不方便啦!

    • 目前见过好几种,思考一下那种比较好……

    • 第一种,既然是报is your activity running,那可以不可以在吐司之前先判断一下activity是否running呢?

    • 第二种,抛出异常增加try-catch,代码如下所示,最后仍然无法解决问题

    • 第三种,那就是自定义类似吐司Toast的view控件。个人建议除非要求非常高,不然不要这样做。毕竟发生这种异常还是比较少见的

  • G.哪些情况会发生该问题?

    • UI 线程执行了一条非常耗时的操作,比如加载图片等等,就类似上面用 sleep 模拟情况

    • 进程退后台或者息屏了,系统为了减少电量或者某种原因,分配给进程的cpu时间减少,导致进程内的指令并不能被及时执行,这样一样会导致进程看起来”卡顿”的现象

    • 当TN抛出消息的时候,前面有大量的 UI 线程消息等待执行,而每个 UI 线程消息虽然并不卡顿,但是总和如果超过了 NotificationManager 的超时时间,还是会出现问题

1.8 java.lang.ClassCastException类转化异常

  • A.详细崩溃日志信息

 

android.widget.FrameLayout cannot be cast to android.widget.RelativeLayout
com.paidian.hwmc.goods.activity.GoodsDetailsActivity.initView(GoodsDetailsActivity.java:712)

 

B.查看崩溃类信息

  • 抛出以指示代码试图将对象强制转换为它不是实例的子类。

 

public class ClassCastException extends RuntimeException {
private static final long serialVersionUID = -9223365651070458532L;


public ClassCastException() {
super();
}

public ClassCastException(String s) {
super(s);
}
}

 

  • C.项目中异常分析

    • 该异常表示类型转换异常,通常是因为一个类对象转换为其他不兼容类对象抛出的异常,检查你要转换的类对象类型。

  • D.引发崩溃日志的流程分析

  • F.解决办法

    • 一般在强制类型转换时出现,例如如果A向B转换,而A不是B的父类时,将产生java.lang.ClassCastException异常。一般建议做这时要使用instanceof做一下类型判断,再做转换。

    • 该案例中,需要把FrameLayout更改成RelativeLayout就可以呢

1.9 Toast运行在子线程问题,handler问题

  • A.详细崩溃日志信息

    • 先来看看问题代码,会出现什么问题呢?

 

new Thread(new Runnable() {
@Override
public void run() {
ToastUtils.showRoundRectToast("潇湘剑雨-杨充");
}
}).start();

 

  • 报错日志如下所示:

 

  • 然后找找报错日志从哪里来的

  • 子线程中吐司的正确做法,代码如下所示

 

new Thread(new Runnable() {
@Override
public void run() {
Looper.prepare();
ToastUtils.showRoundRectToast("潇湘剑雨-杨充");
Looper.loop();
}
}).start();

 

得出的结论

  • Toast也可以在子线程执行,不过需要手动提供Looper环境的。

  • Toast在调用show方法显示的时候,内部实现是通过Handler执行的,因此自然是不阻塞Binder线程,另外,如果addView的线程不是Loop线程,执行完就结束了,当然就没机会执行后续的请求,这个是由Hanlder的构造函数保证的。可以看看handler的构造函数,如果Looper==null就会报错,而Toast对象在实例化的时候,也会为自己实例化一个Hanlder,这就是为什么说“一定要在主线程”,其实准确的说应该是 “一定要在Looper非空的线程”。

  • Handler的构造函数如下所示:

 

 

2.1 java.lang.ClassNotFoundException类找不到异常

  • A.详细崩溃日志信息

 

Didn't find class "om.scwang.smartrefresh.layout.SmartRefreshLayout" on path: DexPathList[[zip file "/data/app/com.paidian.hwmc-EsIbVq6e0mFwE0-rPanqdg==/base.apk", zip file "/data/app/com.paidian.hwmc-EsIbVq6e0mFwE0-rPanqdg==/split_lib_dependencies_apk.apk", zip file "/data/app/com.paidian.hwmc-EsIbVq6e0mFwE0-rPanqdg==/split_lib_slice_0_apk.apk", zip file "/data/app/com.paidian.hwmc-EsIbVq6e0mFwE0-rPanqdg==/split_lib_slice_1_apk.apk", zip file "/data/app/com.paidian.hwmc-EsIbVq6e0mFwE0-rPanqdg==/split_lib_s
com.paidian.hwmc.goods.activity.GoodsDetailsActivity.onCreate(GoodsDetailsActivity.java:209)

 

B.查看崩溃类信息

  • 当应用程序尝试使用字符串名称加载类时引发:但无法找到具有指定名称的类的定义。从1.4版开始,已对此异常进行了修改,以符合通用的异常链接机制。在构建时提供并通过{@link#getException()}方法访问的“在加载类时引发的可选异常”现在称为原因,并且可以通过{@link Throwable#getCace()}方法以及前面提到的“遗留方法”进行访问。

 

public class ClassNotFoundException extends ReflectiveOperationException {
private static final long serialVersionUID = 9176873029745254542L;
private Throwable ex;
public ClassNotFoundException() {
super((Throwable)null); // Disallow initCause
}
public ClassNotFoundException(String s) {
super(s, null); // Disallow initCause
}
public ClassNotFoundException(String s, Throwable ex) {
super(s, null); // Disallow initCause
this.ex = ex;
}
public Throwable getException() {
return ex;
}
public Throwable getCause() {
return ex;
}
}

 

  • C.项目中异常分析

    • 该异常表示在路径下,找不到指定类,通常是因为构建路径问题导致的。

  • D.引发崩溃日志的流程分析

  • F.解决办法

    • 1.要找的Class被混淆了,存在但名字变了;

    • 2.要找的Class未被打入Dex,确实不存在,可能是因为自己的疏忽,或编译环境的冲突;

    • 3.要找的Class确实存在,但你的Classlorder找不到这个Class,往往因为这个Classloder是你自实现的(插件化应用中常见)。

    • 类名是以字符串形式标识的,可信度比较低,在调用Class.forName(""),Class.findSystemClass(""),Class.loadClass("")等方法时,找不到类名时将会报错。如果找不到的Class是系统Class,那么可能是系统版本兼容,厂家Rom兼容的问题,找到对应的设备尝试重现,解决方法可以考虑更换Api,或用自己实现的Class替代。

    • 如果找不到的Class是应用自由Class(含第三方SDK的Class),可以通过反编译工具查看对应apk中是否真的缺少该Class,再进行定位,这种往往发生在:

  • G.其他延申

2.2 java.util.concurrent.TimeoutException连接超时崩溃

  • A.详细崩溃日志信息

 

java.util.concurrent.TimeoutException: android.view.ThreadedRenderer.finalize() timed out after 10 seconds
at android.view.ThreadedRenderer.nDeleteProxy(Native Method)
at android.view.ThreadedRenderer.finalize(ThreadedRenderer.java:423)

 

B.查看崩溃类信息

  • 当阻塞操作超时引发的异常。指定超时的阻塞操作需要一种方法来指示已发生超时。对于许多此类操作,可以返回指示超时的值;如果不可能或不需要,则应声明并抛出{@code TimeoutException}。

 

public class TimeoutException extends Exception {
private static final long serialVersionUID = 1900926677490660714L;
public TimeoutException() {}
public TimeoutException(String message) {
super(message);
}
}

 

  • C.项目中异常分析

  • D.引发崩溃日志的流程分析

  • F.解决办法

    • 一般是系统在gc时,调用对象的finalize超时导致,解决办法:

    • 1.检查分析finalize的实现为什么耗时较高,修复它;

    • 2.检查日志查看GC是否过于频繁,导致超时,减少内容开销,防止内存泄露。

  • G.其他延申

2.3 java.lang.NumberFormatException格式转化错误

  • A.详细崩溃日志信息

 

Exception in thread "main" java.lang.NumberFormatException: For input string: "100 "
at java.lang.NumberFormatException.forInputString(NumberFormatException.java:48)
at java.lang.Integer.parseInt(Integer.java:458)
at java.lang.Integer.parseInt(Integer.java:499)

 

B.查看崩溃类信息

  • 引发,以指示应用程序试图将字符串转换为数字类型之一,但该字符串没有适当的格式。

 

public class NumberFormatException extends IllegalArgumentException {
static final long serialVersionUID = -2848938806368998894L;

public NumberFormatException () {
super();
}

public NumberFormatException (String s) {
super (s);
}

static NumberFormatException forInputString(String s) {
return new NumberFormatException("For input string: \"" + s + "\"");
}
}

 

  • C.项目中异常分析

    • 错误关键字 java.lang.NumberFormatException 这句话明确告诉了我们是数字格式异常,接着后面有 For input string: "100 " 提示,这就告诉我们,当前想把 "100 " 转换成数字类型时出错了,这样就很确切了。

  • D.引发崩溃日志的流程分析

  • F.解决办法

    • 解决办法很简单,改成 Integer.parseInt(str.trim()),注意将字符串转化成整数数据类型时,注意需要trim一下。

  • G.其他延申

2.4 java.lang.IllegalStateException: Fragment not attached to Activity

  • A.详细崩溃日志信息

 

java.lang.IllegalStateException: Fragment not attached to Activity

 

  • B.查看崩溃类信息

  • C.项目中异常分析

    • 出现该异常,是因为Fragment的还没有Attach到Activity时,调用了如getResource()等,需要上下文Content的函数。

    • 出现该异常,是因为Fragment还没有Attach到Activity时,调用了如getResource()等,需要上下文Context的函数。解决方法,就是等将调用的代码写在OnStart()中。

  • D.引发崩溃日志的流程分析

  • F.解决办法

    • 将调用的代码运行在Fragment Attached的生命周期内。

    • 第一种:在调用需要Context的函数之前,增加一个判断isAdded()

 

 

if(isAdded()){//isAdded方法是Android系统提供的,只有在Fragment被添加到所属的Activity后才返回true
activity.getResourses().getString(...);
}

 

  • 第二种:如下所示

 

@Override
public void onAttach(Context context) {
super.onAttach(context);
activity = (MainActivity) context;
}

@Override
public void onDetach() {
super.onDetach();
if (activity != null) {
activity = null;
}
}

 

G.其他延申

  • 发生场景:该错误经常发生在fragment的线程中执行了一个耗时操作,线程在执行完毕后会调用getResources来更新ui。如果在线程操作没有完成,就调用getActivity().recreate()重新加载activity或屏幕旋转,这时就会出现Fragment not attached to Activity的错误

2.5 ArrayIndexOutOfBoundsException 角标越界异常

  • A.详细崩溃日志信息

    • 该异常表示数组越界

 

java.lang.ArrayIndexOutOfBoundsException: 0
at com.example.mytest.CityAdapter.setDataNotify(CityAdapter.java:183)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

 

B.查看崩溃类信息

  • 引发,以指示已使用非法索引访问数组。索引不是负的,就是大于或等于数组的大小。

 

public class ArrayIndexOutOfBoundsException extends IndexOutOfBoundsException {
private static final long serialVersionUID = -5116101128118950844L;
public ArrayIndexOutOfBoundsException() {
super();
}
public ArrayIndexOutOfBoundsException(int index) {
super("Array index out of range: " + index);
}
public ArrayIndexOutOfBoundsException(String s) {
super(s);
}
public ArrayIndexOutOfBoundsException(int sourceLength, int index) {
super("length=" + sourceLength + "; index=" + index);
}
public ArrayIndexOutOfBoundsException(int sourceLength, int offset,
int count){
super("length=" + sourceLength + "; regionStart=" + offset
+ "; regionLength=" + count);
}
}

 

  • C.项目中异常分析

  • D.引发崩溃日志的流程分析

  • F.解决办法

    • 这种情况一般要在数组循环前做好length判断,index超出length上限和下限时都会报错。举例如下:一个数组int test[N],一共有N个元素分别是test[0]~test[N-1],如果调用test[N],将会报错。建议读取时,不要超过数组的长度(array.length)。

    • Android中一种常见情形就是上拉刷新中header也会作为listview的第0个位置,如果判断失误很容易造成越界。

  • G.其他延申

2.6 IllegalAccessException 方法中构造方法权限异常

  • A.详细崩溃日志信息

 

Unable to instantiate application com.pedaily.yc.meblurry.App: java.lang.IllegalAccessException

 

B.查看崩溃类信息

  • 当应用程序试图反射地创建实例(数组除外)、设置或获取字段或调用方法时,将引发IllegalAccessException,但当前执行的方法无法访问指定的类、字段、方法或构造函数的定义。

 

public class IllegalAccessException extends ReflectiveOperationException {
private static final long serialVersionUID = 6616958222490762034L;
public IllegalAccessException() {
super();
}
public IllegalAccessException(String s) {
super(s);
}
}

 

  • C.项目中异常分析

    • 错误提示是,构造方法的权限不对

  • D.引发崩溃日志的流程分析

  • F.解决办法

    • 检查了整个Application,才发现,原来有一个无参数的构造方法,被设计成private。修改其为public即可。

  • G.其他延申

    • android BroadcastReceiver遇到java.lang.IllegalAccessException解决方法,错误原因主要是app中其他地方调用了默认的构造函数,必须增加默认构造函数且访问权限为public

2.7 android.view.WindowManager$BadTokenException,dialog弹窗异常

  • A.详细崩溃日志信息

 

Unable to add window -- token android.os.BinderProxy@9a57804 is not valid; is your activity running?
android.view.ViewRootImpl.setView(ViewRootImpl.java:907)

 

B.查看崩溃类信息

  • 在WindowManager中可以找到这个异常类,主要发生在尝试添加视图时引发的

 

public static class BadTokenException extends RuntimeException {
public BadTokenException() {
}

public BadTokenException(String name) {
super(name);
}
}

 

  • C.项目中异常分析

    • 该异常表示不能添加窗口,通常是所要依附的view已经不存在导致的。

  • D.引发崩溃日志的流程分析

  • F.解决办法

    • 之前项目中有一个自定义弹窗,偶尔会报这个错。解决办法如下代码所示

    • 主要逻辑是在弹窗show或者dismiss的时候,都增加了逻辑判断,判断宿主activity存在。

 

 

/**
* 展示加载窗
* @param context 上下文
* @param isCancel 是否可以取消
*/
public static void show(Context context, boolean isCancel) {
if(context == null){
return;
}
if (context instanceof Activity) {
if (((Activity) context).isFinishing()) {
return;
}
}
if (loadDialog != null && loadDialog.isShowing()) {
return;
}
loadDialog = new LoadLayoutDialog(context, isCancel);
loadDialog.show();
}

/**
* 销毁加载窗
* @param context 上下文
*/
public static void dismiss(Context context) {
if(context == null){
return;
}
try {
if (context instanceof Activity) {
if (((Activity) context).isFinishing()) {
loadDialog = null;
return;
}
}
if (loadDialog != null && loadDialog.isShowing()) {
Context loadContext = loadDialog.getContext();
if (loadContext instanceof Activity) {
if (((Activity) loadContext).isFinishing()) {
loadDialog = null;
return;
}
}
loadDialog.dismiss();
loadDialog = null;
}
} catch (Exception e) {
e.printStackTrace();
loadDialog = null;
}
}

 

  • G.其他延申

    • 1.上一个页面没有destroy的时候,之前的Activity已经接收到了广播。如果此时之前的Activity进行UI层面的操作处理,就会造成crash。UI层面的刷新,一定要注意时机,建议使用set_result来代替广播的形式进行刷新操作,避免使用广播的方式,代码不直观且容易出错。

    • 2.Dialog在Actitivty退出后弹出。在Dialog调用show方法进行显示时,必须要有一个Activity作为窗口的载体,如果Activity被销毁,那么导致Dialog的窗口载体找不到。建议在Dialog调用show方法之前先判断Activity是否已经被销毁。

    • 3.Service&Application弹出对话框或WindowManager添加view时,没有设置window type为TYPE_SYSTEM_ALERT。需要在调用dialog.show()方法前添加dialog.getWindow().SetType(WindowManager.LayoutParams.TYPE_SYSTEM_ALERT)。

    • 4.6.0的系统上, (非定制 rom 行为)若没有给予悬浮窗权限, 会弹出该问题, 可以通过Settings.canDrawOverlays来判断是否有该权限.

    • 5.某些不稳定的MIUI系统bug引起的权限问题,系统把Toast也当成了系统级弹窗,android6.0的系统Dialog弹窗需要用户手动授权,若果app没有加入SYSTEM_ALERT_WINDOW权限就会报这个错。需要加入给app加系统Dialog弹窗权限,并动态申请权限,不满足第一条会出现没权限闪退,不满足第二条会出现没有Toast的情况。

    • Dialog&AlertDialog,Toast,WindowManager不能正确使用时,经常会报出该异常,原因比较多,几个常见的场景如下:

  • H.其他建议

    • 1.不要在非UI线程中使用对话框创建,显示和取消对话框;

    • 2.尽量少用单独线程,出发是真正的耗时操作采用线程,线程也不要直接用Java式的匿名线程,除非是那种单纯的操作,操作完成不需要做其他事情的。

    • 3.如果是在fragment中发起异步网络的回调中进行dialog的操作,那么在操作之前,需要判断 isAdd( ),避免fragment被回收了但是还要求dialog去dismiss

    • 4.在Activity onDestroy中对Dialog提前进行关闭

 

2.8 java.lang.NoClassDefFoundError 找不到类异常

  • A.详细崩溃日志信息

  • B.查看崩溃类信息

    • 如果Java虚拟机或ClassLoader实例试图加载类的定义(作为普通方法调用的一部分或使用新的表达式创建新实例的一部分),则抛出该类的定义。编译当前执行的类时存在搜索类定义,但无法再找到该定义。

 

public class NoClassDefFoundError extends LinkageError {
private static final long serialVersionUID = 9095859863287012458L;
public NoClassDefFoundError() {
super();
}
public NoClassDefFoundError(String s) {
super(s);
}
private NoClassDefFoundError(String detailMessage, Throwable throwable) {
super(detailMessage, throwable);
}
}

 

  • C.项目中异常分析

    • 问题的主要原因:方法数超65536限制。由于实际开发当中的需求不断变更,开源框架越来越多,大多都用第三方SDK,导致方法数很容易超出65536限制。出现错误Java.lang.NoClassDefFoundError

  • D.引发崩溃日志的流程分析

    • 这个错误是Android应用的方法总数限制造成的。android平台的Java虚拟机Dalvik在执行DEX格式的Java应用程序时,使用原生类型short来索引DEX文件中的方法。这意味着单个DEX文件可被引用的方法总数被限制为65536。通常APK包含一个classes.dex文件,因此Android应用的方法总数不能超过这个数量,这包括Android框架、类库和你自己开发的代码。而Android 5.0和更高版本使用名为ART的运行时,它原生支持从APK文件加载多个DEX文件。在应用安装时,它会执行预编译,扫描classes(..N).dex文件然后将其编译成单个.oat文件用于执行. 通熟的讲,就是分包。

  • F.解决办法

    • 64k解决办法

  • G.其他延申

    • 1.分dex包编程,如果依赖的dex包删除了指定的类,执行初始化方法时将会报错;

    • 2.使用第三方SDK或插件化编程时,动态加载或实例化类失败将会报错;

    • 3.系统资源紧张时,当大量class需要加载到内存的时候,处于竞争关系,部分calss竞争失败,导致加载不成功;

    • 4.装载并初始化一个类时失败(比如静态块抛 java.lang.ExceptionInInitializerError 异常),然后再次引用此类也会提示NoClassDefFoundErr 错误;

    • 5.手机系统版本或硬件设备不匹配(如ble设备只支持18以上SDK),程序引用的class在低版本中不存在,导致NoClassDefFoundErr 错误。

    • 6.so文件找不到,设备平台armeabi-v7a,但是我的so库是放在armeabi中的,解决方法新建一个armeabi-v7a包,并且把armeabi的文件拷贝过来.

    • 该异常表示找不到类定义,当JVM或者ClassLoader实例尝试装载该类的定义(这通常是一个方法调用或者new表达式创建一个实例过程的一部分)而这个类定义并没有找时所抛出的错误。

    • [解决方案]:NoClassDefFoundError异常一般出现在编译环境和运行环境不一致的情况下,就是说有可能在编译过后更改了Classpath或者jar包所以导致在运行的过程中JVM或者ClassLoader无法找到这个类的定义。

 

2.9 Android出现:Your project path contains non-ASCII characters.

  • A.详细崩溃日志信息

  • B.查看崩溃类信息

  • C.项目中异常分析

  • D.引发崩溃日志的流程分析

  • F.解决办法

    • 很好解决啦,就是你的工程项目路径或者项目名称包含了中文,修改相关的名称就好

  • G.其他延申

 

3.1 OnErrorNotImplementedException【 Can't create handler inside thread that has not called Looper.prepare()】

  • A.详细崩溃日志信息

 

Can't create handler inside thread that has not called Looper.prepare()

 

  • B.查看崩溃类信息

  • C.项目中异常分析

  • D.引发崩溃日志的流程分析

    • 这是因为Handler对象与其调用者在同一线程中,如果在Handler中设置了延时操作,则调用线程也会堵塞。每个Handler对象都会绑定一个Looper对象,每个Looper对象对应一个消息队列(MessageQueue)。如果在创建Handler时不指定与其绑定的Looper对象,系统默认会将当前线程的Looper绑定到该Handler上。

    • 在主线程中,可以直接使用new Handler()创建Handler对象,其将自动与主线程的Looper对象绑定;在非主线程中直接这样创建Handler则会报错,因为Android系统默认情况下非主线程中没有开启Looper,而Handler对象必须绑定Looper对象。

    • 如果在主线程中创建handler时,系统会自动创建Looper,但是在子线程中创建handler时,是不会自动创建Looper的,此时如果不手动创建Looper,系统就会崩溃

  • F.解决办法

    • 不要在子线程中做UI操作,比如更改界面,吐司等等……

    • 方法1:需先在该线程中手动开启Looper(Looper.prepare()-->Looper.loop()),然后将其绑定到Handler对象上;

 

 

final Runnable runnable = new Runnable() {
  @Override
  public void run() {
    //执行耗时操作
    try {

      Log.e("bm", "runnable线程:" + Thread.currentThread().getId()+ " name:" + Thread.currentThread().getName());

      Thread.sleep(2000);
      Log.e("bm", "执行完耗时操作了~");
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
  }
};
new Thread() {
  public void run() {
    Looper.prepare();
    new Handler().post(runnable);//在子线程中直接去new 一个handler
    Looper.loop();    //这种情况下,Runnable对象是运行在子线程中的,可以进行联网操作,但是不能更新UI
  }
}.start();

 

  • 方法2:通过Looper.getMainLooper(),获得主线程的Looper,将其绑定到此Handler对象上。

 

final Runnable runnable = new Runnable() {
  @Override
  public void run() {
    //执行耗时操作
    try {
      Log.e("bm", "runnable线程: " + Thread.currentThread().getId()+ " name:" + Thread.currentThread().getName());
      Thread.sleep(2000);
      Log.e("bm", "执行完耗时操作了~");
    } catch (InterruptedException e) {
    e.printStackTrace();
    }
  }
};
new Thread() {
  public void run() {
   //在子线程中直接去new 一个handler
    new Handler(Looper.getMainLooper()).post(runnable);
    //这种情况下,Runnable对象是运行在主线程中的,不可以进行联网操作,但是可以更新UI
  }
}.start();

 

3.2 platform-tools\adb.exe,start-server' failed -- run manually if necessary

  • A.详细崩溃日志信息

  • B.查看崩溃类信息

  • C.项目中异常分析

    • adb启动失败,端口被占用

  • D.引发崩溃日志的流程分析

  • F.解决办法

 

百度google大家多说的是任务管理器 kill掉adb 或者重启adb server,但我任务管理器就没有adb ,猜测是某个程序占用了adb端口。于是按此思路查找。
5037为adb默认端口 查看该端口情况如下:
netstat -aon|findstr "5037"
TCP 127.0.0.1:5037 0.0.0.0:0 LISTENING 6540
发现6540占用了 5037端口,继续查看6540的task,发现是wandoujia .如下所示
tasklist|findstr "6540"
wandoujia_daemon.exe 6540 Console 1 4,276 K

接下来问题就好解决了,在任务管理器kill掉wandoujia_daemon.exe ,运行android程序,ok .

1.关闭xx荚进程
2.adb kill-server
3.adb start-server

 

未完待续....希望对大家有帮助....

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值