Я не мог понять это в течение нескольких дней. Проблема возникает, когда я удаляю элемент из моей базы данных во Фрагменте A. Затем я пытаюсь открыть Фрагмент B (который по сути является просто RecyclerView), но как только я это делаю, приложение вылетает. Это потому, что каким-то образом он все еще пытается загрузить удаленный элемент из фрагмента А. в RecyclerView.
Функция, которая удаляет все данные во фрагменте А (используя ViewModel
):
fun deleteSubject(subjectId: Long) {
// Deleting a task on another thread
// There is no need for the ViewModel to wait for the delete operation to complete so we can use this approach
// Deleting associated classes, tasks, exams
GlobalScope.launch {
getApplication<Application>().contentResolver?.delete(
LessonsContract.CONTENT_URI,
"${LessonsContract.Columns.LESSON_SUBJECT} = ?",
arrayOf(subjectId.toString())
)
}
GlobalScope.launch {
getApplication<Application>().contentResolver?.delete(
TasksContract.CONTENT_URI,
"${TasksContract.Columns.TASK_SUBJECT} = ?",
arrayOf(subjectId.toString())
)
}
GlobalScope.launch {
getApplication<Application>().contentResolver?.delete(
ExamsContract.CONTENT_URI,
"${ExamsContract.Columns.EXAM_SUBJECT} = ?",
arrayOf(subjectId.toString())
)
}
GlobalScope.launch {
getApplication<Application>().contentResolver?.delete(
SubjectsContract.buildUriFromId(
subjectId
), null, null
)
}
}
onCreate
во фрагменте B:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.cursorTasks.observe(
this,
Observer { cursor -> tasksAdapter.swapTasksCursor(cursor)?.close() }
)
viewModel.loadTasks()
}
swapTaskCursor
в пользовательском фрагменте B RecyclerView
Адаптер:
fun swapTasksCursor(newCursor: Cursor?): Cursor? {
if (newCursor === cursorTasks) {
return null
}
val numItems = itemCount
val oldCursor = cursorTasks
cursorTasks = newCursor
if (newCursor != null) {
//notify the observers about the new cursor
notifyDataSetChanged()
} else {
//notify the observers about the lack of a data set
notifyItemRangeRemoved(0, numItems)
}
return oldCursor
}
loadTasks()
функция во фрагменте B ViewModel
:
fun loadTasks() {
val projection = arrayOf(
TasksContract.Columns.ID,
TasksContract.Columns.TASK_NAME,
TasksContract.Columns.TASK_DESCRIPTION,
TasksContract.Columns.TASK_TYPE,
TasksContract.Columns.TASK_SUBJECT,
TasksContract.Columns.TASK_DUEDATE,
TasksContract.Columns.TASK_REMINDER
)
GlobalScope.launch {
val cursor = getApplication<Application>().contentResolver.query(
TasksContract.CONTENT_URI,
projection,
null,
null,
"${TasksContract.Columns.ID} DESC"
)
databaseCursor.postValue(cursor)
}
}
РЕДАКТИРОВАТЬ 1
Каждый объект задачи связан с ИД субъекта. Во фрагменте А я удаляю одну из тем и все ее задачи. Во фрагменте B RecyclerView показывает все задачи. Я получаю информацию о задаче с помощью следующей функции (которая принимает идентификатор субъекта в качестве параметра):
override fun loadSubjectFromTask(id: Long): Subject {
val subject = sharedViewModel.subjectFromId(id)
if (subject != null) {
return subject
} else {
// This exception gets thrown after I deleted the subject from Fragment A and opened Fragment B
throw Exception("Couldn't load subject from id $id")
}
}
Это функция subjectFromId
SharedViewModel:
fun subjectFromId(id: Long): Subject? {
val projection = arrayOf(
SubjectsContract.Columns.ID,
SubjectsContract.Columns.SUBJECT_NAME,
SubjectsContract.Columns.SUBJECT_TEACHER,
SubjectsContract.Columns.SUBJECT_COLORCODE
)
val cursor = getApplication<Application>().contentResolver.query(
SubjectsContract.buildUriFromId(id),
projection,
null,
null,
null
)
if (cursor != null) {
try {
if (cursor.moveToNext()) {
val subject = Subject(
cursor.getString(cursor.getColumnIndex(SubjectsContract.Columns.SUBJECT_NAME)),
cursor.getString(cursor.getColumnIndex(SubjectsContract.Columns.SUBJECT_TEACHER)),
cursor.getInt(cursor.getColumnIndex(SubjectsContract.Columns.SUBJECT_COLORCODE))
)
// Id is not set in the instructor
subject.subjectId =
cursor.getLong(cursor.getColumnIndex(SubjectsContract.Columns.ID))
return subject
}
} catch (e: Exception) {
e.printStackTrace()
throw Exception(e)
} finally {
cursor.close()
}
}
return null
}