【问题标题】:Kotlin Closable and SQLiteDatabase on AndroidAndroid 上的 Kotlin 可关闭和 SQLiteDatabase
【发布时间】:2016-09-10 20:12:35
【问题描述】:

我在我的项目中使用此代码

fun getAllData(): List<Data> = writableDatabase.use { db ->
    db.query(...)
}

它在 Lollipop 设备上成功执行,但在 pre-Lollipop 上它会抛出 ClassCastException

FATAL EXCEPTION: main
java.lang.ClassCastException: android.database.sqlite.SQLiteDatabase cannot be cast to java.io.Closeable

可能是因为它是 Java 1.6 并且没有 try-with-resources 功能,但我不确定。

那么为什么会出现这个异常以及如何修复它?

【问题讨论】:

    标签: android sqlite kotlin


    【解决方案1】:

    该问题与try-with-resources无关,只是编译后的代码与运行时环境不兼容的依赖问题。

    问题是在编译时SQLiteDatabase 实现了接口Closeable,然后你将它换成另一个没有的实现。但是代码已经编译了,不知道这个变化。

    当您调用函数/方法时,会检查所有参数以确保它们是正确的类型,这通常由 JVM 处理。对于内联和扩展函数,Kotlin 编译器插入类型检查以确保它在正确的类型上运行,对于这个特定的内联函数,函数的接收者被定义为Closeable。这是方法签名:

    inline fun <T : Closeable, R> T.use(block: (T) -> R): R { ... }
    

    因此编译器对writableDatabase 进行类型检查,如下所示(在字节码中):

    CHECKCAST java/io/Closeable
    

    所以此时,SQLiteDatabase 的实现必须永远实现Closeable 接口,否则编译代码将失败。通过切换到不再适用的旧版本的 Android,您违反了合同并导致异常。编译器无法做任何不同的事情。这就像我在编译完代码后将任何 JVM 应用程序中的 JAR 换成具有完全不同实现的 JAR 一样。更改 Android 版本基本上会交换所有 JAR。

    如果所有版本都有 close 方法(已复制和修改来自 Kotlin 标准库 use 函数):

    inline fun <T : SQLiteDatabase, R> T.use(block: (T) -> R): R {
        var closed = false
        try {
            return block(this)
        } catch (e: Exception) {
            closed = true
            try {
                close()
            } catch (closeException: Exception) {
                // eat the closeException as we are already throwing the original cause
                // and we don't want to mask the real exception
           }
            throw e
        } finally {
            if (!closed) {
                close()
            }
        }
    }
    

    现在内联类型检查将是CHECKCAST android/database/sqlite/SQLiteDatabase,它将始终成功。

    【讨论】:

    • 是的,你是对的。在棒棒糖前 readableDatabase is Closeable 返回 false,而在棒棒糖上返回 true。我想知道,为什么自 API19 以来没有 SQLiteDatabase 实现 Closeable 接口的文档。但无论如何,谢谢!
    • 对不起,你把这个放在哪里了?
    • 那么您是说当我们支持旧版本的Android 时使用.use { ... } 不安全?例如,从 14 到 28 API
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-02-11
    • 2018-02-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多