学习Android之网络请求会回调
网络请求回调的实现方式
虽然掌握了HttpURLConnection和OkHttp的用法,但是发送HTTP请求的代码基本是相同的,所以我们需要将这些通用的网络操作提取到一个公共的类里,并提供一个通用方法:
HttpURLConnection的写法
object HttpUtil { fun sendHttpRequest(address: String): String { var connection: HttpURLConnection? = null try { val response = StringBuilder() val url = URL(address) connection = url.openConnection() as HttpURLConnection connection.connectTimeout = 8000 connection.readTimeout = 8000 val input = connection.inputStream val reader = BufferedReader(InputStreamReader(input)) reader.use { reader.forEachLine { response.append(it) } } return response.toString() } catch (e: Exception) { e.printStackTrace() return e.message.toString() } } }
以后每当需要发起一条HTTP请求,就这样写:
val address = "https://www.baidu.com"
val response = HttpUtil.sendHttpRequest(address)
在获取服务器相应数据后,就可以进行解析和处理了。
注意:网络请求属于耗时操作,而sendHttpRequest()方法中并没有开启线程,如果我们在其内部开启线程,那么服务器相应的数据是无法进行返回的。为什么呢?
因为所有的耗时逻辑都是在子线程里进行的,sendHttpRequest()方法会在服务器还没来得及相应的时候就执行结束了,所以就无法返回响应的数据了。
这个时候我们就需要使用回调机制了,首先定义一个接口:
interface HttpCallbackListener { fun onFinish(response: String) fun onError(e: Exception) }
接口中有两个方法:onFinish()方法表示当服务器成功响应我们请求的时候调用,onError()表示当进行网络操作出现错误的时候调用。
接着修改HttpUtil中的代码:
object HttpUtil { fun sendHttpRequest(address: String, listener: HttpCallbackListener){ thread { var connection: HttpURLConnection? = null try { val response = StringBuilder() val url = URL(address) connection = url.openConnection() as HttpURLConnection connection.connectTimeout = 8000 connection.readTimeout = 8000 val input = connection.inputStream val reader = BufferedReader(InputStreamReader(input)) reader.use { reader.forEachLine { response.append(it) } } // 回调onFinish()方法 listener.onFinish(response.toString()) } catch (e: Exception) { e.printStackTrace() // 回调onError()方法 listener.onError(e) } finally { connection?.disconnect() } } } }
首先给sendHttpRequest()方法添加了一个HttpCallbackListener参数,并在内部开启一个子线程,然后在子线程里执行具体的网络操作。
注意:子线程是无法通过return语句返回数据的,因此这里将服务器响应的数据传入了HttpCallbackListener的onFinish()方法中,如果出现了异常,就将异常原因传入onError()方法中。
现在sendHttpRequest()方法接收两个参数,所以在调用的时候需要将HttpCallbackListener的实例传入:
HttpUtil.sendHttpRequest(address, object : HttpCallbackListener { override fun onFinish(response: String) { // 得到服务器返回的具体内容 } override fun onError(e: java.lang.Exception) { // 在这里对异常情况进行处理 } })
如此一来,我们就巧妙地利用回调机制将响应数据成功返回给调用方了。
OkHttp的写法
但是上述使用HttpURLConnection的写法还是比较复杂的,现在换成OkHttp:
object HttpUtil { fun sendOkHttpRequest(address: String, callback: okhttp3.Callback) { val client = OkHttpClient() val request = Request.Builder() .url(address) .build() client.newCall(request).enqueue(callback) } }
此方法中有一个okhttp3.Callback参数,这是OkHttp库中自带的回调接口,类似于我们刚才编写的HttpCallbackListener。在client.newCall()之后没有调用execute()方法,而是调用了enqueue()方法,并把okhttp3.Callback参数传入。因为OkHttp在enqueue()方法的内部已经开好了子线程,然后会在子线程中执行HTTP请求,并将最终的请求结果回调到okhttp3.Callback中。
那么调用sendOkHttpRequest()方法就可以这样写:
HttpUtil.sendOkHttpRequest(address, object : Callback { override fun onFailure(call: Call, e: IOException) { // 得到服务器返回的具体内容 } override fun onResponse(call: Call, response: Response) { // 对异常进行处理 } })
注意:不管是使用HttpURLConnection还是OkHttp,最终的回调接口都还是在子线程中运行的,因此我们不可以在这里执行任何的UI操作,除非借助runOnUiThread()方法来进行线程转换。

浙公网安备 33010602011771号