网络请求-Android篇(Okhttp和Retrofit)
一.OkHttp的介绍和基本用法
OkHttp是一个流行的开源Java和Android应用程序的HTTP客户端。它由Square Inc.开发,提供了一种简单高效的方式来进行应用程序中的HTTP请求。要在Java或Android项目中使用OkHttp,您需要将OkHttp依赖项添加到您的build.gradle文件中。然后,您可以创建一个OkHttpClient实例,并使用它来进行HTTP请求。OkHttp提供了各种类和方法,用于构建和执行请求、处理响应。使用OkHttp的时候,需要引入:implementation 'com.squareup.okhttp3:okhttp:4.10.0',别忘了添加网络权限!
由于在进行网络请求的时候,我们主要用到get和post两种方式,下面就以这两个为例进行代码展示。
1.Get方式:GET请求将参数附加在URL的查询字符串中,即在URL后面使用?符号连接参数键值对。get方式中又可以分为两种情况,分别是同步请求和异步请求;同步请求在进行请求的时候,当前线程会阻塞住,直到得到服务器的响应后,后面的代码才会执行;而异步请求不会阻塞当前线程,它采用了回调的方式,请求是在另一个线程中执行的,不会影响当前的线程。下面给出代码:
public void getSync(){//同步请求
new Thread(new Runnable() {
@Override
public void run() {
OkHttpClient okHttpClient=new OkHttpClient();
Request request=new Request.Builder()
.url("https://www.httpbin.org/get?a=1&b=2")
.build();
//准备好请求的Call对象
Call call = okHttpClient.newCall(request);
try {
Response response = call.execute();
Log.i("getSync",response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
public void getAsync(){//异步请求
OkHttpClient okHttpClient=new OkHttpClient();
Request request=new Request.Builder()
.url("https://www.httpbin.org/get?a=1&b=2")
.build();
//准备好请求的Call对象
Call call = okHttpClient.newCall(request);
//异步请求
call.enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
if(response.isSuccessful()){
Log.i("getAsync",response.body().string());
}
}
});
}
2.Post方式:POST请求将参数放在请求的主体中,不会直接显示在URL中。Post请求也分为同步和异步方式,和get方式用法相同,代码如下:
public void postSync(){//同步请求
new Thread(new Runnable() {
@Override
public void run() {
OkHttpClient okHttpClient=new OkHttpClient();
FormBody formBody=new FormBody.Builder()
.add("a","1")
.add("b","2")
.build();
Request request=new Request.Builder()
.post(formBody)
.url("https://www.httpbin.org/post")
.build();
//准备好请求的Call对象
Call call = okHttpClient.newCall(request);
try {
Response response = call.execute();
Log.i("postSync",response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
public void postAsync(){//异步请求
OkHttpClient okHttpClient=new OkHttpClient();
FormBody formBody=new FormBody.Builder()
.add("a","1")
.add("b","2")
.build();
Request request=new Request.Builder()
.post(formBody)
.url("https://www.httpbin.org/post")
.build();
//准备好请求的Call对象
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
if(response.isSuccessful()){
Log.i("postAsync",response.body().string());
}
}
});
}
上面是通过表单的方式将数据提交给服务器,那如果要上传文件给服务器呢?使用Multipart。
//提交多个文件给服务器
public void postFiles(){
OkHttpClient okHttpClient=new OkHttpClient();
File file1=new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath()+File.separator+"a.jpg");
File file2=new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath()+File.separator+"b.jpg");
RequestBody requestBody1=RequestBody.create(file1, MediaType.parse("application/x-jpg"));
RequestBody requestBody2=RequestBody.create(file2, MediaType.parse("application/x-jpg"));
MultipartBody multipartBody=new MultipartBody.Builder()
.addFormDataPart("a.jpg",file1.getName(),requestBody1)
.addFormDataPart("b.jpg",file2.getName(),requestBody2)
.build();
Request request=new Request.Builder()
.post(multipartBody)
.url("https://www.httpbin.org/post")
.build();
//准备好请求的Call对象
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) { } @Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
if(response.isSuccessful()){
Log.i("postFiles",response.body().string());
}
}
});
}
如果要查看各个文件类型所对应的Content-type字符串,可以访问以下这个网址:https://www.runoob.com/http/http-content-type.html
提交Json字符串给服务器:
//提交json数据
public void postJson(){
OkHttpClient okHttpClient=new OkHttpClient();
RequestBody requestBody=RequestBody.create("{\"a\":1,\"b\":2}",MediaType.parse("application/json"));//记得使用转义字符处理内部的双引号
Request request=new Request.Builder()
.post(requestBody)
.url("https://www.httpbin.org/post")
.build();
//准备好请求的Call对象
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) { } @Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
if(response.isSuccessful()){
Log.i("postJson",response.body().string());
}
}
});
}
3.拦截器的使用:OkHttp的拦截器(Interceptors)提供了强大的自定义和修改HTTP请求和响应的能力。拦截器允许在发送请求前、收到响应后以及其他阶段对HTTP流量进行拦截和处理。例如:拦截器可以修改请求的URL、请求方法、请求头部、请求体等。这对于添加身份验证头、设置缓存控制头等场景很有用。用法如下:
public void interceptor(){
OkHttpClient okHttpClient=new OkHttpClient.Builder()//添加拦截器的使用OkHttpClient的内部类Builder
.addInterceptor(new Interceptor() {//使用拦截器可以对所有的请求进行统一处理,而不必每个request单独去处理
@NonNull
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
//前置处理,以proceed方法为分割线:提交请求前
Request request = chain.request().newBuilder()
.addHeader("id", "first request")
.build();
Response response = chain.proceed(request);
//后置处理:收到响应后
return response;
}
})
.addNetworkInterceptor(new Interceptor() {//这个在Interceptor的后面执行,无论添加顺序如何
@NonNull
@Override
public Response intercept(@NonNull Chain chain) throws IOException {
Log.i("id",chain.request().header("id"));
return chain.proceed(chain.request());
}
})
.cache(new Cache(new File(Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getAbsolutePath()+"/cache"),1024*1024))//添加缓存
.build();
Request request=new Request.Builder()
.url("https://www.httpbin.org/get?a=1&b=2")
.build();
//准备好请求的Call对象
Call call = okHttpClient.newCall(request);
//异步请求
call.enqueue(new Callback() {
@Override
public void onFailure(@NonNull Call call, @NonNull IOException e) {
}
@Override
public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
if(response.isSuccessful()){
Log.i("interceptor",response.body().string());
}
}
});
}
4.Cookie的使用:大家应该有这样的经历,就是有些网站的好多功能都需要用户登录之后才能访问,而这个功能可以用cookie实现,在客户端登录之后,服务器给客户端发送一个cookie,由客户端保存;然后客服端在访问需要登录之后才能访问的功能时,只要携带这个cookie,服务器就可以识别该用户是否登录。用法如下:
public void cookie(){
Map<String,List<Cookie>> cookies=new HashMap<>();
new Thread(new Runnable() {
@Override
public void run() {
OkHttpClient okHttpClient=new OkHttpClient.Builder()
.cookieJar(new CookieJar() {
@Override
public void saveFromResponse(@NonNull HttpUrl httpUrl, @NonNull List<Cookie> list) {//保存服务器发送过来的cookie
cookies.put("cookies",list);
}
@NonNull
@Override
public List<Cookie> loadForRequest(@NonNull HttpUrl httpUrl) {//请求的时候携带cookie
if(httpUrl.equals("www.wanandroid.com")){
return cookies.get("cookies");
}
return new ArrayList<>();
}
})
.build();
FormBody formBody=new FormBody.Builder()
.add("username","ibiubiubiu")
.add("password","Lhh823924.")
.build();
Request request=new Request.Builder() //模拟登录
.url("https://wanandroid.com/user/lg")
.post(formBody)
.build();
//准备好请求的Call对象
Call call = okHttpClient.newCall(request);
try {
Response response = call.execute();
Log.i("login",response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
//请求收藏页面,必须登录之后才能访问到
request=new Request.Builder()
.url("https://wanandroid.com/lg/collect")
.build();
//准备好请求的Call对象
call = okHttpClient.newCall(request);
try {
Response response = call.execute();
Log.i("collect",response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
二.Retrofit的介绍和基本使用
Retrofit是一个基于OkHttp的强大且易于使用的网络请求库,用于在Android和Java应用程序中进行网络通信。它有以下的优点:
1.简化的API: Retrofit提供了一个简洁、直观的API,使得定义和执行网络请求变得非常容易。您可以使用注解来描述请求方法、URL路径、请求参数以及响应类型等信息,从而减少了样板代码的编写。
2.拦截器支持: Retrofit完全兼容OkHttp拦截器,这使得您可以使用OkHttp的拦截器来自定义和修改请求和响应。这为您提供了更大的灵活性和定制能力。
/**
* 服务器域名:https://www.httpbin.org/
* 接口:post,参数username,password
* 接口:get,参数username,password
*/
//第一步,根据http接口创建java接口
public interface HttpbinService {
@GET("get") //这是GET请求的相对路径。它指定了在基本URL之后所附加的路径,以构建完整的请求URL。例如,如果基本URL为https://api.example.com/,那么最终的请求URL将是https://api.example.com/get
Call<ResponseBody> get(@Query("username") String username, @Query("password") String password);//注意get请求用@Query注解标注请求参数
@POST("post")
@FormUrlEncoded
Call<ResponseBody> post(@Field("username") String username,@Field("password") String password);//post请求用@Field注解
@GET
Call<ResponseBody> download(@Url String url);//使用Url注解需要提供完整的资源路径,这时设置的baseUrl就不起作用了
@POST("post")
@Multipart
Call<ResponseBody> upload(@Part MultipartBody.Part file);
}
3.创建Retrofit实例:使用Builder模式创建Retrofit实例,并配置基本的URL以及其他可选的设置,如转换器、拦截器等。
private Retrofit retrofit;
private HttpbinService httpbinService;
retrofit=new Retrofit.Builder()
.baseUrl("https://httpbin.org/")
.build();
httpbinService=retrofit.create(HttpbinService.class);
4.创建API实现:通过Retrofit创建接口的实现,并使用它来执行网络请求。
public void post(){
Call<ResponseBody> call = httpbinService.post("jack", "123456");
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
try {
Log.i("post",response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
}
});
}
public void get(){
new Thread(new Runnable() {
@Override
public void run() {
Call<ResponseBody> call = httpbinService.get("jack", "password");
try {
Response<ResponseBody> response = call.execute();
Log.i("get",response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
}).start();
}
文件的上传和下载:
public void download(){
Call<ResponseBody> call = httpbinService.download("https://nginx.org/download/nginx-1.20.2.tar.gz");
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
if(response.isSuccessful()){
try {
InputStream inputStream = response.body().byteStream();
//context.getExternalFilesDir(null)是一个用于获取本应用程序的外部存储目录的方法,需要注意的是从Android11开始,应用程序不能直接访问SD卡的根目录,Android应用程序只能在应用的私有目录或特定的公共目录中存储文件
FileOutputStream out=new FileOutputStream(context.getExternalFilesDir(null).getAbsolutePath()+"/nginx.tar.gz");
byte[] data=new byte[4096];
int len=0;
while((len=inputStream.read(data))!=-1){
out.write(data,0,len);
}
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
}
});
}
public void upload(){
MultipartBody.Part video = MultipartBody.Part.createFormData("video", "video.mp4", RequestBody.create(MediaType.parse("video/mpeg4"), new File(Environment.getExternalStorageDirectory().getAbsolutePath() + "/video.mp4")));
Call<ResponseBody> call = httpbinService.upload(video);
call.enqueue(new Callback<ResponseBody>() {
@Override
public void onResponse(Call<ResponseBody> call, Response<ResponseBody> response) {
try {
Log.i("video",response.body().string());
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void onFailure(Call<ResponseBody> call, Throwable t) {
}
});
}
转换器的使用:在以上的例子中,服务器返回给我们的结果要么是字符串形式,要么是输入流的形式;那如果服务器给我们返回Json格式的数据,并且我们要求程序将Json自动转换成对应的javaBean呢,那么这时就可以用到转换器了。
比如,服务器给我们返回的Json字符串如下:
{
"code": 0,
"msg": "ok",
"message": "ok",
"data": []
}
那么,首先我们编写对应的javaBean,可以自己手写,也可以找网上的一些转换工具。
public class Bean{
private Integer code;
private String msg;
private String message;
private List<String> data;
public Integer getCode() {
return this.code;
}
public void setCode(Integer code) {
this.code = code;
}
public String getMsg() {
return this.msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public String getMessage() {
return this.message;
}
public void setMessage(String message) {
this.message = message;
}
public List<String> getData() {
return this.data;
}
public void setData(List<String> data) {
this.data = data;
}
@Override
public String toString() {
return "Bean{" +
"code=" + code +
", msg='" + msg + '\'' +
", message='" + message + '\'' +
", data=" + data +
'}';
}
}
创建Api接口:
public interface Bilibili {
@GET("api/tooltip/query.list.do")
Call<Bean> get(); //将Call当中的泛型类型改为想要返回的javaBean类型
}
进行网络请求并得到响应结果:
public void converter(){
Retrofit retrofit=new Retrofit.Builder()
.baseUrl("https://message.bilibili.com/")
.addConverterFactory(GsonConverterFactory.create())
.build();
Bilibili bilibili = retrofit.create(Bilibili.class);
Call<Bean> call = bilibili.get();
call.enqueue(new Callback<Bean>() {
@Override
public void onResponse(Call<Bean> call, Response<Bean> response) {
Bean bean = response.body();//响应结果自动转成了javaBean类型
Log.i("bean",bean.toString());
}
@Override
public void onFailure(Call<Bean> call, Throwable t) {
}
});
}
以上就是OkHttp和Retrofit的基本用法了。
网络请求-Android篇(Okhttp和Retrofit)的更多相关文章
- 网络请求三方库——OkHttp
我们知道在Android开发中是可以直接使用现成的API进行网络请求的,就是使用 HttpClient 和 HttpURLConnention ,而Android 4.4 之后 HttpClient ...
- 从网络请求过程看OkHttp拦截器
前言 之前我们结合设计模式简单说了下OkHttp的大体流程,今天就继续说说它的核心部分--拦截器. 因为拦截器组成的链其实是完成了网络通信的整个流程,所以我们今天就从这个角度说说各拦截器的功能. 首先 ...
- Android网络请求(3) 网络请求框架OkHttp
Android网络请求(3) 网络请求框架OkHttp 本节我们来讲解OkHtpp网络请求框架 什么是网络请求框架 在我的理解中,网络请求框架是为了方便我们更加便捷规范的进行网络请求所建的类,我们通过 ...
- Android常用网络请求框架Volley Retrofit (okHttp)
Android系统中主要提供了两种方式来进行HTTP通信,HttpURLConnection和HttpClient.在 Android 5.0 的时候 Google 就不推荐使用 HttpClient ...
- 安卓开发常用网络请求框架OkHttp、Volley、XUtils、Retrofit对比
网络请求框架总结1.xutils 此框架庞大而周全,这个框架可以网络请求,同时可以图片加载,又可以数据存储,又可以 View 注解,使用这种框架很方便,这样会使得你整个项目对它依赖性太强,万一 ...
- 一个App带你学会Retrofit2.0,麻麻再也不用担心我的网络请求了!
Retrofit.Retrofit.Retrofit,越来越多的人在玩这个网络请求框架,这个由squareup公司开源的网络请求框架确实挺好用,今天我们就来看一下这个东东怎么玩! Retrofit作为 ...
- 学习RxJava+Retrofit+OkHttp+MVP的网络请求使用
公司的大佬用的是这一套,那我这个菜鸟肯定要学习使用了. 我在网上找了很多文章,写的都很详细,比如 https://www.jianshu.com/u/5fd2523645da https://www. ...
- Android okHttp网络请求之Retrofit+Okhttp+RxJava组合
前言: 通过上面的学习,我们不难发现单纯使用okHttp来作为网络库还是多多少少有那么一点点不太方便,而且还需自己来管理接口,对于接口的使用的是哪种请求方式也不能一目了然,出于这个目的接下来学习一下R ...
- Android okHttp网络请求之Json解析
前言: 前面两篇文章介绍了基于okHttp的post.get请求,以及文件的上传下载,今天主要介绍一下如何和Json解析一起使用?如何才能提高开发效率? okHttp相关文章地址: Android o ...
- Android 网络请求Retrofit + RxJava
一.背景 经常看到项目用Retrofit+RxJava+RxAndroid的框架,为了看懂项目的结构.现在来了解一下,Retrofit: Retrofit是Square 公司开发的一款正对Androi ...
随机推荐
- Node.js卸载与重装
卸载第一步:打开系统自带的卸载功能,找到node js 进行卸载第二步:删除C:\Users\Administrator\AppData\Roaming文件下的npm.npm-cache或者如果是zi ...
- 鼠标移入select options会触发mouseleave 事件处理方案
近来遇到一项目有一侧边工具菜单,在鼠标mouseenter事件打开对应的详细操作列表,当mouseleave时进行关闭,然操作列表中有一个select , 每当鼠标移入select options 时 ...
- 代码随想录算法训练营Day7哈希表| 454.四数相加II383. 赎金信15. 三数之和18. 四数之和 |总结
454.四数相加Ⅱ 题目链接:454.四数相加 给你四个整数数组 nums1.nums2.nums3 和 nums4 ,数组长度都是 n ,请你计算有多少个元组 (i, j, k, l) 能满足:. ...
- 【VS Code+Qt6】拖放操作
由于老周的示例代码都是用 VS Code + CMake + Qt 写的,为了不误导人,在标题中还是加上"VS Code"好一些. 上次咱们研究了剪贴板的基本用法,也了解了叫 QM ...
- 【Python&目标识别】调用百度智能云API实现植被识别
百度智能云于2015年正式对外开放运营,以"云智一体"为核心赋能千行百业,致力于为企业和开发者提供全球领先的人工智能.大数据和云计算服务及易用的开发工具.凭借先进的 ...
- IDEA连接数据库
我只想卷死各位,或者被各位卷死 在入门案例映射配置文件中存在报红的情况.问题如下: 产生的原因:Idea和数据库没有建立连接,不识别表信息.但是大家一定要记住,它并不影响程序的执行. 解决方式:在Id ...
- Python web 框架对比:Flask vs Django
哈喽大家好,我是咸鱼 今天我们从几个方面来比较一些现在流行的两个 python web 框架--Flask 和 Django,突出它们的主要特性.优缺点和简单案例 到最后,大家将更好地了解哪个框架更适 ...
- 2023-07-03:讲一讲Redis缓存的数据一致性问题和处理方案。
2023-07-03:讲一讲Redis缓存的数据一致性问题和处理方案. 答案2023-07-03: 数据一致性 当使用缓存时,无论是在本地内存中缓存还是使用 Redis 等外部缓存系统,会引入数据同步 ...
- 我用numpy实现了GPT-2,GPT-2源码,GPT-2模型加速推理,并且可以在树莓派上运行,读了不少hungging face源码,手动实现了numpy的GPT2模型
之前分别用numpy实现了mlp,cnn,lstm和bert模型,这周顺带搞一下GPT-2,纯numpy实现,最重要的是可在树莓派上或其他不能安装pytorch的板子上运行,生成数据 gpt-2的ma ...
- 安装Hadoop单节点伪分布式集群
目录 安装Hadoop单节点伪分布式集群 系统准备 开启SSH 安装JDK 安装Hadoop 下载 准备启动 伪分布式模式安装 配置 配饰SSH免密登录本机 测试启动 单节点安装YARN 伪分布式集群 ...