Kotlin 干掉接口需要强制实现的方法
假如我有这样一个需求:我需要记录应用中所有存活的 Activity
,那么我的代码就会像以下代码那么写。
class App : Application() {
private val activeActivities: ArrayList<Activity> = ArrayList()
private val activityLifecycleCallback: ActivityLifecycleCallbacks = object : ActivityLifecycleCallbacks {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
activeActivities.add(activity)
}
override fun onActivityStarted(activity: Activity) {
}
override fun onActivityResumed(activity: Activity) {
}
override fun onActivityPaused(activity: Activity) {
}
override fun onActivityStopped(activity: Activity) {
}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {
}
override fun onActivityDestroyed(activity: Activity) {
activeActivities.remove(activity)
}
}
override fun onCreate() {
super.onCreate()
registerActivityLifecycleCallbacks(activityLifecycleCallback)
}
}
我相信很多的人都和我一样写过上面的代码,代码的实现没有什么问题,也没有什么性能问题,就是源码读起来非常的蛋疼,我们其实只需要 ActivityLifecycleCallbacks
中的两个回调方法,其他的方法我们其实不需要,由于这是接口的定义,所以我们必须实现,但是方法中又是空的,什么都没有干,所以上面的代码的可阅读性就非常差,如果我们能够把 ActivityLifecycleCallbacks
所有的空实现方法就干掉就清爽了。
那么我们真的可以干掉这些 Callback
恶心的空实现方法吗?在我看到 LeakCanary
的源码之前,我也认为没有好的方法把它干掉。我就通过 LeakCanary
的实现方式来改造上面的代码:
class App : Application() {
private val activeActivities: ArrayList<Activity> = ArrayList()
private val activityLifecycleCallback: ActivityLifecycleCallbacks = object : ActivityLifecycleCallbacks by noOpDelegate() {
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {
activeActivities.add(activity)
}
override fun onActivityDestroyed(activity: Activity) {
activeActivities.remove(activity)
}
}
override fun onCreate() {
super.onCreate()
registerActivityLifecycleCallbacks(activityLifecycleCallback)
}
}
哈哈,上面的代码是不是瞬间清爽了,上面的代码是通过 Java
中的动态代理和 Kotlin
中的代理/委托实现的。不熟悉 Java
动态代理的同学去网上找找相关的资料,如果不清楚 Kotlin
代理/委托实现的原理可以看看我之前的文章: 基于字节码指令分析 Kotlin 代理。
那么我们就看看这个充满魔法的 noOpDelegate()
方法的实现:
internal inline fun <reified T : Any> noOpDelegate(): T {
val javaClass = T::class.java
return Proxy.newProxyInstance(
javaClass.classLoader, arrayOf(javaClass), NO_OP_HANDLER
) as T
}
private val NO_OP_HANDLER = InvocationHandler { _, _, _ ->
// no op
}
是不是又震惊了,哈哈,代码怎么这么少。牛逼的操作往往都是这么朴实无华。就是通过 Java
动态代理在运行时生成了一个实现了对应接口的对象,对象方法实现的 InvocationHandler
是一个空实现,啥也没有干。
所以调用 noOpDelegate()
方法就得到了一个实现了对应接口的对象,不过这个对象调用所有方法都没有反应。
然后我们再把上面生成的空实现对象再去代理我们的对象,这样就得到了上面的效果,Kotlin
中的被代理的对象可以选择重写需要的方法,这就达到了我们上面的效果,只需要重写我们需要的回调方法。
Kotlin
的对象代理/委托在开发中也用得非常多,也非常好用,Kotlin
官方也提供了很多这样的方法,比如我想要 Activity
实现 CoroutineScope
接口代码就可以像下面这样写:
class MyActivity : Activity(), CoroutineScope by CoroutineScope(Dispatchers.Main) {
override fun onDestroy() {
super.onDestroy()
cancel()
}
}
希望今天的这个小技巧能够帮你干掉接口中需要强制实现的空方法。