Android开发过程遇到的一些坑(持续更新)
主要是开发过程中遇到的手机适配和系统适配的问题,以及一些开发建议的注意点
厂商手机适配的问题
- 某些华为注册的receiver不能超过限制的问题,会报出
register too many Broadcast Receivers
错误。原则上app并会被去限制注册receiver的数量(500),只是华为有去做一个限制,当然一般的app是不会注册这么多(包括动态注册),但是我们引入的一些第三方库可能内部就会有注册这么多,比如Glide
,这时候可以参考HuaWeiVerifier ,绕过华为register too many Broadcast Receivers限制 - vivo/oppo某些机型的TextView有一层自动的灰色蒙层,类似点击的效果,解决方案:关于Android原生View默认焦点高亮的问题
- 锤子手机的权限问题,开启权限,然后去设置关闭返回的时候再去check权限,返回的结果为【已开启】
- vivo y66 悬浮窗的权限是否开启判断,无法使用系统api,解决方式FloatWindowPermission
- OPPO R11s(27),PBBT00(28)这两块机型的后台悬浮窗需要每次都重新
create
,不能通过hide/show
的方式,怀疑其他的oppo也类似,暂时没去尝试。建议悬浮窗的开发使用EasyFloat框架 - 三星手机杀死App之后会有偶现的进程缓存(多使用会出现),导致使用普通的方式杀死App之后,点击桌面图标重新打开不走Application的
onCreate
- 小米通知栏不设置group的时候,假如有多条会被折叠,目前在MI 8上出现,所以我们的通知栏最好设置group.
系统的适配问题
- MainActivity页面的时候点击home键,然后点击图标经过Splash闪屏页面的才能回到首页的问题,解决方案:FLAG_ACTIVITY_BROUGHT_TO_FRONT :app会重启启动页
- TextView必须设置颜色,否则背景为白色的时候,有些系统默认字体也是白色就会导致看不到。
- 不用直接调用
getResource().getColor(@ColorRes int id, @Nullable Theme theme)
,5.0的时候没有这个方法,有些手机会直接崩溃,要么区分版本去调用,要么使用ContextCompat
的getColor()
,getDrawable
同理 - 语音播报的问题,建议统一使用.mp3,有些手机无法播报.m4a,关于这块我也不太清楚,只是遇到过m4a格式的语音不是所有手机都是适配的。
- 小米11自定义Toast偶现的崩溃问题,后续后发现是使用了单例导致,自定义Toast不能使用单例。而且Android11之后,后台无法展示自定义的toast,只能使用系统的才会展示,这里推荐使用ToastUtils框架,他回去兼容那些不同厂商的问题。
- 闹钟注册超出限制的问题,
java.lang.IllegalStateException: Maximum limit of concurrent alarms 500 reached for xxxx
,我们应该使用别的方式替代闹钟,比如WorkerManager - DialogFragment遇到的一些坑
ANR问题优化
- 系统跨进程导致的anr,比如频繁的判断某个权限是否已经获取,这里的频繁是指1s内可能check多次。优化的方向是使用权限缓存,因为用户不可能这么频繁的去更改app的权限,我们只需要做一套机制,在内存保存一份权限的获取情况的内容即可。
- mmkv的频繁读写,建议还是使用内存缓存去做优化,比如用户信息,我们不需要每次都从mmkv里面获取,只需要获取一次,然后放在内存即可。
- 悬浮窗的权限是否开启判断,频繁的话建议使用子线程的方式
代码习惯建议
- Dialog在show之前都必须先判断下
Activit
是否是alive
的,而且需要使用成员变量而不是局部变量,在组件生命周期结束的时候判断是否需要销毁,建议使用下面方法判断是否组件存活。
1 | public static boolean isActivityAlive(final Activity activity){ |
- DialogFragment类以及子类使用空构造函数,回调使用接口形式
- 使用Jetpact框架
- 倒计时的话,如果使用
CountDownTimer
,如果需要展示具体的次数或者是秒数之类的,不用使用他的回调去设置,而是自己自定义一个变量存储,onTick
一次设置一次,这样较为准确。 - 复杂页面不建议使用
MediatorLiveData
组合多个LiveData
,单页面少请求的可以使用。 - app单纯的时间间隔计算可以考虑使用
SystemClock.elapsedRealtime()
,他不必担心用户修改本地的日期。 - Fragment的填充,需要按照流程,先
findFragmentByTag
,如果返回的不为空而且isAdded()
返回了true
就直接show,否则就通过调用add(int containerViewId,Fragment fragment,String tag)
添加,然后hide的时候,同样的如果内存中的Fragment为空,就通过findFragmentByTag
查找,返回不为空就可以调用hide()