[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()
              }
        }
    }

目录
相关文章
|
6天前
|
数据采集 存储 JSON
Python网络爬虫:Scrapy框架的实战应用与技巧分享
【10月更文挑战第27天】本文介绍了Python网络爬虫Scrapy框架的实战应用与技巧。首先讲解了如何创建Scrapy项目、定义爬虫、处理JSON响应、设置User-Agent和代理,以及存储爬取的数据。通过具体示例,帮助读者掌握Scrapy的核心功能和使用方法,提升数据采集效率。
41 6
|
14天前
|
机器学习/深度学习 人工智能
类人神经网络再进一步!DeepMind最新50页论文提出AligNet框架:用层次化视觉概念对齐人类
【10月更文挑战第18天】这篇论文提出了一种名为AligNet的框架,旨在通过将人类知识注入神经网络来解决其与人类认知的不匹配问题。AligNet通过训练教师模型模仿人类判断,并将人类化的结构和知识转移至预训练的视觉模型中,从而提高模型在多种任务上的泛化能力和稳健性。实验结果表明,人类对齐的模型在相似性任务和出分布情况下表现更佳。
38 3
|
3天前
|
算法 JavaScript Android开发
|
7天前
|
数据采集 前端开发 中间件
Python网络爬虫:Scrapy框架的实战应用与技巧分享
【10月更文挑战第26天】Python是一种强大的编程语言,在数据抓取和网络爬虫领域应用广泛。Scrapy作为高效灵活的爬虫框架,为开发者提供了强大的工具集。本文通过实战案例,详细解析Scrapy框架的应用与技巧,并附上示例代码。文章介绍了Scrapy的基本概念、创建项目、编写简单爬虫、高级特性和技巧等内容。
28 4
|
7天前
|
网络协议 物联网 API
Python网络编程:Twisted框架的异步IO处理与实战
【10月更文挑战第26天】Python 是一门功能强大且易于学习的编程语言,Twisted 框架以其事件驱动和异步IO处理能力,在网络编程领域独树一帜。本文深入探讨 Twisted 的异步IO机制,并通过实战示例展示其强大功能。示例包括创建简单HTTP服务器,展示如何高效处理大量并发连接。
24 1
|
13天前
|
网络协议 Shell 网络安全
解决两个 Android 模拟器之间无法网络通信的问题
让同一个 PC 上运行的两个 Android 模拟器之间能相互通信,出(qiong)差(ren)的智慧。
19 3
|
13天前
|
Java 程序员 API
Android|集成 slf4j + logback 作为日志框架
做个简单改造,统一 Android APP 和 Java 后端项目打印日志的体验。
45 1
|
14天前
|
存储 前端开发 测试技术
Android kotlin MVVM 架构简单示例入门
Android kotlin MVVM 架构简单示例入门
22 1
|
23天前
|
调度 Android开发 开发者
构建高效Android应用:探究Kotlin多线程优化策略
【10月更文挑战第11天】本文探讨了如何在Kotlin中实现高效的多线程方案,特别是在Android应用开发中。通过介绍Kotlin协程的基础知识、异步数据加载的实际案例,以及合理使用不同调度器的方法,帮助开发者提升应用性能和用户体验。
40 4
|
23天前
|
JSON 调度 数据库
Android面试之5个Kotlin深度面试题:协程、密封类和高阶函数
本文首发于公众号“AntDream”,欢迎微信搜索“AntDream”或扫描文章底部二维码关注,和我一起每天进步一点点。文章详细解析了Kotlin中的协程、扩展函数、高阶函数、密封类及`inline`和`reified`关键字在Android开发中的应用,帮助读者更好地理解和使用这些特性。
17 1