Warning: file_get_contents(/data/phpspider/zhask/data//catemap/3/android/207.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android 如何从协同程序返回响应值_Android_Class_Kotlin_Fragment_Coroutine - Fatal编程技术网

Android 如何从协同程序返回响应值

Android 如何从协同程序返回响应值,android,class,kotlin,fragment,coroutine,Android,Class,Kotlin,Fragment,Coroutine,我最近和Kotlin一起工作,我被这个问题困扰了。我试图返回一个协程api调用函数的float值receive onResponse。我试图创建一个处理api调用的类,并在片段上使用它 functional.kt class FunctionA(val context: Context?, val A: Float?, val B: String?){ private var cardApi: CardApi = ApiClient.createApi().create(CardApi

我最近和Kotlin一起工作,我被这个问题困扰了。我试图返回一个协程api调用函数的float值receive onResponse。我试图创建一个处理api调用的类,并在片段上使用它

functional.kt


class FunctionA(val context: Context?, val A: Float?, val B: String?){

   private var cardApi: CardApi = ApiClient.createApi().create(CardApi::class.java)

   ....

   func getBalance(cardNo: String): Float?{
       val cardBalance: Float = null

       GlobalScope.launch(Dispatchers.Main) {
            val cardDetails = cardApi.getCardBalance(cardNo)
            cardDetails.enqueue(object : Callback<Card> {
                override fun onFailure(call: Call<Card>, t: Throwable) {
                    trackEvent(API_READ_CARD_BALANCE_ERROR, ERROR to t.message!!)
                }

                override fun onResponse(call: Call<Card>, response: Response<Card>) {
                    if (response.isSuccessful) {
                        val card = response.body()!!
                        cardBalance = card.cardAvailableBalance

                    } else {
                        val error: ApiError = ErrorUtils.parseError(response)
                        val message = error.code + error.message
                        trackEvent(API_READ_CARD_BALANCE_ERROR, ERROR to message)
                        context!!.toast("Errror: " + message)

                        promptErrorDialog(error)
                    }
                }
            })
        }}

        return cardBalance
   }
   ....
   ....

}


class FragmentClass : BaseFragment(){

    val galA = 10.5f
    val galB = "Test"
    private var pass = FunctionA(context!!, valA ,valB)

    ....

    val point = "sasd12125"
    private fun gooToo(){
        val B = pass.getBalance(point)
        print("TEST")
        println("value B: " + B)
    }
    ....

}


TEST
value B: null


class FunctionA(val context: Context?, val A: Float?, val B: String?){

   private var cardApi: CardApi = ApiClient.createApi().create(CardApi::class.java)
   private var card: Card? = null

   interface CardBalanceCallback {
       fun processFinish(output: Boolean, cardBalance: Float?)
   }

   fun getCardBalance(cardNo: String, callback: CardBalanceCallback) = runBlocking {
       getBalance(cardNo, callback)
   }

   private fun getBalance(cardNo: String, callback: CardBalanceCallback) = CoroutineScope(Dispatchers.Main).launch {
        try {
            val response = cardApi.getCardBalance(cardNo).await()
            if (response.isSuccessful) {
                card = response.body()
                callback.processFinish(true, card!!.cardAvailableBalance)
            } else {
                callback.processFinish(false, null)
                val error: ApiError = ErrorUtils.parseError(response)
                val message = when {
                    error.error.code.isNotEmpty() -> error.error.code + error.error.message
                    else -> error.code + error.message
                }
                trackEvent(API_READ_CARD_BALANCE_ERROR, ERROR to message)
                promptErrorDialog(error)
            }
        } catch (e: HttpException) {
            callback.processFinish(false, null)
            trackEvent(API_READ_CARD_BALANCE_ERROR, ERROR to e.message!!)
            context!!.toast(e.message.toString())
        } catch (e: Throwable) {
            callback.processFinish(false, null)
            trackEvent(API_READ_CARD_BALANCE_ERROR, ERROR to e.message!!)
            context!!.toast( e.message.toString())
        }
    }
   ....
   ....

}


class FragmentClass : BaseFragment(){

    private var funcService = FunctionA(null, null ,null)

    ....

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        (activity!!.application as App).component.inject(this)

        val valA = 10.5f
        val valB = "Test"
        val cardNo = "4001526976443264"
        val cardExpDate = "1119"

        funcService = FunctionA(context!!, valA ,valB)
        getCardBalanceApi(cardNo, cardExpDate)

    }

    .... 

    private fun getCardBalanceApi(cardNo: String, cardExpDate: String?) {
        showLoadingDialog()
        funcService.getCardBalance(cardNo, object : SmartPayService.CardBalanceCallback {
            override fun processFinish(output: Boolean, cardBalance: Float?) {
                dismissLoadingDialog()
                if (cardBalance != null) {
                    checkBalance(cardNo, cardBalance, cardExpDate)
                }
            }
        })
    }

    ....

}

现在发生了什么,因为协同程序将在后台花费一些时间,
valb
为空,并且没有得到响应时获得的值。只有在我再次尝试调用该函数之后,才会更新该值。我不确定我是否做得对,我也试着寻找解决办法,但这不符合我目前的情况。也许我的搜索技术太差了

输出


class FunctionA(val context: Context?, val A: Float?, val B: String?){

   private var cardApi: CardApi = ApiClient.createApi().create(CardApi::class.java)

   ....

   func getBalance(cardNo: String): Float?{
       val cardBalance: Float = null

       GlobalScope.launch(Dispatchers.Main) {
            val cardDetails = cardApi.getCardBalance(cardNo)
            cardDetails.enqueue(object : Callback<Card> {
                override fun onFailure(call: Call<Card>, t: Throwable) {
                    trackEvent(API_READ_CARD_BALANCE_ERROR, ERROR to t.message!!)
                }

                override fun onResponse(call: Call<Card>, response: Response<Card>) {
                    if (response.isSuccessful) {
                        val card = response.body()!!
                        cardBalance = card.cardAvailableBalance

                    } else {
                        val error: ApiError = ErrorUtils.parseError(response)
                        val message = error.code + error.message
                        trackEvent(API_READ_CARD_BALANCE_ERROR, ERROR to message)
                        context!!.toast("Errror: " + message)

                        promptErrorDialog(error)
                    }
                }
            })
        }}

        return cardBalance
   }
   ....
   ....

}


class FragmentClass : BaseFragment(){

    val galA = 10.5f
    val galB = "Test"
    private var pass = FunctionA(context!!, valA ,valB)

    ....

    val point = "sasd12125"
    private fun gooToo(){
        val B = pass.getBalance(point)
        print("TEST")
        println("value B: " + B)
    }
    ....

}


TEST
value B: null


class FunctionA(val context: Context?, val A: Float?, val B: String?){

   private var cardApi: CardApi = ApiClient.createApi().create(CardApi::class.java)
   private var card: Card? = null

   interface CardBalanceCallback {
       fun processFinish(output: Boolean, cardBalance: Float?)
   }

   fun getCardBalance(cardNo: String, callback: CardBalanceCallback) = runBlocking {
       getBalance(cardNo, callback)
   }

   private fun getBalance(cardNo: String, callback: CardBalanceCallback) = CoroutineScope(Dispatchers.Main).launch {
        try {
            val response = cardApi.getCardBalance(cardNo).await()
            if (response.isSuccessful) {
                card = response.body()
                callback.processFinish(true, card!!.cardAvailableBalance)
            } else {
                callback.processFinish(false, null)
                val error: ApiError = ErrorUtils.parseError(response)
                val message = when {
                    error.error.code.isNotEmpty() -> error.error.code + error.error.message
                    else -> error.code + error.message
                }
                trackEvent(API_READ_CARD_BALANCE_ERROR, ERROR to message)
                promptErrorDialog(error)
            }
        } catch (e: HttpException) {
            callback.processFinish(false, null)
            trackEvent(API_READ_CARD_BALANCE_ERROR, ERROR to e.message!!)
            context!!.toast(e.message.toString())
        } catch (e: Throwable) {
            callback.processFinish(false, null)
            trackEvent(API_READ_CARD_BALANCE_ERROR, ERROR to e.message!!)
            context!!.toast( e.message.toString())
        }
    }
   ....
   ....

}


class FragmentClass : BaseFragment(){

    private var funcService = FunctionA(null, null ,null)

    ....

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        (activity!!.application as App).component.inject(this)

        val valA = 10.5f
        val valB = "Test"
        val cardNo = "4001526976443264"
        val cardExpDate = "1119"

        funcService = FunctionA(context!!, valA ,valB)
        getCardBalanceApi(cardNo, cardExpDate)

    }

    .... 

    private fun getCardBalanceApi(cardNo: String, cardExpDate: String?) {
        showLoadingDialog()
        funcService.getCardBalance(cardNo, object : SmartPayService.CardBalanceCallback {
            override fun processFinish(output: Boolean, cardBalance: Float?) {
                dismissLoadingDialog()
                if (cardBalance != null) {
                    checkBalance(cardNo, cardBalance, cardExpDate)
                }
            }
        })
    }

    ....

}

在返回
cardBalance
值之前,我应该如何等待协同程序完成?

getBalance()
设置为挂起函数,然后在片段中使用
lifecycleScope
调用

private fun gooToo(){
   lifecycleScope.launch {
       val B = pass.getBalance(point)
       print("TEST")
       println("value B: " + B)
   }
}
getBalance()
函数签名类似于

suspend fun getBalance(): Float = withContext(Dispatchers.IO)
getBalance()
设为挂起函数,然后在片段中使用
lifecycleScope
调用

private fun gooToo(){
   lifecycleScope.launch {
       val B = pass.getBalance(point)
       print("TEST")
       println("value B: " + B)
   }
}
getBalance()
函数签名类似于

suspend fun getBalance(): Float = withContext(Dispatchers.IO)

从协同程序返回单个值的正确方法是使用
await()

现在,由于您使用协程来包装一些回调API,所以这不会很好地工作。因此,我建议采取以下措施:

val scope = CoroutineScope(Dispatchers.IO)

suspend fun getBalance(cardNo: String): Float{
    val res = CompletableDeferred<Float>()

    scope.launch {
        val cardDetails = cardApi.getCardBalance(cardNo)
        cardDetails.enqueue(object : Callback<Card> {
            override fun onFailure(call: Call<Card>, t: Throwable) {
                trackEvent(API_READ_CARD_BALANCE_ERROR, ERROR to t.message!!)
            }

            override fun onResponse(call: Call<Card>, response: Response<Card>) {
                if (response.isSuccessful) {
                    val card = response.body()!!
                    res.complete(card.cardAvailableBalance)

                } else {
                    val error: ApiError = ErrorUtils.parseError(response)
                    val message = error.code + error.message
                    trackEvent(API_READ_CARD_BALANCE_ERROR, ERROR to message)
                    res.completeExceptionally(message)

                    withContext(Dispatchers.Main) {
                        promptErrorDialog(error)    
                    }
                }
            }
        })
    }

    return res.await()
}
val scope=CoroutineScope(Dispatchers.IO)
暂停趣味getBalance(卡号:字符串):浮动{
val res=CompletableDeferred()
范围.发射{
val cardDetails=cardApi.getCardBalance(卡号)
排队(对象:回调){
覆盖失效时的乐趣(调用:调用,t:可丢弃){
trackEvent(API\u读取\u卡\u余额\u错误,错误到t.message!!)
}
覆盖fun onResponse(调用:调用,响应:响应){
if(response.issucessful){
val卡=响应。主体()!!
res.complete(卡片可用平衡)
}否则{
val error:APIRROR=ErrorUtils.parseError(响应)
val消息=error.code+error.message
trackEvent(API\读取\卡\余额\错误,消息错误)
res.CompleteExceptionly(消息)
withContext(Dispatchers.Main){
提示器对话框(错误)
}
}
}
})
}
return res.await()
}
有几点需要考虑。首先,我使用了
Dispatchers.IO
而不是
Dispatchers.Main
,只有在需要时才使用
withContext(Dispatchers.Main)
切换到
Main
线程。否则,您只是在主线程上运行IO,不管是否协同路由

其次,使用
GlobalScope
是一种不好的做法,你应该不惜一切代价避免它。相反,我创建了一个自定义作用域,您可以
.cancel()
来防止协同路由泄漏


第三,最正确的方法是返回
Deferred
,而不是
Float
,因为
await()
是阻塞的。但是为了简单起见,我留下了它。

从协同程序返回单个值的正确方法是使用
await()

现在,由于您使用协程来包装一些回调API,所以这不会很好地工作。因此,我建议采取以下措施:

val scope = CoroutineScope(Dispatchers.IO)

suspend fun getBalance(cardNo: String): Float{
    val res = CompletableDeferred<Float>()

    scope.launch {
        val cardDetails = cardApi.getCardBalance(cardNo)
        cardDetails.enqueue(object : Callback<Card> {
            override fun onFailure(call: Call<Card>, t: Throwable) {
                trackEvent(API_READ_CARD_BALANCE_ERROR, ERROR to t.message!!)
            }

            override fun onResponse(call: Call<Card>, response: Response<Card>) {
                if (response.isSuccessful) {
                    val card = response.body()!!
                    res.complete(card.cardAvailableBalance)

                } else {
                    val error: ApiError = ErrorUtils.parseError(response)
                    val message = error.code + error.message
                    trackEvent(API_READ_CARD_BALANCE_ERROR, ERROR to message)
                    res.completeExceptionally(message)

                    withContext(Dispatchers.Main) {
                        promptErrorDialog(error)    
                    }
                }
            }
        })
    }

    return res.await()
}
val scope=CoroutineScope(Dispatchers.IO)
暂停趣味getBalance(卡号:字符串):浮动{
val res=CompletableDeferred()
范围.发射{
val cardDetails=cardApi.getCardBalance(卡号)
排队(对象:回调){
覆盖失效时的乐趣(调用:调用,t:可丢弃){
trackEvent(API\u读取\u卡\u余额\u错误,错误到t.message!!)
}
覆盖fun onResponse(调用:调用,响应:响应){
if(response.issucessful){
val卡=响应。主体()!!
res.complete(卡片可用平衡)
}否则{
val error:APIRROR=ErrorUtils.parseError(响应)
val消息=error.code+error.message
trackEvent(API\读取\卡\余额\错误,消息错误)
res.CompleteExceptionly(消息)
withContext(Dispatchers.Main){
提示器对话框(错误)
}
}
}
})
}
return res.await()
}
有几点需要考虑。首先,我使用了
Dispatchers.IO
而不是
Dispatchers.Main
,只有在需要时才使用
withContext(Dispatchers.Main)
切换到
Main
线程。否则,您只是在主线程上运行IO,不管是否协同路由

其次,使用
GlobalScope
是一种不好的做法,你应该不惜一切代价避免它。相反,我创建了一个自定义作用域,您可以
.cancel()
来防止协同路由泄漏


第三,最正确的方法是返回
Deferred
,而不是
Float
,因为
await()
是阻塞的。但是为了简单起见,我留下了它。

为了解决我的小问题,我最终使用回调来传递响应数据。我发现,就我的理解水平而言,这种方法非常有效,也更容易理解。这个方法框架还可以用于我将来要使用的任何api服务调用

functional.kt


class FunctionA(val context: Context?, val A: Float?, val B: String?){

   private var cardApi: CardApi = ApiClient.createApi().create(CardApi::class.java)

   ....

   func getBalance(cardNo: String): Float?{
       val cardBalance: Float = null

       GlobalScope.launch(Dispatchers.Main) {
            val cardDetails = cardApi.getCardBalance(cardNo)
            cardDetails.enqueue(object : Callback<Card> {
                override fun onFailure(call: Call<Card>, t: Throwable) {
                    trackEvent(API_READ_CARD_BALANCE_ERROR, ERROR to t.message!!)
                }

                override fun onResponse(call: Call<Card>, response: Response<Card>) {
                    if (response.isSuccessful) {
                        val card = response.body()!!
                        cardBalance = card.cardAvailableBalance

                    } else {
                        val error: ApiError = ErrorUtils.parseError(response)
                        val message = error.code + error.message
                        trackEvent(API_READ_CARD_BALANCE_ERROR, ERROR to message)
                        context!!.toast("Errror: " + message)

                        promptErrorDialog(error)
                    }
                }
            })
        }}

        return cardBalance
   }
   ....
   ....

}


class FragmentClass : BaseFragment(){

    val galA = 10.5f
    val galB = "Test"
    private var pass = FunctionA(context!!, valA ,valB)

    ....

    val point = "sasd12125"
    private fun gooToo(){
        val B = pass.getBalance(point)
        print("TEST")
        println("value B: " + B)
    }
    ....

}


TEST
value B: null


class FunctionA(val context: Context?, val A: Float?, val B: String?){

   private var cardApi: CardApi = ApiClient.createApi().create(CardApi::class.java)
   private var card: Card? = null

   interface CardBalanceCallback {
       fun processFinish(output: Boolean, cardBalance: Float?)
   }

   fun getCardBalance(cardNo: String, callback: CardBalanceCallback) = runBlocking {
       getBalance(cardNo, callback)
   }

   private fun getBalance(cardNo: String, callback: CardBalanceCallback) = CoroutineScope(Dispatchers.Main).launch {
        try {
            val response = cardApi.getCardBalance(cardNo).await()
            if (response.isSuccessful) {
                card = response.body()
                callback.processFinish(true, card!!.cardAvailableBalance)
            } else {
                callback.processFinish(false, null)
                val error: ApiError = ErrorUtils.parseError(response)
                val message = when {
                    error.error.code.isNotEmpty() -> error.error.code + error.error.message
                    else -> error.code + error.message
                }
                trackEvent(API_READ_CARD_BALANCE_ERROR, ERROR to message)
                promptErrorDialog(error)
            }
        } catch (e: HttpException) {
            callback.processFinish(false, null)
            trackEvent(API_READ_CARD_BALANCE_ERROR, ERROR to e.message!!)
            context!!.toast(e.message.toString())
        } catch (e: Throwable) {
            callback.processFinish(false, null)
            trackEvent(API_READ_CARD_BALANCE_ERROR, ERROR to e.message!!)
            context!!.toast( e.message.toString())
        }
    }
   ....
   ....

}


class FragmentClass : BaseFragment(){

    private var funcService = FunctionA(null, null ,null)

    ....

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        (activity!!.application as App).component.inject(this)

        val valA = 10.5f
        val valB = "Test"
        val cardNo = "4001526976443264"
        val cardExpDate = "1119"

        funcService = FunctionA(context!!, valA ,valB)
        getCardBalanceApi(cardNo, cardExpDate)

    }

    .... 

    private fun getCardBalanceApi(cardNo: String, cardExpDate: String?) {
        showLoadingDialog()
        funcService.getCardBalance(cardNo, object : SmartPayService.CardBalanceCallback {
            override fun processFinish(output: Boolean, cardBalance: Float?) {
                dismissLoadingDialog()
                if (cardBalance != null) {
                    checkBalance(cardNo, cardBalance, cardExpDate)
                }
            }
        })
    }

    ....

}

FragmentClass.kt


class FunctionA(val context: Context?, val A: Float?, val B: String?){

   private var cardApi: CardApi = ApiClient.createApi().create(CardApi::class.java)

   ....

   func getBalance(cardNo: String): Float?{
       val cardBalance: Float = null

       GlobalScope.launch(Dispatchers.Main) {
            val cardDetails = cardApi.getCardBalance(cardNo)
            cardDetails.enqueue(object : Callback<Card> {
                override fun onFailure(call: Call<Card>, t: Throwable) {
                    trackEvent(API_READ_CARD_BALANCE_ERROR, ERROR to t.message!!)
                }

                override fun onResponse(call: Call<Card>, response: Response<Card>) {
                    if (response.isSuccessful) {
                        val card = response.body()!!
                        cardBalance = card.cardAvailableBalance

                    } else {
                        val error: ApiError = ErrorUtils.parseError(response)
                        val message = error.code + error.message
                        trackEvent(API_READ_CARD_BALANCE_ERROR, ERROR to message)
                        context!!.toast("Errror: " + message)

                        promptErrorDialog(error)
                    }
                }
            })
        }}

        return cardBalance
   }
   ....
   ....

}


class FragmentClass : BaseFragment(){

    val galA = 10.5f
    val galB = "Test"
    private var pass = FunctionA(context!!, valA ,valB)

    ....

    val point = "sasd12125"
    private fun gooToo(){
        val B = pass.getBalance(point)
        print("TEST")
        println("value B: " + B)
    }
    ....

}


TEST
value B: null


class FunctionA(val context: Context?, val A: Float?, val B: String?){

   private var cardApi: CardApi = ApiClient.createApi().create(CardApi::class.java)
   private var card: Card? = null

   interface CardBalanceCallback {
       fun processFinish(output: Boolean, cardBalance: Float?)
   }

   fun getCardBalance(cardNo: String, callback: CardBalanceCallback) = runBlocking {
       getBalance(cardNo, callback)
   }

   private fun getBalance(cardNo: String, callback: CardBalanceCallback) = CoroutineScope(Dispatchers.Main).launch {
        try {
            val response = cardApi.getCardBalance(cardNo).await()
            if (response.isSuccessful) {
                card = response.body()
                callback.processFinish(true, card!!.cardAvailableBalance)
            } else {
                callback.processFinish(false, null)
                val error: ApiError = ErrorUtils.parseError(response)
                val message = when {
                    error.error.code.isNotEmpty() -> error.error.code + error.error.message
                    else -> error.code + error.message
                }
                trackEvent(API_READ_CARD_BALANCE_ERROR, ERROR to message)
                promptErrorDialog(error)
            }
        } catch (e: HttpException) {
            callback.processFinish(false, null)
            trackEvent(API_READ_CARD_BALANCE_ERROR, ERROR to e.message!!)
            context!!.toast(e.message.toString())
        } catch (e: Throwable) {
            callback.processFinish(false, null)
            trackEvent(API_READ_CARD_BALANCE_ERROR, ERROR to e.message!!)
            context!!.toast( e.message.toString())
        }
    }
   ....
   ....

}


class FragmentClass : BaseFragment(){

    private var funcService = FunctionA(null, null ,null)

    ....

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        (activity!!.application as App).component.inject(this)

        val valA = 10.5f
        val valB = "Test"
        val cardNo = "4001526976443264"
        val cardExpDate = "1119"

        funcService = FunctionA(context!!, valA ,valB)
        getCardBalanceApi(cardNo, cardExpDate)

    }

    .... 

    private fun getCardBalanceApi(cardNo: String, cardExpDate: String?) {
        showLoadingDialog()
        funcService.getCardBalance(cardNo, object : SmartPayService.CardBalanceCallback {
            override fun processFinish(output: Boolean, cardBalance: Float?) {
                dismissLoadingDialog()
                if (cardBalance != null) {
                    checkBalance(cardNo, cardBalance, cardExpDate)
                }
            }
        })
    }

    ....

}


这是我在第一篇文章中针对这个特殊问题所做的一些简单更改。这种方法可能没有我正在学习的那么好或者足够流畅。希望它能帮助你们中的一些人。干杯

为了解决我的小问题,我最终使用回调传递响应数据。我发现