复制 enqueue() 方法
Replicating the enqueue() method
我有以下方法,可以简单地以以太同步或异步方式获取数据:
enum class CallType { SYNC, ASYNC }
suspend fun get( url: String, callType : CallType, mock : String? = null, callback: Callback? ): Response?
{
var response : okhttp3.Response ?= null
val request = Request.Builder()
.url( url )
.build()
val call = client.newCall( request )
if( mock != null )
{
// this works fine for SYNC, but how to make it work with ASYNC callback?
delay( 1000 )
return okhttp3.Response.Builder().body(
ResponseBody.create( "application/json".toMediaType(), mock )
).build()
}
if( callType == CallType.ASYNC && callback != null )
call.enqueue( callback )
else
response = call.execute()
return response
}
我希望能够mock/overwrite回复。当以 SYNC 方式执行时,我可以很好地做到这一点,因为我只需要构造和 return 一个假的 okhttp3.response,就像下面的代码片段一样,代码执行停止,一切都很好:
if( mock != null )
{
delay( 1000 )
return okhttp3.Response.Builder().body(
ResponseBody.create( "application/json".toMediaType(), mock )
).build()
}
问题是我希望能够对 ASYNC 调用执行相同的操作,但我不确定从这里到哪里去。我基本上是在尝试复制 enqueue() 方法,以便在延迟一段时间后触发我的回调(传递给 get() 方法)并且我的假 okhttp3.Response 通过回调 returned ,而不是 return。关于如何实现这一目标的任何建议?谢谢!
一种简单的方法是以同步方式调用回调:
if (mock != null) {
val response = ... // prepare mock response here
callback.onResponse(response)
}
因此,即使在您的 get 函数完成之前,回调也会被调用。
如果你想实现响应实际上是异步传递的,你需要从一个额外的协同程序中执行模拟传递
if (mock != null) {
GlobalScope.launch {
val response = ... // prepare mock response here
delay(1000)
callback.onResponse(response)
}
}
您在实施中混合了不同的概念。异步应该用 CoroutineContext
而不是参数来控制。像这样,您将始终 return 一个非空值。隐藏实现细节(此处 OkHttp)而不公开它也是明智的。
您可以使用 suspendCoroutine
将 OkHttp 与协程桥接。
suspend fun get(
url: String,
mock : String? = null
) = if(mock != null) {
delay( 1000 )
Response.Builder().body(
ResponseBody.create(
"application/json".toMediaType()
mock
)
).build()
} else suspendCoroutine { continuation ->
client.newCall(
Request.Builder()
.url(url)
.build()
).enqueue(
object : Callback {
override fun onFailure(call: Call, e: IOException) =
continuation.resumeWithException(e)
override fun onResponse(call: Call, response: Response) =
continuation.resume(response)
}
)
}
要同步访问它,只需使用
runBlocking { get(url, mock) }
如果您确实需要提供自己的 Callable
,您可以轻松地委托给它。但是您还必须创建一个调用,即使您在模拟响应时不需要它。
我有以下方法,可以简单地以以太同步或异步方式获取数据:
enum class CallType { SYNC, ASYNC }
suspend fun get( url: String, callType : CallType, mock : String? = null, callback: Callback? ): Response?
{
var response : okhttp3.Response ?= null
val request = Request.Builder()
.url( url )
.build()
val call = client.newCall( request )
if( mock != null )
{
// this works fine for SYNC, but how to make it work with ASYNC callback?
delay( 1000 )
return okhttp3.Response.Builder().body(
ResponseBody.create( "application/json".toMediaType(), mock )
).build()
}
if( callType == CallType.ASYNC && callback != null )
call.enqueue( callback )
else
response = call.execute()
return response
}
我希望能够mock/overwrite回复。当以 SYNC 方式执行时,我可以很好地做到这一点,因为我只需要构造和 return 一个假的 okhttp3.response,就像下面的代码片段一样,代码执行停止,一切都很好:
if( mock != null )
{
delay( 1000 )
return okhttp3.Response.Builder().body(
ResponseBody.create( "application/json".toMediaType(), mock )
).build()
}
问题是我希望能够对 ASYNC 调用执行相同的操作,但我不确定从这里到哪里去。我基本上是在尝试复制 enqueue() 方法,以便在延迟一段时间后触发我的回调(传递给 get() 方法)并且我的假 okhttp3.Response 通过回调 returned ,而不是 return。关于如何实现这一目标的任何建议?谢谢!
一种简单的方法是以同步方式调用回调:
if (mock != null) {
val response = ... // prepare mock response here
callback.onResponse(response)
}
因此,即使在您的 get 函数完成之前,回调也会被调用。
如果你想实现响应实际上是异步传递的,你需要从一个额外的协同程序中执行模拟传递
if (mock != null) {
GlobalScope.launch {
val response = ... // prepare mock response here
delay(1000)
callback.onResponse(response)
}
}
您在实施中混合了不同的概念。异步应该用 CoroutineContext
而不是参数来控制。像这样,您将始终 return 一个非空值。隐藏实现细节(此处 OkHttp)而不公开它也是明智的。
您可以使用 suspendCoroutine
将 OkHttp 与协程桥接。
suspend fun get(
url: String,
mock : String? = null
) = if(mock != null) {
delay( 1000 )
Response.Builder().body(
ResponseBody.create(
"application/json".toMediaType()
mock
)
).build()
} else suspendCoroutine { continuation ->
client.newCall(
Request.Builder()
.url(url)
.build()
).enqueue(
object : Callback {
override fun onFailure(call: Call, e: IOException) =
continuation.resumeWithException(e)
override fun onResponse(call: Call, response: Response) =
continuation.resume(response)
}
)
}
要同步访问它,只需使用
runBlocking { get(url, mock) }
如果您确实需要提供自己的 Callable
,您可以轻松地委托给它。但是您还必须创建一个调用,即使您在模拟响应时不需要它。