簡體   English   中英

MVVM:嘗試使用 LiveData 加載數據時,ViewModel 為空

[英]MVVM: ViewModel is null when trying to load data using LiveData

因此,我正在嘗試構建一個簡單的 MVVM 接口,以將 ViewModel 檢索到的數據庫中的行程加載到我的 TripFragment 中。 但是,我不斷收到此錯誤消息,說我的 TripViewModel 為空:

Attempt to invoke virtual method 'void androidx.lifecycle.LiveData.observe(androidx.lifecycle.LifecycleOwner, androidx.lifecycle.Observer)' on a null object reference

我似乎無法弄清楚為什么它認為它為空。 我相信問題出在 TripViewModel 中,並且與它從 AndroidViewModel 繼承以及我在構造函數中傳遞應用程序的上下文有關。

類 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
}

類 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
}

類 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
}

旅行實體

@Entity
data class Trip(var title: String, var startDate: String, var endDate: String?) {

    @PrimaryKey(autoGenerate = true)
    var tid: Long = 0
}

編輯:我已經打印了一堆調試日志並在TripRepository這一行中指出了錯誤。

init {
    CoroutineScope(IO).launch {
        // tripDao is never assigned properly, 
        tripDao = AppDatabase.getDatabase(application.applicationContext).tripDao()
        allTrips = tripDao.getAll()
    }
}

tripDao = AppDatabase.getDatabase(application.applicationContext).tripDao()導致錯誤,將 tripDao 轉換為空變量。 問題與我獲取數據庫的方式有關,因此我在下面附上了我的 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
            }
        }
    }
}

我找不到修復我的數據庫訪問代碼的解決方案,所以我根據 Google 在 Codelabs 上的架構組件教程重構了我的整個代碼庫。 當然,這幫助我解決了我遇到的問題。 將來需要本教程的人的鏈接: https : //codelabs.developers.google.com/codelabs/android-room-with-a-view-kotlin/#13

在您的課程TripViewModel ,您有:

private var allTrips: LiveData<List<Trip>> = getAll()

fun getAll(): LiveData<List<Trip>> {
    return allTrips
}

所以你在這里有一個圓形的安排。 allTrips被分配了一個初始值,無論getAll()返回什么,但它在分配allTrips之前調用getAll() 所以你找到了一種將空值分配給不可空值的方法!

似乎您打算放置allTrips = tripRepository.getAll()

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM