[英]How to preserve scroll position of a RecyclerView after a configuration change when using MVVM viewmodel and livedata?
[英]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.