简体   繁体   English

MVVM:尝试使用 LiveData 加载数据时,ViewModel 为空

[英]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.

相关问题 使用 MVVM 视图模型和实时数据时,如何在配置更改后保留 RecyclerView 的滚动位置? - How to preserve scroll position of a RecyclerView after a configuration change when using MVVM viewmodel and livedata? 无法观察空数据-具有Livedata的MVVM - Cannot observe null data - MVVM with Livedata 如何观察viewmodel中的数据 LiveData + Courotine + MVVM + Retrofit - How to observe data in viewmodel LiveData + Courotine + MVVM + Retrofit 如何将ViewModel与存储库连接,以便将数据传播到视图(MVVM,Livedata) - How to connect ViewModel with Repository so that data is propagated to the View (MVVM, Livedata) LiveData - 使用 LiveData 时数据绑定返回 null - LiveData - Databinding returns null when using LiveData 将 LiveData/ViewModel 与片段一起使用? - Using LiveData/ViewModel with Fragments? MVVM 中视图和 ViewModel 之间的通信与 LiveData - Communication between view and ViewModel in MVVM with LiveData MVVM:复杂的View / ViewModel-&gt;多个LiveData对象? - MVVM: Complex View/ViewModel -> Multiple LiveData objects? 活动未观察到 ViewModel (MVVM) 对 LiveData 的更新 - Activity not observing update to LiveData from ViewModel (MVVM) 为什么 LiveData 在 ViewModel 中返​​回 null? - Why LiveData returns null in ViewModel?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM