当前位置: 首页 > news >正文

网络请求回调的实现方式

网络请求回调的实现方式

  • 一个应用程序可能会在许多个地方用到网络功能,而发送HTTP请求的代码基本上是相同的,如果我们每一次都去编写一遍HTTP请求的代码,这显然是不太合理的做法.
  • 通常情况下我们应该将这些通用的网络操作提取到一个公共的类当中,并且提供一个通用的方法,当想要发起网络请求的时候,只需要简单调用一下这个方法即可.
  • 比如我们可以使用如下写法
    object HttpUtil {
        private fun sendRequest(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()
            } finally {
                connection?.disconnect()
            }
        }
    }
  • 以后当想要发起一条HTTP请求的时候,就可以这样写了
val address = "https://www.baidu.com"
val response = HttpUtil.sendRequest(address)
  • 在获取到服务器响应的数据之后,我们就可以对他进行解析和处理了.
  • 但是需要注意的是,网络请求通常都是耗时的,而sendRequest()方法当中并没有开启线程,这就可能会造成主线程被堵塞
  • 但是如果单纯的在sendRequest()方法中开一个线程,服务器响应的数据是无法进行返回的,因为所有耗时的逻辑都是在子线程中进行的,sendRequest()方法会在服务器还没有来得及反应的时候就执行结束了,当然也就无法返回响应的数据了.
  • 对于这种情况只需要使用编程语言的回调机制就可以了
  • 首先需要定义一个接口,比如将他命名成为HttpCallbackListener,代码如下所示
interface HttpCallbackListener {
    fun onFinish(response: String)
    fun onError(e: Exception)
}
  • 可以看到在接口当中定义了两个方法,onFinish()和onError()
  • onFinish()方法表示服务器成功响应我们请求的时候进行调用
  • onError()方法表示当进行网络操作出现错误的时候进行调用
  • 这两个方法都有参数,onFinish()方法中的参数代表服务器返回的数据,而onError()方法中的参数记录着错误的详细信息
  • 接着修改HttpUtil当中的代码,如下所示
  object HttpUtil {
        private fun sendRequest(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()
              }
          }   
        }
    }
  • 首先给sendRequest()方法中添加了一个HttpCallbackListener类型的参数,并在方法的内部开启了一个子线程,然后在子线程中执行具体的网络操作.
  • 现在sendRequest()方法中接收了两个参数,因此我们在调用它的时候,还需要将HttpCallbackListener的实例传入,如下所示
HttpUtil.sendRequest(address, object : HttpCallbackListener{
    override fun onFinish(response: String) {
        //得到服务器所需要的内容
    }
    
    override fun onError(e: Exception) {
        //在这里对异常情况进行处理
    }
})
  • 这样当服务器成功响应的时候,我们就可以在onFinish()方法里面对数据进行处理了,类似的,如果出现异常,就可以在onError()方法里对异常情况进行处理,如此一来,就巧妙的利用回调机制将响应的数据成功返回给调用方了.
  • 上述是使用了HttpURLConnection的写法,还是比较复杂的,如果使用OkHttp其实就会变得简单一些
  • 在HttpUtil当中加入一个sendOkHttpRequest()方法,如下所示
object HttpUtil {
    fun sendOkHttpRequest(address: String, callback: okhttp3.Callback) {
        val client = OkHttpClient()
        val request = Request.Builder()
        	.url(address)
        	.build()
        client.newCall(request).enqueue(callback)
    }
}
  • 可以看到sendOkHttpRequest()方法中有一个okhttp3.Callback参数,这个是OkHttp库中自带的回调接口,类似于我们刚才自己编写的HttpCallbackListener,然后在client.newCall()之后没有像之前那样一直调用execute()方法,而是调用了一个enqueue()方法,并把okhttp3.Callback参数进行传入
  • OkHttp在enqueue()方法的内部已经帮我们开好了线程,然后会在子线程中执行HTTP请求,并将最终的请求结果回调到okhttp3.Callback当中
  • 那么我们在调用sendOkHttpRequest()方法的时候就可以这样写:
HttpUtil.sendOkHttpRequest(address: String, object : Callback {
    override fun onRequese(call: Call, response: Response) {
        //得到服务器返回的具体内容
        val responseData = response.body?.string()
    }
    override fun onFailure(call: Call, e: Exception) {
        //在这里进行异常情况处理
    }
})
  • 需要注意的是无论是HttpURLConnection还是OkHttp,最终回调的接口都还是在子线程当中运行的,因此我们不可以在这里执行任何UI操作,除非借助runOnUiThread()方法来进行线程更替.

相关文章:

  • STM32 使用IQmath实现SVPWM 正弦波无刷电机控制
  • Openstack的安装部署教程
  • 密码学_AES加密算法
  • 个人博客系统(前后端分离)
  • Linux常用基本指令详解
  • Linux c编程之静态库与动态库
  • 【消息中间件】RocketMQ如何实现Producer的负载均衡
  • 阳了在家没事干?教大家用python在家做一个万能看视频软件,绝对正经啦~
  • Footprint Analytics 如何帮助区块链研究人员进行数据研究
  • 代码质量管理平台实战| SonarQube 安装、配置及 JaCoCo、Maven 集成
  • 黑马Hive+Spark离线数仓工业项目--数仓事实层DWB层构建(2)
  • VIAVI唯亚威光纤高分辨率多模 OTDR 测试方案
  • rust program英文和汉语混合笔记(4)
  • Attention:何为注意力机制?
  • 高级网络复习——防火墙,OSPF协议,rip协议,三层,DHCP中继知识题解(带答案)
  • ----------
  • 【140天】尚学堂高淇Java300集视频精华笔记(86-87)
  • android 一些 utils
  • egg(89)--egg之redis的发布和订阅
  • gulp 教程
  • java2019面试题北京
  • Linux编程学习笔记 | Linux多线程学习[2] - 线程的同步
  • python docx文档转html页面
  • spark本地环境的搭建到运行第一个spark程序
  • Spring-boot 启动时碰到的错误
  • Vim 折腾记
  • 翻译--Thinking in React
  • 官方解决所有 npm 全局安装权限问题
  • 基于Volley网络库实现加载多种网络图片(包括GIF动态图片、圆形图片、普通图片)...
  • 技术攻略】php设计模式(一):简介及创建型模式
  • 猫头鹰的深夜翻译:Java 2D Graphics, 简单的仿射变换
  • 面试遇到的一些题
  • 提醒我喝水chrome插件开发指南
  • 我从编程教室毕业
  • 一天一个设计模式之JS实现——适配器模式
  • 用Node EJS写一个爬虫脚本每天定时给心爱的她发一封暖心邮件
  • Nginx惊现漏洞 百万网站面临“拖库”风险
  • Redis4.x新特性 -- 萌萌的MEMORY DOCTOR
  • 阿里云API、SDK和CLI应用实践方案
  • 数据库巡检项
  • ​ ​Redis(五)主从复制:主从模式介绍、配置、拓扑(一主一从结构、一主多从结构、树形主从结构)、原理(复制过程、​​​​​​​数据同步psync)、总结
  • ​云纳万物 · 数皆有言|2021 七牛云战略发布会启幕,邀您赴约
  • (C++17) std算法之执行策略 execution
  • (day 2)JavaScript学习笔记(基础之变量、常量和注释)
  • (四)JPA - JQPL 实现增删改查
  • (一)ClickHouse 中的 `MaterializedMySQL` 数据库引擎的使用方法、设置、特性和限制。
  • (一)Java算法:二分查找
  • .naturalWidth 和naturalHeight属性,
  • .Net 代码性能 - (1)
  • .NET/C# 使窗口永不获得焦点
  • .Net6 Api Swagger配置
  • .net6Api后台+uniapp导出Excel
  • .net8.0与halcon编程环境构建
  • .net获取当前url各种属性(文件名、参数、域名 等)的方法
  • /usr/lib/mysql/plugin权限_给数据库增加密码策略遇到的权限问题