[英]MVVM: ViewModel is null when trying to load data using LiveData
So I'm trying to build a simple MVVM interface to load trips from the database retrieved by the ViewModel into my TripFragment.因此,我正在尝试构建一个简单的 MVVM 接口,以将 ViewModel 检索到的数据库中的行程加载到我的 TripFragment 中。 However, I keep getting this error saying that my TripViewModel is null:但是,我不断收到此错误消息,说我的 TripViewModel 为空:
Attempt to invoke virtual method 'void androidx.lifecycle.LiveData.observe(androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Observer)' on a null object reference
I can't seem to figure out why it thinks that it's null.我似乎无法弄清楚为什么它认为它为空。 I believe the issue is in TripViewModel and has something to do with how the fact that it inherits from AndroidViewModel and that I'm passing the application's context in the constructor.我相信问题出在 TripViewModel 中,并且与它从 AndroidViewModel 继承以及我在构造函数中传递应用程序的上下文有关。
class TripFragment : Fragment()类 TripFragment : Fragment()
private var tripViewModel: TripViewModel? = null
private var textViewTripName: TextView? = null
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view =
inflater.inflate(R.layout.fragment_trip, container, false)
val recyclerView: RecyclerView = view.recycler_view
recyclerView.layoutManager = LinearLayoutManager(context)
recyclerView.setHasFixedSize(true)
val adapter = TripAdapter()
recyclerView.adapter = adapter
tripViewModel = ViewModelProvider(this).get(TripViewModel(activity!!.application)::class.java)
// This is the line where it crashes, it never executes past this
tripViewModel!!.getAll().observe(viewLifecycleOwner, Observer<List<Trip>> {
fun onChanged(trips: List<Trip>) {
adapter.setTrips(trips)
Log.d("TripFragment", "Went through observer")
}
})
return view
}
class TripViewModel(application: Application): AndroidViewModel(application)类 TripViewModel(应用程序:应用程序):AndroidViewModel(应用程序)
private var tripRepository: TripRepository = TripRepository(application)
private var allTrips: LiveData<List<Trip>> = getAll()
fun insert(trip: Trip) {
tripRepository.insert(trip)
}
fun update(trip: Trip) {
tripRepository.update(trip)
}
fun delete(trip: Trip) {
tripRepository.delete(trip)
}
fun clear() {
tripRepository.clear()
}
fun getAll(): LiveData<List<Trip>> {
return allTrips
}
class TripRepository(application: Application)类 TripRepository(应用程序:应用程序)
private lateinit var tripDao: TripDao
private lateinit var allTrips: LiveData<List<Trip>>
init {
CoroutineScope(IO).launch {
tripDao = AppDatabase.getDatabase(application.applicationContext).tripDao()
allTrips = tripDao.getAll()
}
}
fun insert(trip: Trip) {
CoroutineScope(IO).launch {
tripDao.insert(trip)
}
}
fun update(trip: Trip) {
CoroutineScope(IO).launch {
tripDao.update(trip)
}
}
fun delete(trip: Trip) {
CoroutineScope(IO).launch {
tripDao.delete(trip)
}
}
fun clear() {
CoroutineScope(IO).launch {
tripDao.clear()
}
}
fun getAll(): LiveData<List<Trip>> {
return allTrips
}
Trip entity旅行实体
@Entity
data class Trip(var title: String, var startDate: String, var endDate: String?) {
@PrimaryKey(autoGenerate = true)
var tid: Long = 0
}
EDIT: I've printed a bunch of debug logs and pinpointed the error at this line in TripRepository
.编辑:我已经打印了一堆调试日志并在TripRepository
这一行中指出了错误。
init {
CoroutineScope(IO).launch {
// tripDao is never assigned properly,
tripDao = AppDatabase.getDatabase(application.applicationContext).tripDao()
allTrips = tripDao.getAll()
}
}
The line tripDao = AppDatabase.getDatabase(application.applicationContext).tripDao()
causes an error which turns tripDao into a null variable.行tripDao = AppDatabase.getDatabase(application.applicationContext).tripDao()
导致错误,将 tripDao 转换为空变量。 The problem has something to do with how I fetch the database, so I've attached my AppDatabase class below.问题与我获取数据库的方式有关,因此我在下面附上了我的 AppDatabase 类。
@Database(entities = [Trip::class], version = 2, exportSchema = false)
abstract class AppDatabase : RoomDatabase() {
abstract fun tripDao(): TripDao
companion object {
// Singleton prevents multiple instances of database opening at the
// same time.
@Volatile
private var INSTANCE: AppDatabase? = null
fun getDatabase(context: Context): AppDatabase {
val tempInstance = INSTANCE
if (tempInstance != null) {
Log.d("AppDatabase", "Returning existing database")
return tempInstance
}
synchronized(this) {
val instance = Room.databaseBuilder(
context.applicationContext,
AppDatabase::class.java,
"tripweaver_database"
)
.fallbackToDestructiveMigration()
.build()
INSTANCE = instance
Log.d("AppDatabase", "Returning new database")
return instance
}
}
}
}
I couldn't find the solution to fixing my database access code so I restructured my whole codebase according to the architecture components tutorial by Google on Codelabs.我找不到修复我的数据库访问代码的解决方案,所以我根据 Google 在 Codelabs 上的架构组件教程重构了我的整个代码库。 Surely enough this helped me fix the issues I was having.当然,这帮助我解决了我遇到的问题。 Link for whoever needs this tutorial in the future: https://codelabs.developers.google.com/codelabs/android-room-with-a-view-kotlin/#13将来需要本教程的人的链接: https : //codelabs.developers.google.com/codelabs/android-room-with-a-view-kotlin/#13
In your class TripViewModel
, you have:在您的课程TripViewModel
,您有:
private var allTrips: LiveData<List<Trip>> = getAll()
fun getAll(): LiveData<List<Trip>> {
return allTrips
}
So you have a circular arrangement here.所以你在这里有一个圆形的安排。 allTrips
is assigned an initial value of whatever getAll()
returns, but it's calling getAll()
before allTrips
is assigned. allTrips
被分配了一个初始值,无论getAll()
返回什么,但它在分配allTrips
之前调用getAll()
。 So you found a way to assign a null to a non-nullable!所以你找到了一种将空值分配给不可空值的方法!
Seems like maybe you meant to put allTrips = tripRepository.getAll()
.似乎您打算放置allTrips = tripRepository.getAll()
。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.