В нашем приложении так много запросов, и теперь мы используем ROOM, я хочу подтвердить, что это правильный способ использования Coroutine, прежде чем мы использовали это
В Дао
@Query("SELECT * FROM VISITS")
suspend fun getAllVisits(): List<Visits>
И мы получаем вот так
fun getAll(visit: Visits?) = runBlocking {
Log.i(TAG, "addOrUpdateRecord")
try {
val list = ArrayList<Visits>()
list.addAll(async {
visitsDao.getAllVisits()
}.await())
}
Но в какой-то статье я читал, что блокировка запуска предназначена только для тестирования, а не для производства, пожалуйста, направьте меня правильным образом Спасибо
Я не могу использовать withcontext без runblocker.
вам нужно создать класс, расширяющий ViewModel (), и просто реализовать @Glenn Sandoval. подробнее здесь developer.android.com/topic/libraries/architecture/viewmodel
Вы можете использовать что-то вроде этого
GlobalScope.launch {
withContext(Dispatchers.IO){
// your query
}
}
на основе ответов @Chirag Rayani, если вы используете viewModel, вы можете использовать viewModelScope.launch {withContext (dispatchers.IO)} и объединить его с liveata.postValue ()
если вы используете viewModelScope и скажете, что вы обновляете одну строку в db, и перед обновлением строки вы переключаетесь на другое действие, тогда вы можете получить исключение или данные могут не обновиться в db. поэтому я думаю, что лучше использовать GlobalScope @Yehezkiel L
пока viewModel прикреплен к жизненному циклу активности или фрагмента, он все еще в порядке cmiiw
GlobalScope не является хорошей практикой GlobalScope никогда не убивает автоматически, даже если мы закрываем приложение, поэтому я не использую это
Если вам нужна область сопрограммы для запуска сопрограммы, у вас есть lifecycleScope или viewModelScope, готовые к использованию в соответствии с вашими потребностями.
Внутри действия:
fun myMethod() {
lifecycleScope.launch {
val list = visitsDao.getAllVisits()
//Do something with list here
...
}
}
Внутри фрагмента:
fun myMethod() {
viewLifecycleOwner.lifecycleScope.launch {
val list = visitsDao.getAllVisits()
//Do something with list here
...
}
}
Внутри ViewModel:
fun myMethod() {
viewModelScope.launch {
val list = visitsDao.getAllVisits()
//Do something with list here
...
}
}
Внутри обычного класса:
class MyPresenter: CoroutineScope {
private val myJob = Job()
override val coroutineContext: CoroutineContext
get() = Dispatchers.Default + myJob
...
fun myMethod() {
launch {
val list = visitsDao.getAllVisits()
//Do something with list here
...
}
}
...
//Call clear when required
fun clear() {
this.myJob.cancel()
}
}
Наш шаблон проектирования - MVP, но я могу использовать этот метод?
@bakhtiyarhussain Вы можете реализовать CoroutineScope в Presenter следующим образом: class MyPresenter: CoroutineScope by MainScope(){ ... }. Используйте подходящий Диспетчер в соответствии с вашими потребностями или создайте его CoroutineContext самостоятельно, без делегирования. Только будьте осторожны, чтобы правильно отменить его прицел
если я реализую CoroutineScope, как вы делаете в презентаторе в моем tableHelperClass, и использую запуск (Dispatchers.IO) при выполнении моих запросов, это хорошая практика?
@bakhtiyarhussain Если вы добавите ключевое слово suspend в свой метод DAO, вам не нужно беспокоиться о диспетчере, который выполняет вызов. Room выполнит запрос в фоновом потоке.
так что мне просто нужно использовать запуск? и это правильный способ, о котором я упоминаю?
и как отменить выполнение длинного запроса, если пользователь нажал и перешел к другому действию, как отменить выполняющийся запрос?
@bakhtiyarhussain launch будет работать на диспетчере coroutineContext. Просто убедитесь, что вы создали CoroutineContext с правильным диспетчером, и когда вам нужно изменить диспетчер внутри функции, вы можете использовать withContext. В вашем случае достаточно просто пометить метод DAO как приостановленный. Как я уже упоминал, Room выполнит запрос в фоновом потоке.
@bakhtiyarhussain Чтобы отменить выполнение, просто вызовите cancel в задании или в CoroutineScope. Посмотрите на метод clear, который я сделал.
в презентаторе мы не используем myJob, а просто используем для отмены?
@bakhtiyarhussain Один из элементов CoroutineContext - это Job. Каждый вызов launch возвращает задание. Используйте это задание для cancel сопрограммы. В MyPresenter я создаю задание, которое использую для построения CoroutineContext, и использую это задание для отмены всего, используя преимущества структурированного параллелизма.
Я делаю то же самое и использую this.myjob.cancel, но работа не отменяется
@bakhtiyarhussain Сделать сопрограммы совместимыми с отменой. Это может помочь вам понять, как работают сопрограммы: kotlinlang.org/docs/cancellation-and-timeouts.html
пожалуйста, посмотрите stackoverflow.com/questions/66914896/…
Большое спасибо, @Glenn Sandoval, вы решили мою проблему
В Viewmodel:
viewmodelScope.launch(Dispatchers.IO){
visitsDao.getAllVisits()
}
ИЛИ другая функция приостановки
suspend fun addAll() {
visitsDao.getAllVisits().run{
ArrayList<Visits>().addAll(this)
}
}
EvenMore, просто используйте поток, и вы можете сделать это с помощью Live Data Builder / map / asLiveData и т. д.
посмотрите плз stackoverflow.com/questions/66914896/…
Да, я это видел. И вот мой результат, запускать блокировку не рекомендуется. Проверьте ссылка на сайт. «Основной поток, вызывающий runBlocking, блокирует, пока сопрограмма внутри runBlocking не завершится». Если у вас нет ViewModel, просто используйте MainScope (), который может быть отменен, когда вид будет уничтожен. И вы можете создать свой собственный, просто используя SupervisorJob () + Диспетчеры.Главная.
Кстати, я привык использовать MainScope до того, как Google создал viewModelScope и lifecycleScope. Проверить kotlinx.coroutines / -main-scope
Вы можете использовать либо launch {}, либо withContext (io) {} <- этот тип возврата