Использовать основной поток после длительной работы в сети - PullRequest
0 голосов
/ 12 июня 2019

В моем приложении для Android у меня есть длительная работа в сети.После завершения операции мне нужно обновить пользовательский интерфейс.

Так что в результате длинная операция должна выполняться в фоновом потоке.

Фрагмент:

private val isShowProgressLiveData = MutableLiveData<Boolean>()

  // launch a new coroutine in background and continue
GlobalScope.launch() {
            try {
                val executeOperations = OperationFactory.createExecuteTraderOperation(Trader.Operation.CREATE, base, quote)
                val response: Response<Void> = executeOperations.await()
                if (response.isSuccessful) { 
                    isShowProgressLiveData.value = false
                    isForwardToTradersLiveData.value = true
                } else {
                    Debug.w(TAG, "doClickStart_error")
                }
            } catch (e: Throwable) {
                Debug.e(TAG, "doClickStart_network error: $e.message", e)
            }
        }

Но я получаю ошибку

isShowProgressLiveData.value = false

Сообщение об ошибке:

java.lang.IllegalStateException: Cannot invoke setValue on a background thread
    at androidx.lifecycle.LiveData.assertMainThread(LiveData.java:461)
    at androidx.lifecycle.LiveData.setValue(LiveData.java:304)
    at androidx.lifecycle.MutableLiveData.setValue(MutableLiveData.java:50)
    at com.myoperation.AddTraderViewModel$doClickStart$3.invokeSuspend(AddTraderViewModel.kt:55)
    at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
    at kotlinx.coroutines.DispatchedTask.run(Dispatched.kt:238)
    at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:594)
    at kotlinx.coroutines.scheduling.CoroutineScheduler.access$runSafely(CoroutineScheduler.kt:60)
    at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:742)

Мне нужно обновить пользовательский интерфейс в главном потоке.Так как я могу это исправить?

Ответы [ 2 ]

2 голосов
/ 12 июня 2019

Вы можете переключиться на основной поток как с withContext(Dispatchers.Main) При запуске сопрограмма с запуском начнется на Dispatchers.Default. Лучше всего указать это так:

GlobalScope.launch(Dispatchers.IO) {
            try {
                val executeOperations = OperationFactory.createExecuteTraderOperation(Trader.Operation.CREATE, base, quote)
                val response: Response<Void> = executeOperations.await()
                if (response.isSuccessful) { 
                  withContext(Dispatchers.Main){ //switched to Main thread
                    isShowProgressLiveData.value = false
                    isForwardToTradersLiveData.value = true
                 }
                } else {
                    Debug.w(TAG, "doClickStart_error")
                }
            } catch (e: Throwable) {
                Debug.e(TAG, "doClickStart_network error: $e.message", e)
            }
        }
0 голосов
/ 12 июня 2019

Вы все еще в фоновом потоке, когда пытаетесь выполнить

isShowProgressLiveData.value = false

Вы можете сделать что-то вроде этого:

GlobalScope.launch() {
        try {
            val executeOperations = OperationFactory.createExecuteTraderOperation(Trader.Operation.CREATE, base, quote)
            val response: Response<Void> = executeOperations.await()
            if (response.isSuccessful) { 


                YourActivity.runOnUiThread(object:Runnable() {

                override fun run() {
                isShowProgressLiveData.value = false
                isForwardToTradersLiveData.value = true
                    }


             }
            } else {
                Debug.w(TAG, "doClickStart_error")
            }
        } catch (e: Throwable) {
            Debug.e(TAG, "doClickStart_network error: $e.message", e)
        }
    }
...