I use Room in my Android Studio project.
I hope to get the ID of added record quickly, but the following Code A can't work, how can I fix it? or I have to use these code just like Code B?
I have no way to get a return value of suspend function directly in Kotlin ?
Code A
@Dao
interface RecordDao {
@Insert(onConflict = OnConflictStrategy.REPLACE)
suspend fun addRecord(aRecordEntity: RecordEntity): Long
}
class RecordRepository @Inject constructor(private val mRecordDao:RecordDao): IRecordRepository {
override suspend fun addRecord(aMRecord: MRecord): Long = withContext(Dispatchers.Default) {
mRecordDao.addRecord(ModelMapper.modelToEntity(aMRecord))
}
}
@HiltViewModel
class SoundViewModel @Inject constructor(
private val aRecordRepository: IRecordRepository
): ViewModel()
{
fun addRecord(aMRecord: MRecord):Long= viewModelScope.async {
aSoundMeter.addRecord(aMRecord)
}.await()
}
Code B
//The same
@HiltViewModel
class SoundViewModel @Inject constructor(
private val aRecordRepository: IRecordRepository
): ViewModel()
{
var id = 0L;
fun addRecord(aMRecord: MRecord) {
viewModelScope.launch {
id = aSoundMeter.addRecord(aMRecord)
}
}
}
CodePudding user response:
You can only return the value of a suspend function from another suspend function. So make your ViewModel's function a suspend
function:
@HiltViewModel
class SoundViewModel @Inject constructor(
private val aRecordRepository: IRecordRepository
): ViewModel()
{
suspend fun addRecord(aMRecord: MRecord): Long =
aSoundMeter.addRecord(aMRecord)
}
And launch a coroutine to call it and work with the results in your Fragment:
viewLifecycleOwner.lifecycleScope.launch {
// ...
val id = viewModel.addRecord(record)
// do something with id inside same launched coroutine
}
Note, if you're doing something critical to repository state, you should be using the results of addRecord
inside a coroutine launched in the ViewModel instead. In that case, the Fragment should just "fire and forget" by calling some regular function in the ViewModel that has no return value.
Also, there are two issues with your code that I think show a misunderstanding:
Your repo code wraps the call to the DAO's suspend function using
withContext
. There is no reason to wrap a suspend function call inwithContext()
because the DAO suspend function already internally handles calling things on the right threads or dispatchers. It would be incorrect for a suspend function to ever block such that a specific IO or Default Dispatcher would be needed to call it.withContext(Dispatchers.IO)
is for when you are calling blocking IO functions, like directly working with InputStreams and OutputStreams.Never use
async { }.await()
. That's pointless and no different than directly calling the functions that you are wrapping inasync
since you are waiting for them immediately anyway.