ReleasableVar,可以为空的 Kotlin 非空类型 var
0. 题外话:Hadi 的插件
上周的 JetBrains 开发者大会,Hadi 的两个插件比较亮眼,这里有小伙伴如果没有听到最后一场,可能不知道它们是啥,它们分别是:
1. 描述下需求
前不久跟群里小伙伴讨论的时候,发现他们有一个需求,那就是在一个变量使用完之后要将其置为
null
,但是呢,又不愿意将它声明为可空类型,这个需求实在是。。大概就像这样吧:
1 |
class MainActivity: Activity { |
你想着 Activity 的
onStop
调用了之后到被回收还得等一会儿呢,甚至
onDestroy
都会过一会儿才会被执行到,所以
image
可能会在内存被持有一段时间。所以幸好我们可以通过
recycle
方法先告诉
Bitmap
该释放内存了,不然的话我们只能等着
Activity
回收的时候
image
引用的对象才可以回收。
不可空类型能够置为
null
看上去是个合理的需求,只要我确定在这之后不再使用就好了。好吧,既然合理,我们就想想办法。
2. 解决办法
这么看来不用官方了,我们自己似乎也可以搞定,写个属性代理即可:
1 |
fun <T : Any> releasableNotNull() = ReleasableNotNull<T>() |
1 |
class Foo { |
额,可是怎么才能调用到属性代理对象的方法呢?调用不到的话岂不是白折腾。。
1 |
fun <R> KProperty0<R>.release() { |
我们用反射其实可以很轻松的拿到代理对象的,那么这个故事就快要讲完了——不仅如此,我们还可以仿造
lateinit
定义一个判断是否初始化的方法:
1 |
val <R> KProperty0<R>.isInitialized: Boolean |
3. 干掉反射
然后就有人说,我靠你居然用反射!你作弊!。。。。其实如果用反射,最好的办法是用 Java 反射直接设置为
null
,但这个神不知鬼不觉的,你敢用么。算了算了,咱不用反射了好吧。
1 |
internal lateinit var releasableRefs: WeakIdentityMap<Any, MutableMap<String, ReleasableNotNull<*>>> |
1 |
class ReleasableNotNull<T : Any> : ReadWriteProperty<Any, T> { |
Map 里面又是一个 Map,这意思是说一个对象里面可能有多个成员被代理。接着改写我们的扩展方法:
1 |
val <R> KProperty0<R>.isInitialized: Boolean |
4. 怎么用?
啊,我忘了一件最重要的事儿,也许有小伙伴还不知道
KProperty0
是啥,它其实就是一个顶级变量或者已经绑定完
receiver
的变量,例如:
1 |
var varInPackage = "Hello" |
这两个属性我们通过下面的属性引用得到的就是
KProperty0
的实例:
1 |
::varInPackage |
换句话说,我们开头给出的那个
image
的例子就可以这样写了:
1 |
class MainActivity: Activity { |
5. 你想直接用?
1 |
compile "com.bennyhuo.kotlin:releasable-nonnull-vars:1.1.0" |