我是 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?
uj5u.com熱心網友回復:
你必須讓你的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"
uj5u.com熱心網友回復:
Room DAO 函式應該總是掛起,這樣它就不能阻塞主 UI 執行緒,你可以參考這個谷歌推薦的例子:https : //developer.android.com/codelabs/android-room-with-a-view-kotlin#5
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/361490.html
