背景
记录一个输入法应用线上P0事故产生的迭代线.
- 迭代1
在键盘上有个运营位弹窗,在键盘收起的时候关闭弹窗. 代码如下:
fun Activity.showExampleDialog(view: View) {
AppCompatDialog(this).apply {
setContentView(
Button(this@showExampleDialog).apply {
setOnClickListener {
dismiss()
}
}
)
}.show();
}
复制代码
- 迭代2 在收起键盘的时候有可能执行一些耗时操作,如果有耗时操作dismiss会被放入到子线程执行
Executors.newSingleThreadExecutor().execute(Runnable {
// 可能的耗时操作
dismiss()
});
复制代码
- 迭代3 线上发现一些可疑崩溃,鉴于键盘已经收起来了,RD评估影响不大. 直接把整个回调代码块try了起来.
Executors.newSingleThreadExecutor().execute(Runnable {
try {
// 可能的耗时操作
dismiss()
} catch (e: Exception) {
}
});
复制代码
- 迭代4 因需求需要,把Dialog换成了PopupWindow`.
fun Activity.showExamplePopWindow(view: View) {
PopupWindow(this).apply {
setContentView(
Button(this@showExamplePopWindow).apply {
setOnClickListener {
Executors.newSingleThreadExecutor().execute(Runnable {
try {
dismiss()
} catch (e: Exception) {
}
});
}
}
)
}.showAsDropDown(view);
}
复制代码
- 事故
这个需求的弹窗平时很少用到,上诉修改完后几个月没有用,突然有天推送了一个运营弹窗,推送完后发现线上大量用户反馈:
键盘上有一个弹窗无法关闭,因为挡住了键盘,键盘也无法输入了.
复制代码
(PS:绝大部分用户不知道怎么杀死输入法,应用没有做兜底,也失去了自救的机会)
原因
- Dialog的dismiss方法系统已经帮开发者做了线程判断,如果在子线程使用,系统会自动切回到主线程执行,但是PopupWindow确不行.
- 几个迭代下来,代码解构已经发生改变,执行dismiss函数的代码已经被放到其他类里面, 执行线程也被切换到了子线程.
改进
抛开其他,仅对程序员来说:
- 粗暴的try…catch,切子线程能解决的只是当时的问题,一些问题不明就里的处理方式带来的后果比崩溃严重.
- 后浪在改代码的时候,一定要找个前浪问清楚需求的背景和帮忙review下
- 做可以支持指定线程执行的回调方法.
fun android.view.View.onClick(
context: CoroutineContext = Dispatchers.Main,
handler: suspend CoroutineScope.(v: android.view.View?) -> Unit
) {
setOnClickListener { v ->
CoroutineScope(context).launch {
v?.let { handler(it) }
}
}
}
复制代码
总结
通过这个扩展顺便熟悉下Kotlin的语法
对比着Java实现,体会下Koltin代码的简洁.
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END