在 Android 開發中,我們常使用 Kotlin 的 use {} 語法來自動管理資源,例如關閉檔案、關閉資料庫 Cursor。但這個便利的語法在 Android 11 以下,對某些類別其實會出錯造成應用程式閃退。如果一時不查,小心這坑就這樣踩了下去…
錯誤說明
| |
這段程式碼在 Android 12(API 31)以上沒問題,但在 Android 11 (API 30) 以下執行時,會拋出以下錯誤:
| |
白話來說,上面這個錯誤告訴我們,TypedArray 並沒有實作 AutoCloseable 介面,所以在試圖呼叫 AutoCloseable.close() 時拋出 IncompatibleClassChangeError 錯誤。
問題釐清:use {} 的背後原理
Kotlin use {} 是一個 extension function,會在 Block 結束後自動呼叫 AutoCloseable.close() 方法來釋放資源。
| |
但在 Android 11 (API 30) 以下的版本,TypedArray 並沒有實作 AutoCloseable,也就是說它根本不支援 close() 方法,導致執行期間會嘗試呼叫一個不存在的方法,最後拋出錯誤導致 App 閃退。
正確做法:使用 AndroidX 的 use {}
改用 androidx.core.content.res.use ,而它的實作方式如下:
| |
跟 Kotlin 版相比, androidx.core.content.res.use 是用 recycle() 來釋放資源,不會去呼叫那個不存在的 AutoCloseable.close()。
結論,如果你遇到這個問題,請記得將 import androidx.core.content.res.use 補上,就沒問題了。
延伸補充與建議
Kotlin 的 use 有兩種實作來源:
在開發時建議檢查類別是否有實作 AutoCloseable 或 Closeable。
如果有實作就可以安心使用 Kotlin 的 use {} 。
否則請改用 AndroidX 提供的 use {} 方法,或者手動呼叫 recycle() 或 close() 釋放資源。
舉例:android.database.Cursor 就有實作 Closeable,所以可以使用 Kotlin 的 use {}。
以上就是本次的踩坑筆記分享,希望能幫到你的忙,或是至少能幫到未來的我自己!?🤯
下個坑見 🤪