Android's TypedArray
s need to be .recycle()
d. Also, TypedArray
implements AutoClosable
, which means that we can use Kotlin's .use { ... }
construct to automate closing/recycling. That is implemented as
@Suppress("ACTUAL_WITHOUT_EXPECT")
@SinceKotlin("1.2")
@kotlin.internal.InlineOnly
// TODO: remove java.lang package prefix when the kotlin.AutoCloseable typealias is introduced and KT-55392 is fixed.
// The prefix is currently needed for the current dokka to generate correct signature.
public actual inline fun <T : java.lang.AutoCloseable?, R> T.use(block: (T) -> R): R {
contract {
callsInPlace(block, InvocationKind.EXACTLY_ONCE)
}
var exception: Throwable? = null
try {
return block(this)
} catch (e: Throwable) {
exception = e
throw e
} finally {
this.closeFinally(exception)
}
}
@SinceKotlin("1.2")
@PublishedApi
internal fun java.lang.AutoCloseable?.closeFinally(cause: Throwable?) = when {
this == null -> {}
cause == null -> close()
else ->
try {
close()
} catch (closeException: Throwable) {
cause.addSuppressed(closeException)
}
}
and TypedArray
's override of the .close
method is simply
public void close() {
recycle();
}
but there is also a custom extension function, equally named .use
, just for TypedArray
public inline fun <R> TypedArray.use(block: (TypedArray) -> R): R {
return block(this).also {
recycle()
}
}
I wonder why that extension function exists. It is arguably much simpler, but I kinda doubt it'll make much of a difference. Are there any reasons other than performance to create this extension function? Or is the performance gain actually significant?
I also find it a somewhat poor choice to name the two functions identically, because it's now really easy to occasionally import the wrong one!
This custom version of use
is a legacy from old versions of the Android API.
The TypedArray
class implements AutoCloseable
, but it existed before the Kotlin stdlib had a use
extension function for AutoCloseable
. That came with Kotlin 1.2, and only when using the jdk7 version of the JVM target (at the time, Kotlin also supported Java 1.6). At the time, the use
extension was only defined for the Closeable
interface, which TypedArray
does not implement.
Note that this custom definition of use
has different behaviour than Kotlin's AutoCloseable.use
, as it doesn't recycle if the code throws an exception. Judging from this conversation, it appears that it wasn't considered important for it to recycle if an exception was thrown.
You don't have to use this custom definition. If you don't import it, your code will use the AutoCloseable
version from the Kotlin standard library, which will work just as well.