关于处理客户反馈的问题的步骤
注意:要与客户的场景一致(正式线or测试线、账号密码、门店、操作步骤)
- 与IOS比对
- IOS有一样的问题,初步判定是接口问题,抓接口反馈给后台
- IOS正常,安卓重现客户场景
- 安卓正常:初步判定是版本不同的问题,找旧包抓接口
- 异常复现:如果有错误日志则通过日志定位问题;如果没有错误日志抓接口给后台
- IOS正常,安卓重现客户场景
- IOS有一样的问题,初步判定是接口问题,抓接口反馈给后台
功能相关问题
Camera相机相关
关于Camera横竖屏问题
1、如果Camera处理的是横屏的倒是没有什么问题的
2、如果处理的是竖屏的话,那么原点是在右下角的或者左下角的,而不是跟横屏时候一样在左上角或者右上角
3、还有一个就是控件的坐标位置是根据左上角或者右上角来计算的,这点在处理Camera竖屏的时候一定要注意,不能根据控件的坐标来定义
图片显示
现象:燕谷坊遇到保存drawable然后取出来的时候是黑色的图片的情况
解决:保存bitmap图片,不要保存drawable图片
编译相关问题
安卓编译报错解决方法
1 | ./gradlew clean assembleDebug --stacktrace |
获取更多报错信息
编译无法成功的问题
- 这个很诡异的错误,90%都是由于自定义控件在xml的路径写错了引起的
未归类问题
[android:android.content.res.Resources$NotFoundException: String resource ID #..](https://www.cnblogs.com/mybkn/archive/2012/07/09/2582958.html)
做Android应用开发的朋友有时候会遇到这样的Bug,
android.content.res.Resources$NotFoundException: String resource ID #0x0
找不到资源文件ID
#0x0
原因分析如下:
遇到这种情况,很有可能是把一个int
型业务数据的 设置setText()
或者类似的方法中, 这样Android
系统就会主动去资源文件当中寻找, 但是它不是一个资源文件ID
, 所以就会报出这个bug
。
解决:将int
型业务数据,转换成String
类型即可。
android.content.res.Resources$NotFoundException
Android资源不是可绘制的(颜色或路径)
1 | Resource is not a Drawable (color or path): TypedValue{t=0x2/d=0x7f040151 a=2} |
异常分析:由于将图片资源拷贝到了drawable-land-xhdpi
目录下,本来应该拷贝到drawable-xhdpi
目录下
解决方法:
- 1.引用的资源ID 是否能匹配到
R.java
文件中定义的资源; - 2.是否因为缓存等原因导致编译
APK
时未把资源文件打包进去,可以把APK
反编译检查下; - 3.是否使用了一个错误的类型来引用了某个资源或者配置资源时存在错误;
- 4.是否将
Int
等整型变量作为了参数传给了View.setText
调用,这种情况下该整型变量将被认为是一个资源ID
号去资源列表中查找对应的资源,导致找不到对应资源错误;解决方法是做类型转换View.setText(String.valueOf(Int id))
。
CompilationFailedException问题
Caused by: org.gradle.api.internal.tasks.compile.CompilationFailedException: Compilation failed; see
删除build/intermediates
然后重新编译
当时遇到这个错误只知道是编译错误,不知道为什么,也定不了问题所在,网上说的一堆也试了,都没用
日志的错误说的也不清晰,有很多时候我都是Rebuild或清理工程就解决了,这次是因为集成极光分享,集成到一半又删了,没删干净,所以出现了这个问题,处理方法是把下图的文件夹删掉,重新编译,立马定位到代码块找不到极光的包,删除该代码就好了,因为上次集成极光编译是没问题的,删了极光后还有缓存,Android studio都没检测出来。
:app:transformResourcesWithMergeJavaResForDebug
1 | Error:Execution failed for task ':app:transformResourcesWithMergeJavaResForDebug'. > |
解决方案:将bulid目录删掉 重新编译即可!!!!!少走弯路
debug无法显示值的问题
Android stdio IDE环境下debug代码不显示变量值,add to watch无效
解决方案:
修改app.gradle 文件下的testCoverageEnabled为false
1 | buildTypes { |
NormalDemocompile Classpath
问题
Unable to resolve dependency for ':face@NormalDemo/compileClasspath': Could not resolve project :aliveDetect.
1 | <a href="openFile:E:/ProjectLandi/LandiTool/ScanFaceTool/face/build.gradle">Open File</a> |
Unable to resolve dependency for ':face@NormalDemoUnitTest/compileClasspath': Could not resolve project :aliveDetect.
1 | <a href="openFile:E:/ProjectLandi/LandiTool/ScanFaceTool/face/build.gradle">Open File</a> |
答案:
出现以上情况就是因为Could not resolve project :aliveDetect.
这个工程下的gradle
有问题,配置跟宿主工程有点不一样才会造成这样的aliveDetect
的gradle
下面是这样的:
1 | buildTypes { |
app的gradle下面是这样的:
1 | buildTypes { |
注意到是因为app
的build.gradle
中多了一个demo
,,,,,,就是这个demo
引起的要么删除 要么就给我在aliveDetect
这个地方添加,这样就不会有错误了,也可以编译过去
不会造成 编译之后出现Try Again Open Messages View Show Log in Explorer.
transformClassesWithInstantRunForNormalDebug
问题
java.lang.RuntimeException: com.android.build.api.transform.TransformException: java.lang.RuntimeException:Failed to find byte code for java/awt/RenderingHints$Key com.android.build.api.transform.TransformException: java.io.IOException: Failed to find byte code for java/awt/RenderingHints$Key
切记这个要一致:
1 | compileOptions { |
java.lang.OutOfMemoryError
问题:运行项目出现java.lang.OutOfMemoryError: GC overhead limit exceeded...
解决:在项目build.gradle中添加
1 | android { |
解决方案
1 | 该异常表示未能成功分配字节内存,通常是因为内存不足导致的内存溢出。 |
Picasso导致的OutOfMemoryError 解决方案:
在application中添加android:largeHead="true"
1 | <application |
unable to unzip
问题:Gradle build failed - unable to unzip
You have just to do in a Terminal (for have terminal : Select View > Tool Windows > Terminal) :
On Windows:
1 | gradlew cleanBuildCache |
On Mac or Linux:
1 | ./gradlew cleanBuildCache |
And build Gradle
:app:javaPreCompileDebug
在app的build中
1 | android { |
java.lang.IllegalStateException非法状态异常
1 | IllegalStateException: Can not perform this action after onSaveInstanceState: |
onSaveInstanceState方法是在该Activity即将被销毁前调用,来保存Activity数据的,如果在保存完状态后再给它添加Fragment就会报错。
解决:
把commit()
换成commitAllowingStateLoss()
其他延申
- 错误类型大致为以下几种:
1 | 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()方法。
- 第二种:该异常是由于服务器错误返回的JSON字符串和服务器正常下时返回的JSON字符串结构不同,导致利用Gson解析的时候报了一个异常:本该去解析集合却强制去解析对象所致.解决办法:在使用Gson解析JSON时try cash一下,不报错按照正常逻辑继续解析,报异常则处理为请求失败逻辑即可.
IllegalStateException:Can’t compress a recycled bitmap
无法压缩回收位图
1 | Can't compress a recycled bitmap |
如果位图已被回收,则希望抛出异常的方法将调用此值。知道了崩溃的具体位置,就该分析具体的原因呢!
1 | public boolean compress(CompressFormat format, int quality, OutputStream stream) { |
异常分析:
使用了已经被释放过内存的对象。对于Bitmap
:Bitmap bitmap=一个bitmap对象
。使用过程中调用bitmap.recycle()
,之后再使用bitmap就会报错。
bitmap.recycle()
解释:释放与此位图关联的本机对象,并清除对象数据的引用。这将不会同步释放对象数据。它只允许在没有其他引用的情况下对其进行垃圾手机。位图被标记为“死”,这意味着如果调用getPixels()
或setPixels()
它将抛出异常,而不会绘制任何内容。此操作不能反转,因此只有在确定没有进一步使用位图的情况下才应该调用该操作。这个一个高级调用,通常不需要调用,因为当没有对此位图的引用时,普通GC进程将释放此内存。
1 | Free the native object associated with this bitmap, and clear the reference to the pixel data |
解决方法:
- 在使用bitmap前增加判断
if(mBitmap.isRecycled()) return null;
java.lang.IllegalArgumentException参数不匹配异常
参数不匹配异常,通常由于传递了不正确的参数导致
常见的出现场景
- Activity、Service状态异常;
- 非法URL;
- UI线程操作。
- Fragment中嵌套了子Fragment,Fragment被销毁,而内部Fragment未被销毁,所以导致再次加载时重复,在onDestroyView() 中将内部Fragment销毁即可
- 在请求网络的回调中使用了glide.into(view),view已经被销毁会导致该错误
java.lang.NullPointerException空指针异常
解决方法:(采取不信任原则)
- 方法形参要判空后才使用
- 全局变量容易被系统回收或者更改,使用全局变量前建议判空
- 第三方接口的调用,对返回值进行判空
- 请注意线程安全
android.view.WindowManager$BadTokenException异常,Toast报错Unable to add window
1 | android.view.WindowManager$BadTokenException |
异常分析:
- 这个异常发生在Toast显示的时候,原因是因为token失效。通常情况下,一般是不会出现这种异常。但是由于在某些情况下, Android进程某个UI线程的某个消息阻塞。导致 TN 的 show 方法 post 出来 0 (显示) 消息位于该消息之后,迟迟没有执行。这时候,NotificationManager 的超时检测结束,删除了 WMS 服务中的 token 记录。删除 token 发生在 Android 进程 show 方法之前。这就导致了上面的异常。
- 测试代码。模拟一下异常的发生场景,其实很容易,只需要这样做就可以出现上面这个问题
1 | Toast.makeText(this,"潇湘剑雨-yc",Toast.LENGTH_SHORT).show(); |
解决方法:
- 第一种,既然是报is your activity running,那可以不可以在吐司之前先判断一下activity是否running呢?
- 第二种,抛出异常增加try-catch,代码如下所示,最后仍然无法解决问题
- 按照源码分析,异常是发生在下一个UI线程消息中,因此在上一个ui线程消息中加入try-catch是没有意义的。而且用到吐司地方这么多,这样做也不方便啦!
- 第三种,那就是自定义类似吐司Toast的view控件。个人建议除非要求非常高,不然不要这样做。毕竟发生这种异常还是比较少见的
哪些情况会发生该问题?
- UI 线程执行了一条非常耗时的操作,比如加载图片等等,就类似上面用 sleep 模拟情况
- 进程退后台或者息屏了,系统为了减少电量或者某种原因,分配给进程的cpu时间减少,导致进程内的指令并不能被及时执行,这样一样会导致进程看起来”卡顿”的现象
- 当TN抛出消息的时候,前面有大量的 UI 线程消息等待执行,而每个 UI 线程消息虽然并不卡顿,但是总和如果超过了 NotificationManager 的超时时间,还是会出现问题
华为手机不打印Log
手机拨号盘输入 *#*#2846579#*#*
进入设置页:
- 后台设置–打开log日志
- USB端口设置–Google模式(或生产模式)
SDK not initialized or invoked in wrong process!
原因:这个是云信IM的初始化没有在Application中进行导致的,我是考虑到这个app要当成宿主的一个lib此时它的application是失效的,所以放到BaseActivity中进行初始化的。
宿主中调用了两个子app的云信IM初始化,其中一个报这个错误了。
解决:改成在宿主中实例化一遍云信IM即可,用到的key统一成一份,之后再跟后台商量着根据返回的内容加个类型来决定app是否显示这条信息【其中一个云信IM的初始化用开关进行关闭控制】