房间数据库中更新时的重复数据条目

问题描述

我有一个笔记应用程序。用户可以创建新笔记或更改现有笔记。

在这个应用程序中,我试图在用户更改现有笔记时自动保存笔记。因此,我使用 textWatcher 并在文本观察器的 saveNotes() 方法调用 onTextChanged() 方法。因此,我打算在每次用户从文本中添加删除任何字符时保存注释。

var ide: Int? = null  //Global Variable
//in OnCreate()
if(intent.getBooleanExtra("isViewOrUpdate",false)){
            viewOrOpenednote = intent.getSerializableExtra("note") as Note?
            ide = viewOrOpenednote?.id

在上面的两个代码示例中..整个想法是让变量 ide 充当检查器,即如果用户正在创建新笔记,它将返回 null 否则,它将存储笔记的 id 如果用户已打开现有笔记以查看或编辑该笔记。

下面是textWatcher

title_edit_text.addTextChangedListener((object : TextWatcher {
            override fun beforeTextChanged(p0: CharSequence?,p1: Int,p2: Int,p3: Int) {}
            override fun onTextChanged(p0: CharSequence?,p3: Int) {
                saveNote()   // here I 
            }
            override fun afterTextChanged(p0: Editable?) {}
        }))

saveNote()

private fun saveNote() {
                val note = Note()
                note.setTitle(Title)

                if (ide != null) {
                    note.setId(ide!!)  // Here I am assigning the note id to `ide` in case the 
                                         `saveNote()` is called when user has opened an existing note. If 
                                          this is a new note then ide will be null automatically.
                }
                class SaveNotes : AsyncTask<Void,Void,Void>() {
                    override fun doInBackground(vararg void: Void?): Void? {
                        NotesDatabase.getDatabase(applicationContext).noteDao().insertNote(note)
                        return null
                    }

                    override fun onPostExecute(result: Void?) {
                        super.onPostExecute(result)
                        ide = note.id               //This is because: If user has added a first 
                                                     character in new note,then after that an id will be 
                                                     assigned to this new database,whenever 
                                                    `saveNote()` method is called again after text change 
                                                     I need to save the changed note to the same existing 
                                                     id. I hope I am clear.

                     // ***UPDATE*** After much contemplation I have found out 
                       that here lies the problem! changing the value of ide by 
                       simply `ide = note.id` will always give null value for new 
                       note,as this id is not received from the created note,but from the blank note instance I created above. 
                    }
                }
                SaveNotes().execute()
}

问题:即使采取了上述预防措施,每次我更改笔记时,都会创建同一笔记的多个实例。示例:

假设我输入:你好

我得到的结果是 5 个不同 id 的不同笔记。和文字如下:

h //id = 5

他 //id = 4

hel //id = 3

地狱//id = 2

你好 //id = 1

NoteDao.java

@Dao
public interface NoteDao {

    @Query("SELECT * FROM note ORDER BY id DESC")
    List<Note> getAllNotes();

    @Insert(onConflict = OnConflictStrategy.REPLACE)
    void insertNote(Note note);

    @Delete
    void delete(Note note);
}

Note.java

@Entity(tableName = "note")
public class Note implements Serializable {

    @PrimaryKey(autoGenerate = true)
    private int id;

    @ColumnInfo(name = "title")

NoteDatabase.java

 public static synchronized NotesDatabase getDatabase(Context context)
    {
        if(notesDatabase == null){
           notesDatabase =  Room.databaseBuilder(context,NotesDatabase.class,"note_db"
                    )
                   .addMigrations(MIGRATION_1_2)
                   .build();
        }
        return notesDatabase;
    }


    public abstract NoteDao noteDao();

解决方法

每次在 onTextChange 中调用 saveNote 时,您都会创建一个新实例 (viewOrOpenedNote),因此传递您从数据库中获取或当前显示给用户的旧实例便笺对象。

//Pass the same note instance which you are showing on the screen.
@Update
fun updateNote(note: Note)

//Give note the same id as It saved in the previous note. e-g create a note instance but set Id = viewOrOpenedNote.id so that is where Conflict will arise and the database will replace it.
@Insert(onConflict = OnConflictStrategy.REPLACE)
fun insertNote(note: Note) : Long

使用协程

第一步:

def coroutines_android_version = '1.3.9'
// Coroutines libraries
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-core:$coroutines_core"
implementation "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_android_version"

第二步:

在班级层面明确它。

private val ioScope = CoroutineScope(Dispatchers.IO)

第三步:

ioScope.launch {
    saveNote()
}

suspend fun saveNote(){
    NotesDatabase.getDatabase(applicationContext).noteDao().insertNote(note)
}
,

像这样在你的 Dao 中创建一个函数

@Update(onConflict = OnConflictStrategy.REPLACE)
fun update(note: Note): Int

并将以下代码放入您的 saveNote 函数中

fun saveNote(item: Note) {
    database.runInTransaction {
        val id = item.id

        if(id == null)
            getNoteDao().insert(item)
        else
            getNoteDao().update(item)
    }
}
,

总结

考虑到您在 postExecuteMethod() 中指出 ide = note.id 处的错误所做的更改。执行以下操作:

1. 用这个

更改NoteDao.java中的插入块
@Insert(onConflict = OnConflictStrategy.REPLACE)
    long insertNote(Note note);  //long istead of void if you need the id as return

2.ide 的数据类型从 int

更改为 Long
    var ide: Long? = null

3.onCreate()

if(intent.getBooleanExtra("isViewOrUpdate",false)){
            viewOrOpenedNote = intent.getSerializableExtra("note") as Note?
              ide = viewOrOpenedNote?.id?.toLong() //Convert to long

4. 您现在只需要用下面的块替换 saveNote() 方法。

private fun saveNote() {
                val database = NotesDatabase.getDatabase(applicationContext) //add this here
                val note = Note()
                note.setTitle(Title)

                if (ide != null) {
                   note.setId(ide!!.toInt())  //convert to int as ide is long
                }
                class SaveNotes : AsyncTask<Void,Void,Void>() {
                    override fun doInBackground(vararg void: Void?): Void? {
                            ide = database.noteDao().insertNote(note)  // two things inone line: first insert the note and then get the id of the note saved
                        return null
                    }

                    override fun onPostExecute(result: Void?) {
                        super.onPostExecute(result)
                        // Let this be empty
                    }
                }
                SaveNotes().execute()
}