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
相关产品推荐
相关产品推荐

