我是 kotlin 和 android 開發的初學者。我在 Room教程中遵循了Persist data並且我有一個流行的問題來保存我的數據:
Cannot access database on the main thread since it may potentially lock the UI for a long period of time.
我通過閱讀其他回復來理解原因。但我不明白如何處理它。
我的實體及其 DAO :
@Entity
data class AccountConfiguration(
@PrimaryKey val server_address: String,
@ColumnInfo(name = "user_name") val user_name: String,
@ColumnInfo(name = "password") val password: String, // FIXME : secure storage
@ColumnInfo(name = "notify_hungry") val notify_hungry: Boolean,
@ColumnInfo(name = "notify_thirsty") val notify_thirsty: Boolean,
@ColumnInfo(name = "notify_ap") val notify_ap: Boolean,
@ColumnInfo(name = "network_grab_each") val network_grab_each: Int,
)
@Dao
interface AccountConfigurationDao {
@Query("SELECT * FROM accountconfiguration LIMIT 1")
fun get(): Flow<AccountConfiguration>
@Query("DELETE FROM accountconfiguration")
fun clear()
@Insert
fun insert(account_configuration: AccountConfiguration)
}
它的視圖模型:
class AccountConfigurationViewModel(private val repository: AccountConfigurationRepository) : ViewModel() {
val accountConfiguration: LiveData<AccountConfiguration> = repository.accountConfiguration.asLiveData()
fun insert(account_configuration: AccountConfiguration) = viewModelScope.launch {
repository.update(account_configuration)
}
fun isEntryValid(server_address: String, user_name: String, password: String, network_grab_each: Int): Boolean {
if (server_address.isBlank() || user_name.isBlank() || password.isBlank() || network_grab_each < 5 * 60) {
return false
}
return true
}
}
然後,有關視圖的一部分(此處為整個文件):
class AccountConfigurationFragment : Fragment() {
private var _binding: AccountConfigurationFragmentBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
private val viewModel: AccountConfigurationViewModel by activityViewModels {
AccountConfigurationViewModelFactory(
(activity?.application as RollingDashboardApplication).account_configuration_repository
)
}
lateinit var accountConfiguration: AccountConfiguration
// [...] hidden code
private fun save() {
Toast.makeText(context, R.string.saving, Toast.LENGTH_LONG).show()
if (isEntryValid()) {
val networkGrabEach = 3600 // FIXME : determine value for real
viewModel.insert(
AccountConfiguration(
server_address = binding.textInputServerAddress.text.toString(),
// [...] hidden code
network_grab_each = networkGrabEach,
)
)
Toast.makeText(context, R.string.account_configuration_saved, Toast.LENGTH_LONG).show()
findNavController().navigate(R.id.action_AccountConfigurationFragment_to_DashboardFragment)
} else {
Toast.makeText(context, R.string.wrong_inputs, Toast.LENGTH_LONG).show()
}
}
// [...] hidden code
}
我不明白這個調用viewModel.insert(
是如何異步的。NoteAccountConfigurationRepository.update
已經是一個suspend
函數。我嘗試通過這樣的修改沒有成功(同樣的錯誤):
- fun insert(account_configuration: AccountConfiguration) = viewModelScope.launch {
+ suspend fun insert(account_configuration: AccountConfiguration) = viewModelScope.launch {
lifecycleScope.launch { // coroutine on Main
viewModel.insert(
// ...
我怎樣才能讓這個數據庫插入非阻塞 UI?
你必須讓你的DAO
方法掛起,這樣它們就不會阻塞UI thread
@Dao
interface AccountConfigurationDao {
@Query("SELECT * FROM accountconfiguration LIMIT 1")
fun get(): Flow<AccountConfiguration>
@Query("DELETE FROM accountconfiguration")
suspend fun clear() //make this suspend
@Insert
suspend fun insert(account_configuration: AccountConfiguration) //make this suspend
}
我試過你的github
代碼,你必須取消註釋implementation "androidx.room:room-runtime:$room_version"
。
我認為 Room 中存在一個錯誤,2.3.0
因為它Not sure how to handle query method's return type (java.lang.Object).
在將suspend
關鍵字添加到DAO
. 你應該使用房間2.4.0-beta02
def room_version = "2.4.0-beta02"
implementation "androidx.room:room-runtime:$room_version"
implementation "androidx.room:room-ktx:$room_version"
kapt "androidx.room:room-compiler:$room_version"
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句