You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android Kotlin类初始化问题:lateinit属性未初始化报错求解

Android中Kotlin类初始化问题:lateinit未初始化错误

问题描述

在Android Studio中使用Kotlin开发时,声明了private lateinit var db: AppDatabase,但调用getPinjamanAktif()方法时总是收到lateinit property db has not been initialized错误提示,不清楚如何正确初始化类。

相关代码如下:

PinjamanSuperRepository代码

class PinjamanSuperRepository(
    private val api: PinjamanApi,
    private val preferences: UserPreferences
) : BasePinjamanRepository(){
    private lateinit var db: AppDatabase
    private val pagingSourceFactory = { db.pinjamanAktifDao.select_all() }
    @ExperimentalPagingApi
    fun getPinjamanAktif(): Flow<PagingData<Data>> {
        return Pager(
            config = PagingConfig(
                pageSize = NETWORK_PAGE_SIZE,
                enablePlaceholders = false
            ),
            remoteMediator = PlayersRemoteMediator(
                api,
                db
            ),
            pagingSourceFactory = pagingSourceFactory
        ).flow
    }
    companion object {
        private const val NETWORK_PAGE_SIZE = 25
    }
}

AppDatabase代码

abstract class AppDatabase : RoomDatabase() {
    abstract val pinjamanAktifDao: PinjamanAktifDao
    abstract val remoteKeysDao: RemoteKeysDao
    companion object {
        
        @Volatile
        private var instance: AppDatabase? = null
        private val LOCK = Any()

        operator fun invoke(context: Context) = instance
            ?: synchronized(LOCK) {
                instance ?: buildDatabase(
                    context
                ).also {
                    instance = it
                }
            }

        private fun buildDatabase(context: Context) =
            Room.databaseBuilder(
                context.applicationContext,
                AppDatabase::class.java,
                "app_db"
            ).fallbackToDestructiveMigration()
                .build()
    }
}

错误原因

你用lateinit修饰db变量,意味着承诺在首次使用前完成初始化,但代码中db从未被赋值,调用getPinjamanAktif()时它仍处于未初始化状态,因此抛出异常。

正确的初始化方式

针对你的场景,推荐以下几种可行方案:

方案一:构造函数注入AppDatabase实例

这是最符合依赖注入原则的方式,将AppDatabase作为构造参数传入Repository,避免直接依赖Context或自行创建实例:

class PinjamanSuperRepository(
    private val api: PinjamanApi,
    private val preferences: UserPreferences,
    private val db: AppDatabase // 直接通过构造函数注入
) : BasePinjamanRepository(){
    private val pagingSourceFactory = { db.pinjamanAktifDao.select_all() }
    @ExperimentalPagingApi
    fun getPinjamanAktif(): Flow<PagingData<Data>> {
        return Pager(
            config = PagingConfig(
                pageSize = NETWORK_PAGE_SIZE,
                enablePlaceholders = false
            ),
            remoteMediator = PlayersRemoteMediator(
                api,
                db
            ),
            pagingSourceFactory = pagingSourceFactory
        ).flow
    }
    companion object {
        private const val NETWORK_PAGE_SIZE = 25
    }
}

创建Repository实例时传入已初始化的AppDatabase:

val db = AppDatabase.invoke(context)
val repository = PinjamanSuperRepository(api, preferences, db)

方案二:使用by lazy延迟初始化

如果无法通过构造函数注入,可使用by lazy实现延迟初始化,首次访问时自动执行初始化逻辑:

class PinjamanSuperRepository(
    private val api: PinjamanApi,
    private val preferences: UserPreferences,
    private val context: Context // 需要传入Context
) : BasePinjamanRepository(){
    private val db: AppDatabase by lazy {
        AppDatabase.invoke(context)
    }
    private val pagingSourceFactory = { db.pinjamanAktifDao.select_all() }
    @ExperimentalPagingApi
    fun getPinjamanAktif(): Flow<PagingData<Data>> {
        return Pager(
            config = PagingConfig(
                pageSize = NETWORK_PAGE_SIZE,
                enablePlaceholders = false
            ),
            remoteMediator = PlayersRemoteMediator(
                api,
                db
            ),
            pagingSourceFactory = pagingSourceFactory
        ).flow
    }
    companion object {
        private const val NETWORK_PAGE_SIZE = 25
    }
}

方案三:在Repository初始化时手动赋值

若坚持使用lateinit,需在调用getPinjamanAktif()前完成初始化,比如在init块中:

class PinjamanSuperRepository(
    private val api: PinjamanApi,
    private val preferences: UserPreferences,
    private val context: Context
) : BasePinjamanRepository(){
    private lateinit var db: AppDatabase
    
    init {
        db = AppDatabase.invoke(context)
    }
    
    private val pagingSourceFactory = { db.pinjamanAktifDao.select_all() }
    @ExperimentalPagingApi
    fun getPinjamanAktif(): Flow<PagingData<Data>> {
        return Pager(
            config = PagingConfig(
                pageSize = NETWORK_PAGE_SIZE,
                enablePlaceholders = false
            ),
            remoteMediator = PlayersRemoteMediator(
                api,
                db
            ),
            pagingSourceFactory = pagingSourceFactory
        ).flow
    }
    companion object {
        private const val NETWORK_PAGE_SIZE = 25
    }
}

注意事项

  • lateinit仅适用于非空类型变量,必须在首次使用前完成初始化,否则会抛出异常。
  • 优先选择构造函数注入,降低代码耦合度,便于测试。
  • by lazy默认是线程安全的,适合大多数Android开发场景。

内容的提问来源于stack exchange,提问作者NUR KHOLIQ

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.02 01:17:18