在查询数据库时以错误的顺序接收数据
Receiving data in incorrect order on Querying database
Activity 接收意图
class AddNoteActivity : AppCompatActivity() {
private lateinit var addViewModel: NoteViewModel
private lateinit var titleEditText: TextInputEditText
private lateinit var contentEditText: TextInputEditText
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_add_note_activty)
setSupportActionBar(toolbar)
addViewModel = ViewModelProviders.of(this).get(NoteViewModel::class.java)
titleEditText = findViewById(R.id.itemTitle)
contentEditText = findViewById(R.id.itemNote)
val extra = intent.extras
if (extra != null) {
val uuid = extra.getLong("UUID")
val note: Notes? = addViewModel.getNote(uuid)
titleEditText.setText(note!!.title)
contentEditText.setText(note.note)
}
}
}
NoteViewModel class
class NoteViewModel(application: Application) : AndroidViewModel(application) {
companion object {
private var note: Notes = Notes(0, "", "test title", "test ontent")
}
fun getNote(uuid: Long?): Notes {
val job = async(CommonPool) {
getNoteAsyncTask(notesDatabase).execute(uuid)
}
runBlocking { job.await() }
return note
}
class getNoteAsyncTask(database: NotesDatabase) : AsyncTask<Long, Unit, Unit>() {
private val db: NotesDatabase = database
override fun doInBackground(vararg params: Long?) {
note = db.notesDataDao().getNote(params[0])
}
}
}
如果我通过 intent 从数据库中获取带有 uuid 的 Note 对象,并在 titleEditText 和 contentEditText 中设置接收到的数据,则 Note 中的数据集来自我们单击 Note 项时调用的先前 intent回收视图。第一次单击注释项时,我得到了我设置的默认值 "test title" 和 "test content".
上述是大部分时间的行为。有时 titleEditText 和 contentEditText 中的数据集是正确的 Note 对象。
有人可以告诉我我做错了什么吗?如何纠正我的应用程序行为?
不幸的是,您使用视图模型向视图提供数据的方式存在很大错误(AddNoteActivity
)。
基本上,您的视图从来没有机会等待数据被获取,因为它总是收到一个默认值。发生这种情况是因为 AsyncTask
在其自己的线程池上运行,因此协程会立即完成并且 returns 默认值。
您应该考虑使用 LiveData 来 post 一个新对象到您的视图并重构您的视图模型。
因此,您需要对数据库进行同步查询并观察对注释的更改,而不是对其进行 getter。当然,在现实生活场景中,拥有不同类型的状态以便能够在用户等待时显示微调器可能是个好主意。但这是另一个大问题。所以为了简单起见,考虑将您的视图模型更改为类似的东西:
class NoteViewModel(private val database: NotesDatabase) : ViewModel { // you do not need an application class here
private val _notes = MutableLiveData<Notes>()
val notes: LiveData<Notes> = _notes
fun loadNotes(uuid: Long) {
launch(CommonPool) {
val notes = database.notesDataDao().getNote(uuid)
_notes.setValue(notes)
}
}
}
然后,您可以观察 activity 中注释字段的变化。
class AddNoteActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ...
val noteViewModel = ViewModelProviders.of(this).get(NoteViewModel::class.java)
noteViewModel.notes.observe(this, Observer {
title.text = it.title
content.text = it.note
})
}
}
您还需要使用 ViewModelProvider.Factory 创建您的视图模型并正确地将依赖项注入其中。尽量避免在那里有上下文,因为它会使测试变得更加困难。
Activity 接收意图
class AddNoteActivity : AppCompatActivity() {
private lateinit var addViewModel: NoteViewModel
private lateinit var titleEditText: TextInputEditText
private lateinit var contentEditText: TextInputEditText
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_add_note_activty)
setSupportActionBar(toolbar)
addViewModel = ViewModelProviders.of(this).get(NoteViewModel::class.java)
titleEditText = findViewById(R.id.itemTitle)
contentEditText = findViewById(R.id.itemNote)
val extra = intent.extras
if (extra != null) {
val uuid = extra.getLong("UUID")
val note: Notes? = addViewModel.getNote(uuid)
titleEditText.setText(note!!.title)
contentEditText.setText(note.note)
}
}
}
NoteViewModel class
class NoteViewModel(application: Application) : AndroidViewModel(application) {
companion object {
private var note: Notes = Notes(0, "", "test title", "test ontent")
}
fun getNote(uuid: Long?): Notes {
val job = async(CommonPool) {
getNoteAsyncTask(notesDatabase).execute(uuid)
}
runBlocking { job.await() }
return note
}
class getNoteAsyncTask(database: NotesDatabase) : AsyncTask<Long, Unit, Unit>() {
private val db: NotesDatabase = database
override fun doInBackground(vararg params: Long?) {
note = db.notesDataDao().getNote(params[0])
}
}
}
如果我通过 intent 从数据库中获取带有 uuid 的 Note 对象,并在 titleEditText 和 contentEditText 中设置接收到的数据,则 Note 中的数据集来自我们单击 Note 项时调用的先前 intent回收视图。第一次单击注释项时,我得到了我设置的默认值 "test title" 和 "test content".
上述是大部分时间的行为。有时 titleEditText 和 contentEditText 中的数据集是正确的 Note 对象。
有人可以告诉我我做错了什么吗?如何纠正我的应用程序行为?
不幸的是,您使用视图模型向视图提供数据的方式存在很大错误(AddNoteActivity
)。
基本上,您的视图从来没有机会等待数据被获取,因为它总是收到一个默认值。发生这种情况是因为 AsyncTask
在其自己的线程池上运行,因此协程会立即完成并且 returns 默认值。
您应该考虑使用 LiveData 来 post 一个新对象到您的视图并重构您的视图模型。
因此,您需要对数据库进行同步查询并观察对注释的更改,而不是对其进行 getter。当然,在现实生活场景中,拥有不同类型的状态以便能够在用户等待时显示微调器可能是个好主意。但这是另一个大问题。所以为了简单起见,考虑将您的视图模型更改为类似的东西:
class NoteViewModel(private val database: NotesDatabase) : ViewModel { // you do not need an application class here
private val _notes = MutableLiveData<Notes>()
val notes: LiveData<Notes> = _notes
fun loadNotes(uuid: Long) {
launch(CommonPool) {
val notes = database.notesDataDao().getNote(uuid)
_notes.setValue(notes)
}
}
}
然后,您可以观察 activity 中注释字段的变化。
class AddNoteActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// ...
val noteViewModel = ViewModelProviders.of(this).get(NoteViewModel::class.java)
noteViewModel.notes.observe(this, Observer {
title.text = it.title
content.text = it.note
})
}
}
您还需要使用 ViewModelProvider.Factory 创建您的视图模型并正确地将依赖项注入其中。尽量避免在那里有上下文,因为它会使测试变得更加困难。