Kotlin回调方法可以支持指定线程执行

1,182 阅读2分钟

背景

记录一个输入法应用线上P0事故产生的迭代线.

  1. 迭代1 在键盘上有个运营位弹窗,在键盘收起的时候关闭弹窗. 代码如下:
fun Activity.showExampleDialog(view: View) {
    AppCompatDialog(this).apply {
        setContentView(
            Button(this@showExampleDialog).apply {
                setOnClickListener {
                    dismiss()
                }
            }
        )
    }.show();
}
  1. 迭代2 在收起键盘的时候有可能执行一些耗时操作,如果有耗时操作dismiss会被放入到子线程执行
    Executors.newSingleThreadExecutor().execute(Runnable {
    // 可能的耗时操作
        dismiss()
    });
  1. 迭代3 线上发现一些可疑崩溃,鉴于键盘已经收起来了,RD评估影响不大. 直接把整个回调代码块try了起来.
    Executors.newSingleThreadExecutor().execute(Runnable {
        try {
        // 可能的耗时操作
            dismiss()
        } catch (e: Exception) {
        }
    });
  1. 迭代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);
}
  1. 事故 这个需求的弹窗平时很少用到,上诉修改完后几个月没有用,突然有天推送了一个运营弹窗,推送完后发现线上大量用户反馈:
键盘上有一个弹窗无法关闭,因为挡住了键盘,键盘也无法输入了.

(PS:绝大部分用户不知道怎么杀死输入法,应用没有做兜底,也失去了自救的机会)

原因

  1. Dialog的dismiss方法系统已经帮开发者做了线程判断,如果在子线程使用,系统会自动切回到主线程执行,但是PopupWindow确不行.
  2. 几个迭代下来,代码解构已经发生改变,执行dismiss函数的代码已经被放到其他类里面, 执行线程也被切换到了子线程.

改进

抛开其他,仅对程序员来说:

  1. 粗暴的try...catch,切子线程能解决的只是当时的问题,一些问题不明就里的处理方式带来的后果比崩溃严重.
  2. 后浪在改代码的时候,一定要找个前浪问清楚需求的背景和帮忙review下
  3. 做可以支持指定线程执行的回调方法.
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代码的简洁.