[Android]网络框架之OkHttp(详细)(kotlin)

简介: [Android]网络框架之OkHttp(详细)(kotlin)

OkHttp的介绍


https://square.github.io/okhttp/

由Square公司贡献的一个处理网络请求的开源项目,是目前Android使用最广泛的网络框架。从Android4.0开始HttpURLConnection的底层实现采用的是OkHttp

添加依赖


implementation 'com.squareup.okhttp3:okhttp:4.9.0'

上述依赖会自动下载okhttp库和okio库

OkHttp的使用

记得添加权限!

<uses-permission android:name="android.permission.INTERNET" />

get的同步与异步请求


get请求的基本步骤:

1.创建OkHttpClient的实例

2.创建Request对象,设置url地址

3.创建Call对象,调用它的execute方法(同步)或者enqueue方法(异步)来发送请求并获取服务器返回的数据

4.得到服务器返回的数据的具体内容

get同步请求

//get同步请求
    fun getSync() {
        thread {
            try {
                val client = OkHttpClient()
                val request = Request.Builder()
                    .url("https://www.httpbin.org/get?a=1&b=2")
                    .build()
                val call=client.newCall(request)
                val response = call.execute()//execute方法会阻塞在这里,必须等到服务器响应,得到response才会执行下面的代码
                val requestData = response.body?.string()
                if (requestData != null) {
                    Log.e("getSync", requestData)
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

get异步请求

//get异步请求
    fun getAsync(){
        val client = OkHttpClient()
        val request = Request.Builder()
            .url("https://www.httpbin.org/get?a=1&b=2")
            .build()
        val call=client.newCall(request)
        //异步请求,enqueue方法不会阻塞后续代码的执行
        call.enqueue(object :Callback{
            //请求失败调用
            override fun onFailure(call: Call, e: IOException) {
            }
            //请求结束调用(意味着与服务器的通信成功)
            override fun onResponse(call: Call, response: Response) {
                if(response.isSuccessful){
                    response.body?.let { Log.e("getAsync", it.string()) }
                }
            }
        })
    }

响应码在200到299之间就是成功的。

post的同步与异步请求


post请求的基本步骤:

1.创建OkHttpClient的实例

2.创建RequestBody对象来存放待提交的参数

2.创建Request对象,设置url地址,调用post方法,把RequestBody对象传入

3.创建Call对象,调用它的execute方法(同步)或者enqueue方法(异步)来发送请求并获取服务器返回的数据

4.得到服务器返回的数据的具体内容

post同步请求提交键值对

//post同步请求
    fun postSync(){
        thread {
            try {
                val client = OkHttpClient()
                val requestBody=FormBody.Builder().add("a","1").add("b","2").build()
                val request = Request.Builder()
                    .url("https://www.httpbin.org/post")
                    .post(requestBody)
                    .build()
                val call=client.newCall(request)
                val response = call.execute()//execute方法会阻塞在这里,必须等到服务器响应,得到response才会执行下面的代码
                val requestData = response.body?.string()
                if (requestData != null) {
                    Log.e("postSync", requestData)
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

post异步请求提交键值对

//post异步请求
    fun postAsync(){
        val client = OkHttpClient()
        val requestBody=FormBody.Builder().add("a","1").add("b","2").build()
        val request = Request.Builder()
            .url("https://www.httpbin.org/post")
            .post(requestBody)
            .build()
        val call=client.newCall(request)
        //异步请求,enqueue方法不会阻塞后续代码的执行
        call.enqueue(object :Callback{
            //请求失败调用
            override fun onFailure(call: Call, e: IOException) {
            }
            //请求结束调用(意味着与服务器的通信成功,)
            override fun onResponse(call: Call, response: Response) {
                if(response.isSuccessful){
                    response.body?.let { Log.e("postAsync", it.string()) }
                }
            }
        })
    }

POST请求的数据格式


协议规定POST提交的数据必须放在请求体中,但协议并没有规定数据必须使用什么编码方式。而常用的数据编码方式有:

  • application/x-www-form-urlencoded:默认, key1=value1&key2=value2
  • multipart/form-data:一般用于表单需要文件上传
  • .application/json:提交json数据
  • text/plain:将文件设置为纯文本的形式
  • application/octet-stream:提交二进制数据,如果用于文件上传,只能上传一个文件

注意:

String、ByteArray、ByteString转RequestBody都用toRequestBody()

而File转RequestBody用asRequestBody()

POST请求上传文件


fun Filetest(){
        thread {
            try {
                val client = OkHttpClient()
                //创建文件
                val file1=File(externalCacheDir,"jfApp")
                if (!file1.exists()){
                    file1.createNewFile();
                }
                //在file1中写入aaa
                file1.printWriter().use { out->
                    out.println("aaa")
                }
                //把file转化为RequestBody
                val fileBody1=file1.asRequestBody("text/plain".toMediaType())
                val request = Request.Builder()
                    .url("https://www.httpbin.org/post")
                    .post(fileBody1)
                    .build()
                val call=client.newCall(request)
                val response = call.execute()
                val requestData = response.body?.string()
                if (requestData != null) {
                    Log.e("file", requestData)
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

POST请求上传json对象


fun jsontest(){
        thread {
            try {
                val client = OkHttpClient()
                val json:String="{\"a\":1,\"b\":2}"
                val requestBody=json.toRequestBody("application/json".toMediaType())
                val request = Request.Builder()
                    .url("https://www.httpbin.org/post")
                    .post(requestBody)
                    .build()
                val call=client.newCall(request)
                val response = call.execute()
                val requestData = response.body?.string()
                if (requestData != null) {
                    Log.e("jsontext", requestData)
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

POST请求上传多个数据


fun Filetest(){
        thread {
            try {
                val client = OkHttpClient()
                //创建文件
                val file1=File(externalCacheDir,"jfApp")
                val file2=File(externalCacheDir,"jfApp2")
                if (!file1.exists()){
                    file1.createNewFile();
                }
                if (!file2.exists()){
                    file2.createNewFile();
                }
                //在file1中写入aaa
                file1.printWriter().use { out->
                    out.println("aaa")
                }
                //把file转化为RequestBody
                val fileBody1=file1.asRequestBody("text/plain".toMediaType())
                val fileBody2=file2.asRequestBody("text/plain".toMediaType())
                //把数据放入multipartBody中
                val multipartBody = MultipartBody.Builder()
                    .addFormDataPart("file1", file1.name,fileBody1)//添加文件
                    .addFormDataPart("file2",file2.name,fileBody2)
                     .addFormDataPart("a","1")//添加键值对
                    .build()
                val request = Request.Builder()
                    .url("https://www.httpbin.org/post")
                    .post(multipartBody)
                    .build()
                val call=client.newCall(request)
                val response = call.execute()
                val requestData = response.body?.string()
                if (requestData != null) {
                    Log.e("file", requestData)
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

OkHttp的配置

1.Builder构建器


val okHttpClient:OkHttpClient=OkHttpClient.Builder().build()

可以加入一些自己配置的小配件

2.自定义拦截器


okhttp的拦截器就是在intercept(chain: Interceptor.Chain)的回调中对Request和Response进行修改,然后通过chain.proceed(request)调起下一个拦截器。

val okHttpClient:OkHttpClient=OkHttpClient.Builder().addInterceptor(xxx).build()

val okHttpClient:OkHttpClient=OkHttpClient.Builder().addNetworkInterceptor(xxx).build()

addInterceptor()和addNetworkInterceptor()的区别:

1.addInterceptor()的优先级高于addNetworkInterceptor()。

2.在1的条件下,添加拦截器的的顺序就是执行的顺序。

在拦截器中修改Request添加请求头,就可以在每个Request对象中自动添加请求头,减少麻烦。

fun interceptor(){
        thread {
            try {
                val okHttpClient:OkHttpClient=OkHttpClient.Builder()
                    .addInterceptor(object : Interceptor{
                        override fun intercept(chain: Interceptor.Chain): Response {
                            //前置处理
                            val request=chain.request().newBuilder()
                                .addHeader("os","android")
                                .addHeader("version","1.0").build()
                            val response=chain.proceed(request)
                            //后置处理
                            return  response
                        }
                    })
                    .build()
                val request = Request.Builder()
                    .url("https://www.httpbin.org/get?a=1&b=2")
                    .build()
                val call=okHttpClient.newCall(request)
                val response = call.execute()//execute方法会阻塞在这里,必须等到服务器响应,得到response才会执行下面的代码
                val requestData = response.body?.string()
                if (requestData != null) {
                    Log.e("getSync", requestData)
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

3.自定义缓存


OkHttp按照Http协议规则实现了缓存的处理,缓存是比如:当我们发起第一次请求之后,如果后续还需要进行同样的请求,此时如果符合缓存规则,则可以减少与服务器的网络通信,直接从本地文件缓存中读取响应放回给请求者。但是在默认情况下,OkHttp的缓存是关闭状态,需要我们开启。

Cache(缓存文件地址,缓存最大容量字节)

val okHttpClient:OkHttpClient=OkHttpClient.Builder()
        .cache(Cache(File(externalCacheDir,"a"),1024*1024))
         .build()

4. 自定义Cookie


Cookie是某个网站为了辨别用户身份,进行会话跟踪(比如确定登录状态)而存储在用户本地终端上的数据(通常经过加密),由用户客户端计算机暂时或永久保存的信息。

我们在玩Android - wanandroid.com - 每日推荐优质文章

这个网站上注册账号,然后得到账号和密码。这个网站提供很多接口。

请求登录接口之后将返回cookie保存下来,才能请求其他接口,这里请求的是收藏列表。

fun cookietest(){
         val cookies = HashMap<String,List<Cookie>>()
          thread {
              val okHttpClient:OkHttpClient=OkHttpClient.Builder().cookieJar(object :CookieJar{       //加载并保存cookie
                  override fun loadForRequest(url: HttpUrl): List<Cookie> {
                      val cookies: List<Cookie>? = cookies.get(url.host)
                      if(cookies==null)
                          return ArrayList<Cookie>()
                      else {
                          return cookies
                      }
                  }
                  //保存cookie
                  override fun saveFromResponse(url: HttpUrl, list: List<Cookie>) {
                      cookies.put(url.host,list)
                  }
              }).build()
              val fromBody=FormBody.Builder().add("username","xxx")
                  .add("password","xxx").build()//网站的账号和密码
              var request = Request.Builder()
                  .url("https://www.wanandroid.com/user/login")
                  .post(fromBody)
                  .build()
              var call=okHttpClient.newCall(request)
            try {
                val response = call.execute()
                val requestData = response.body?.string()
                if (requestData != null) {
                    Log.e("cookietest", requestData)
                }
            } catch (e: Exception) {
                e.printStackTrace()
            }
              request=Request.Builder().url("https://www.wanandroid.com/lg/collect/list/0/json")
                  .build()
              call=okHttpClient.newCall(request)
              try {
                  val Response=call.execute()
                  Response.body?.let { Log.e("cookietest", it.string()) }
              }catch (e:Exception){
                  e.printStackTrace()
              }
        }
    }

目录
相关文章
|
2月前
|
API 数据处理 Android开发
Android网络请求演变:从Retrofit到Flow的转变过程。
通过这个比喻,我们解释了 Android 网络请求从 Retrofit 到 Flow 的转变过程。这不仅是技术升级的体现,更是反映出开发者在面对并发编程问题时,持续探索和迭求更好地解决方案的精神。未来,还会有更多新的技术和工具出现,我们期待一同 witness 这一切的发展。
100 36
|
3月前
|
前端开发 Java 编译器
当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
128 36
当flutter react native 等混开框架-并且用vscode-idea等编译器无法打包apk,打包安卓不成功怎么办-直接用android studio如何打包安卓apk -重要-优雅草卓伊凡
|
2月前
|
XML JavaScript Android开发
【Android】网络技术知识总结之WebView,HttpURLConnection,OKHttp,XML的pull解析方式
本文总结了Android中几种常用的网络技术,包括WebView、HttpURLConnection、OKHttp和XML的Pull解析方式。每种技术都有其独特的特点和适用场景。理解并熟练运用这些技术,可以帮助开发者构建高效、可靠的网络应用程序。通过示例代码和详细解释,本文为开发者提供了实用的参考和指导。
92 15
|
2月前
|
监控 安全 Cloud Native
企业网络架构安全持续增强框架
企业网络架构安全评估与防护体系构建需采用分层防御、动态适应、主动治理的方法。通过系统化的实施框架,涵盖分层安全架构(核心、基础、边界、终端、治理层)和动态安全能力集成(持续监控、自动化响应、自适应防护)。关键步骤包括系统性风险评估、零信任网络重构、纵深防御技术选型及云原生安全集成。最终形成韧性安全架构,实现从被动防御到主动免疫的转变,确保安全投入与业务创新的平衡。
|
3月前
|
Android开发 开发者 Kotlin
Android实战经验之Kotlin中快速实现MVI架构
MVI架构通过单向数据流和不可变状态,提供了一种清晰、可预测的状态管理方式。在Kotlin中实现MVI架构,不仅提高了代码的可维护性和可测试性,还能更好地应对复杂的UI交互和状态管理。通过本文的介绍,希望开发者能够掌握MVI架构的核心思想,并在实际项目中灵活应用。
103 8
|
4月前
|
编译器 Android开发 开发者
Android经典面试题之Kotlin中Lambda表达式和匿名函数的区别
Lambda表达式和匿名函数都是Kotlin中强大的特性,帮助开发者编写简洁而高效的代码。理解它们的区别和适用场景,有助于选择最合适的方式来解决问题。希望本文的详细讲解和示例能够帮助你在Kotlin开发中更好地运用这些特性。
76 9
|
5月前
|
机器学习/深度学习 算法 PyTorch
基于图神经网络的大语言模型检索增强生成框架研究:面向知识图谱推理的优化与扩展
本文探讨了图神经网络(GNN)与大型语言模型(LLM)结合在知识图谱问答中的应用。研究首先基于G-Retriever构建了探索性模型,然后深入分析了GNN-RAG架构,通过敏感性研究和架构改进,显著提升了模型的推理能力和答案质量。实验结果表明,改进后的模型在多个评估指标上取得了显著提升,特别是在精确率和召回率方面。最后,文章提出了反思机制和教师网络的概念,进一步增强了模型的推理能力。
212 4
基于图神经网络的大语言模型检索增强生成框架研究:面向知识图谱推理的优化与扩展
|
6月前
|
人工智能 自然语言处理
WebDreamer:基于大语言模型模拟网页交互增强网络规划能力的框架
WebDreamer是一个基于大型语言模型(LLMs)的网络智能体框架,通过模拟网页交互来增强网络规划能力。它利用GPT-4o作为世界模型,预测用户行为及其结果,优化决策过程,提高性能和安全性。WebDreamer的核心在于“做梦”概念,即在实际采取行动前,用LLM预测每个可能步骤的结果,并选择最有可能实现目标的行动。
155 1
WebDreamer:基于大语言模型模拟网页交互增强网络规划能力的框架
|
6月前
|
JSON 数据处理 Swift
Swift 中的网络编程,主要介绍了 URLSession 和 Alamofire 两大框架的特点、用法及实际应用
本文深入探讨了 Swift 中的网络编程,主要介绍了 URLSession 和 Alamofire 两大框架的特点、用法及实际应用。URLSession 由苹果提供,支持底层网络控制;Alamofire 则是在 URLSession 基础上增加了更简洁的接口和功能扩展。文章通过具体案例对比了两者的使用方法,帮助开发者根据需求选择合适的网络编程工具。
116 3
|
6月前
|
安全 API 网络安全
使用OkHttp进行HTTPS请求的Kotlin实现
使用OkHttp进行HTTPS请求的Kotlin实现