你可能需要了解下的Android开发技巧(一)

1,683 阅读2分钟

携手创作,共同成长!这是我参与「掘金日新计划 · 8 月更文挑战」的第19天,点击查看活动详情

本篇文章将是介绍Android常见开发技巧系列的开篇,分享日常开发的一些技巧。

callbackFlow {}+debounce()降频

假如当前要做一个实时搜索的功能,监听输入框动态输入的内容向服务器发起搜索请求,这不仅会增大服务器的压力,而且也会产生很多的无用请求。

比如其实你想搜索一个“android”,但随着你在输入框中动态编辑,最多可能会向服务器发送7次请求,很明显前面6次请求都是属于无用请求(暂时不考虑模糊匹配的场景)。

这个时候我们就可以借助于callbackFlow{}将输入框的动态输入转换成流,再借助debounce()对流进行降频即可。关于对debounce()的讲解,可以参考之前的文章:debounce()限流

fun test4(editText: EditText) {
    lifecycleScope.launchWhenResumed {
        callbackFlow {
            val watcher = editText.doAfterTextChanged {
                trySend(it?.toString() ?: "")
            }
            
            invokeOnClose {
                editText.removeTextChangedListener(watcher)
            }
        }.debounce(200).collect {
            //对于输入框中的内容向服务器发起实时搜索请求
            
        }
    }
}

判断当前是否为主进程

常见的业务场景中,可能我们会把Service单独放一个进程处理,比如为了单独存放WebView再或者专门开一个服务进程与服务器进行通信,这样当UI进程死掉,也能缓存最新的数据到内容和本地 。

但有时,Service单独放一个进程处理,也会走Application的初始化逻辑,比如初始化第三方SDK、获取某些资源等等,但这些可能是只有UI进程才需要,所以Service进程初始化应该跳过这些逻辑。

所以我们需要判断当前的线程是否属于UI线程,可以利用UI进程的包名和进程名相同的特性实现,代码如下:

fun isMainProcess(): Boolean =
    getSystemService<ActivityManager>()?.let {
        it.runningAppProcesses.find { info ->
            info.pid == Process.myPid()
        }?.let { res ->
            res.processName == packageName
        }
    } ?: true

当我写完上面的代码之后,发现Application竟然直接提供了一个获取当前进程名称的方法:

image.png

不过这个只有SDK28以上才能使用,可以判断一下,SDK28以下用上面的代码判断,SDK28及以上用下面的代码判断:

fun isMainProcess2(): Boolean = packageName == getProcessName()