如何在Kotlin类中声明可被所有函数访问、在onCreate中初始化的val?
解决Kotlin ContentProvider中DBHelper的初始化与全局访问问题
在Kotlin里要实现类似Java那种在onCreate()中初始化、且能被类内所有方法访问的数据库助手实例,有两种常用的靠谱方案,我来给你拆解清楚:
方案1:用lateinit var(最贴近Java的写法)
lateinit关键字允许我们声明一个非空变量,延迟到后续再完成初始化——这完美适配你在onCreate()里初始化DBHelper的需求。而且ContentProvider的生命周期能保证onCreate()一定会在query()、insert()等业务方法之前被调用,所以后续访问时变量肯定已经完成初始化,不会出现未初始化的异常。
修改你的代码如下:
class ProviderMMR : ContentProvider() { // 用lateinit var声明,延迟初始化 private lateinit var dbHelper: mmrbd companion object Matcher { var uriMatcher = UriMatcher(UriMatcher.NO_MATCH) init { uriMatcher.addURI(MMDContract.columnas.AUTHORITY, MMDContract.columnas.TABLA_FARMACIA, 1) } } override fun onCreate(): Boolean { // 在这里完成DBHelper的初始化,ContentProvider的context此时已可用 dbHelper = mmrbd(context!!) return true } override fun insert(uri: Uri?, values: ContentValues?): Uri { val db = dbHelper.writableDatabase val rowID = db.insert(MMDContract.columnas.TABLA_FARMACIA, null, values) val uri_actividad = ContentUris.withAppendedId(MMDContract.columnas.CONTENT_BASE_URI, rowID) return uri_actividad } override fun query(uri: Uri?, projection: Array<out String>?, selection: String?, selectionArgs: Array<out String>?, sortOrder: String?): Cursor { val db = dbHelper.readableDatabase // 在这里实现你的查询逻辑 TODO("补充查询逻辑") } override fun update(uri: Uri?, values: ContentValues?, selection: String?, selectionArgs: Array<out String>?): Int { TODO("not implemented") } override fun delete(uri: Uri?, selection: String?, selectionArgs: Array<out String>?): Int { TODO("not implemented") } override fun getType(uri: Uri?): String { TODO("not implemented") } }
方案2:用val结合lazy委托(更Kotlin化的写法)
如果你坚持想要用不可变的val变量,可以结合lazy委托实现延迟初始化。lazy块会在变量第一次被访问时执行初始化逻辑,而因为onCreate()先于所有业务方法执行,第一次访问dbHelper时context肯定已经被系统赋值:
class ProviderMMR : ContentProvider() { // 用lazy委托实现延迟初始化的val private val dbHelper: mmrbd by lazy { mmrbd(context!!) } companion object Matcher { var uriMatcher = UriMatcher(UriMatcher.NO_MATCH) init { uriMatcher.addURI(MMDContract.columnas.AUTHORITY, MMDContract.columnas.TABLA_FARMACIA, 1) } } override fun onCreate(): Boolean { // 这里不需要手动初始化dbHelper,第一次访问时lazy块会自动执行 return true } override fun insert(uri: Uri?, values: ContentValues?): Uri { val db = dbHelper.writableDatabase val rowID = db.insert(MMDContract.columnas.TABLA_FARMACIA, null, values) val uri_actividad = ContentUris.withAppendedId(MMDContract.columnas.CONTENT_BASE_URI, rowID) return uri_actividad } // 其他重写方法和方案1一致... }
为什么不能用init块初始化?
Android Studio提示你必须在onCreate()中初始化,核心原因是:ContentProvider的context在类初始化阶段(也就是init块执行时)还没有被系统赋值——context是在ContentProvider被系统创建并调用onCreate()时才会传入的,所以在init块里根本拿不到可用的context来实例化mmrbd。
两种方案都能满足你的需求:如果更习惯Java的写法,选lateinit var;如果想保持Kotlin的不可变特性,选val + lazy的组合。
内容的提问来源于stack exchange,提问作者Eduardo Corona
相关产品推荐
相关产品推荐

