возвращать результат и lateinit: выполнение свойств не было инициализировано - PullRequest
1 голос
/ 12 июня 2019

В моем приложении для Android мне нужно вернуть Response<Void> только после финиша longOperaton.Это может быть через 1 секунду или 10 секунд.

Фрагмент:

import kotlinx.coroutines.*
import retrofit2.Response
import java.util.*


 fun executeTraderOperation(traderOperation: Trader.Operation, base: String, quote: String): Response<Void> {
            lateinit var executions: Response<Void>
            GlobalScope.launch(Dispatchers.IO) {
                async {
                    executions = longOperation(traderOperation, base, quote)
                }
            }
            return executions
}

, но я получаю ошибку во время выполнения:

FATAL EXCEPTION: main
Process: com.myprojedt.debug, PID: 8059
kotlin.UninitializedPropertyAccessException: lateinit property executions has not been initialized
    at com.myprojedt.service.OperationFactory$Companion.executeTraderOperation(OperationFactory.kt:38)
    at com.myprojedt.viewmodel.AddTraderViewModel.doClickStart(AddTraderViewModel.kt:43)
    at com.myprojedt.ui.activity.AddTraderActivity.onClickStart(AddTraderActivity.java:110)
    at com.myprojedt.databinding.AddTraderActivityBindingImpl._internalCallbackOnClick(AddTraderActivityBindingImpl.java:160)
    at com.myprojedt.generated.callback.OnClickListener.onClick(OnClickListener.java:11)
    at android.view.View.performClick(View.java:5204)
    at android.view.View$PerformClick.run(View.java:21153)
    at android.os.Handler.handleCallback(Handler.java:739)
    at android.os.Handler.dispatchMessage(Handler.java:95)
    at android.os.Looper.loop(Looper.java:148)
    at android.app.ActivityThread.main(ActivityThread.java:5417)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:726)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:616)
   Force finishing activity com.myprojedt.debug/com.myprojedt.ui.activity.AddTraderActivity

PS

longOperation - это длительная сетевая операция

Ответы [ 2 ]

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

executeTraderOperation() вызывается в главном потоке приложения, любезно предоставлено onClick(). Затем вы создаете некоторый код для фонового потока, любезно предоставленный GlobalScope.launch(Dispatchers.IO). Затем вы возвращаете executions, который еще не был инициализирован кодом в фоновом потоке ... следовательно, сбой.

Перепишите это как:

suspend fun executeTraderOperation(traderOperation: Trader.Operation, base: String, quote: String): Response<Void> = withContext(Dispatchers.IO) {
    longOperation(traderOperation, base, quote)
}

Затем имейте doClickStart() на AddTraderViewModel, звоните executeTraderOperation() в подходящей области:

fun doClickStart() {
    viewModelScope.launch(Dispatchers.Main) {
        val response = longOperation(traderOperation, base, quote)
        TODO("do something with response")
    }
}

(это предполагает, что AddTraderViewModel - это AndroidX ViewModel и что у вас есть зависимость -ktx, чтобы дать вам viewModelScope)

1 голос
/ 13 июня 2019

Вот мое решение:

class AddTraderViewModel(application: Application) : AndroidViewModel(application) {
  private val isShowProgressLiveData = MutableLiveData<Boolean>()

 fun doClickStart(base: String, quote: String) {
         GlobalScope.launch(Dispatchers.Main) {
            val response = OperationFactory.executeTraderOperation2(Trader.Operation.CREATE, base, quote)
            if (response.isSuccessful) { // Returns true if http code is in the range [200..300). */
                isShowProgressLiveData.value = false
            } else {
                isShowProgressLiveData.value = false
            }
        }
    }

}


class OperationFactory {
companion object {

  suspend fun executeTraderOperation2(traderOperation: Trader.Operation, base: String, quote: String): Response<Void> = withContext(Dispatchers.IO) {
            runOperation(traderOperation, base, quote)
        }

        suspend fun runOperation(traderOperation: Trader.Operation, base: String, quote: String): Response<Void> {                
            val executeTraderOperation = myRestClient.executeTraderOperation(some_param_here)
            val response = executeTraderOperation.await()
            return response
        }
    }

}

import kotlinx.coroutines.Deferred;
import retrofit2.Call;
import retrofit2.Response;

 @GET("test/{my_operation}")
    Deferred<Response<Void>> executeTraderOperation(some_param_here);

и теперь отлично работает.

...