Фрагмент пытается загрузить ранее удаленные данные - PullRequest
0 голосов
/ 03 февраля 2020

Я не мог понять это в течение нескольких дней. Проблема возникает, когда я удаляю элемент из моей базы данных во Фрагменте 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
}
...