Android基础学习(十六)—— OkHttp

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

  • 支持HTTP/2,并允许对同一主机的所有请求共享一个套接字
  • 如果非 HTTP/2,则通过连接池减少了请求延迟
  • 默认请求GZip压缩数据
  • 响应缓存,避免了重复请求的网络

测试HTTP请求的服务器(大家都可以使用)URL:

https://www.httpbin.org/

一、OkHttp的基本使用

1、添加依赖,申请权限

在模块的build.gradle中添加依赖:

implementation("com.squareup.okhttp3:okhttp:4.9.0")

在AndroidManifest.xml中申请网络权限:

<uses-permission android:name="android.permission.INTERNET"/>
2、基本使用
OkHttpClient okHttpClient = new OkHttpClient();

GET同步请求:

//默认为Get请求
//Request.Builder().url(URL).get().build()中的get()可省略
//如果是Post,post()方法必须显式写出来
//创建Request请求对象
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();
    System.out.println("getSync:" + response.body().string());
}catch(IOException e){
    e.printStackTrace();
}

结果:

getSync:{
  "args": {
    "a": "1", 
    "b": "2"
  }, 
  "headers": {
    "Accept-Encoding": "gzip", 
    "Host": "www.httpbin.org", 
    "User-Agent": "okhttp/4.9.0", 
    "X-Amzn-Trace-Id": "Root=1-62f46765-066cbbd646cecf103cd67c0b"
  }, 
  "origin": "223.104.38.107", 
  "url": "https://www.httpbin.org/get?a=1&b=2"
}

GET异步请求:

OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
        .url("https://www.httpbin.org/get")
        .build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback(){
      @Override
      public void onFailure(Call call, IOException e){
           System.out.println( "getAsync onFailure:" + e);
      }
      @Override
      public void onResponse(Call call, Response response) throws IOException {
           System.out.println( "getAsync onResponse:" + response.body().string());
      }
 });

结果:

getAsync onResponse:{
  "args": {}, 
  "headers": {
    "Accept-Encoding": "gzip", 
    "Host": "www.httpbin.org", 
    "User-Agent": "okhttp/4.9.0", 
    "X-Amzn-Trace-Id": "Root=1-62f46837-383412113417986048a23c1c"
  }, 
  "origin": "223.104.38.107", 
  "url": "https://www.httpbin.org/get"
}

注意:

在Android中同步请求需写在一个新的线程当中:

new Thread(){
    @Override
    public void run(){
        //OkHttp,get同步请求代码
        ...
    }
}.start();

开启一个新线程是因为,Call.execute()方法会发生阻塞,只有该方法执行完毕,才会执行下面的代码

Call.enqueue()方法内部会自己创建子线程

启动一个Post同步请求:

public void postSync(View view){
    new Thread(){
        @Override
        public void run(){
            FormBody formBody = new FormBody.Builder()
                    .add("a","1")
                    .add("b", "2")
                    .build;
            Request request = new Request.Builder()
                    .url("https://www.httpbin.org/post")
                    .post(formBody)
                    .build();
            //获得准备执行请求的Call对象
            Call call = okHttpClient.newCall(request);
            try{
                //执行请求得到响应
                Response response = call.execute();
                Log.i(TAG, "postSync:" + response.body().string());
            }catch(IOException e){
                e.printStackTrace();
            }
        }
	}.start();
}

同理,可写出Post异步请求

二、POST请求的数据格式

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

https://www.runoob.com/http/http-content-type.html

  • Content-Type:application/x-www-form-urlencoded

    数据被编码为名称/值对,默认类型

  • Content-Type:multipart/form-data

    数据被编码为一条消息,一般用于文件上传

  • Content-Type:application/octet-stream

    提交二进制数据,如果用于文件上传,只能上传一个文件

  • Content-Type:application/json

    提交json数据

代码示例:

1、上传多个文件:

public class uploadFileUnitTest(){
    public void uploadFileTest(){
        OkHttpClient okHttpClient = new OkHttpClient();
        File file1 = new File("E:\\1.txt");
        File file2 = new File("E:\\2.txt");
        
        //addFormDataPart参数"file1","file2"这个名称在真正开发时需和服务器协商好
        MultipartBody multipartBody = new MultipartBody.Builder()
            .addFormDataPart("file1", file1.getName(), RequestBody.create(file1, MediaType.parse("text/plain")))
            .addFormDataPart("file2", file2.getName(), RequestBody.create(file2, MediaType.parse("text/plain")))
        	.build();
        	
        
        Request request = new Request.Builder()
            .url("https://www.httpbin.org/post")
            .post(multipartBody)
            .build();
        
        Call call = okHttpClient.newCall(request);
        Response response = call.execute();
        System.out.println(response.body().string());
    }
}

结果:

{
  "args": {}, 
  "data": "--0ec6eed5-b84c-480a-878b-f7477e1f5211\r\nContent-Disposition: form-data; name=\"f1\"; filename=\"1.txt\"\r\nContent-Type: text/plain\r\nContent-Length: 22\r\n\r\n1111111111111111111111\r\n--0ec6eed5-b84c-480a-878b-f7477e1f5211\r\nContent-Disposition: form-data; name=\"f2\"; filename=\"2.txt\"\r\nContent-Type: text/plain\r\nContent-Length: 16\r\n\r\n2222222222222222\r\n--0ec6eed5-b84c-480a-878b-f7477e1f5211--\r\n", 
  "files": {}, 
  "form": {}, 
  "headers": {
    "Accept-Encoding": "gzip", 
    "Content-Length": "382", 
    "Content-Type": "multipart/mixed; boundary=0ec6eed5-b84c-480a-878b-f7477e1f5211", 
    "Host": "www.httpbin.org", 
    "User-Agent": "okhttp/4.9.0", 
    "X-Amzn-Trace-Id": "Root=1-62f46b94-286b12c151288d1a2b5b3c61"
  }, 
  "json": null, 
  "origin": "223.104.38.107", 
  "url": "https://www.httpbin.org/post"
}

2、上传 json 数据:

public void jsonTest(){
	OkHttpClient okHttpClient = new OkHttpClient();
       
   	RequestBody requestBody = RequestBody.create("{\"a\":1,\"b\":2}", MediaType.parse("application/json"));
        
    Request request = new Request.Builder()
            .url("https://www.httpbin.org/post")
            .post(requestBody)
            .build();
        
    Call call = okHttpClient.newCall(request);
    Response response = call.execute();
    System.out.println(response.body().string());
 }

3、下载文件

public void download() throws IOException {
        OkHttpClient okHttpClient = new OkHttpClient();
        Request request = new Request.Builder()
                .url("https://image.baidu.com/search/down?tn=download&word=download&ie=utf8&fr=detail&url=https%3A%2F%2Fgimg2.baidu.com%2Fimage_search%2Fsrc%3Dhttp%253A%252F%252Fc-ssl.duitang.com%252Fuploads%252Fitem%252F202105%252F29%252F20210529001057_aSeLB.thumb.1000_0.jpeg%26refer%3Dhttp%253A%252F%252Fc-ssl.duitang.com%26app%3D2002%26size%3Df9999%2C10000%26q%3Da80%26n%3D0%26g%3D0n%26fmt%3Dauto%3Fsec%3D1662861218%26t%3D08bd446ab8c926831d0f1eed9cf60c82&thumburl=https%3A%2F%2Fimg2.baidu.com%2Fit%2Fu%3D1994380678%2C3283034272%26fm%3D253%26fmt%3Dauto%26app%3D138%26f%3DJPEG%3Fw%3D500%26h%3D500")
                .build();
        Call call = okHttpClient.newCall(request);
        Response response = call.execute();
        InputStream inputStream = response.body().byteStream();
        FileOutputStream fos = new FileOutputStream("E:\\666.jpg");
        int len;
        byte[] buff = new byte[4096];
        while((len = inputStream.read(buff)) != -1){
            fos.write(buff, 0, len);
        }
        fos.close();
        inputStream.close();
    }

三、OkHttp构建者的设置

提供了构建者模式来创建 OkHttpClient 对象:

OkHttpClient okHttpClient = new OkHttpClient.Builder().build();

向OkHttpClient增加自定义配置,这些自定义配置包括拦截器等

1、拦截器

添加拦截器的方式:

OkHttpClient okHttpClient = new OkHttpClient.Builder().addInterceptor(new XXX).build();
OkHttpClient okHttpClient = new OkHttpClient.Builder().addNetworkInterceptor(new XXX).build();

在同时添加 addInterception 拦截器和 addNetworkInterceptor 拦截器后,addInterception添加的拦截器中的内容会优先执行。

代码示例:

public class InterceptorUnitTest{
    OkHttpClient okHttpClient = new OkHttpClient.Builder().addInterceptor(new Interceptor(){
        @Override
        public Response intercept(Chain chain) throws IOException{
            //1. 不做任何处理
            //return chain.proceed(chain.request());  //拦截器没有做任何操作,就只是过了一遍拦截器
            
            //2. 自定义处理
            //前置处理
           Request request = chain.request().newBuilder().addHeader("os","android").addHeader("version", "1.0").build();
           Response response = chain.proceed(request);
            //后置处理
            return response;
            
        }
    }).build();
    
    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(TAG, "getSync:" + response.body().string());
	}catch(IOException e){
    	e.printStackTrace();
	}
}

加入拦截器的作用:在请求过程中会执行一次拦截器的代码

2、缓存与Cookie

缓存:

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

//pathname: 缓存文件地址
//maxSize:缓存最大容量字节
OkHttpClient okHttpClient = new OkHttpClient.Builder().cache(new Cache(new File(pathname), maxSize)).build();

Cookie:

Cookie是某些网站为了辨别用户身份,进行会话跟踪(比如确定登录状态、VIP身份)而存储在用户本地终端上的数据(通常经过加密)。

比如查看“收藏文章列表” 时,需要确定用户登录状态,这时用到Cookie

玩Android 里面有开放的API:

玩Android

玩Android 开放API

代码示例(使用Cookie):

public class CookieUnitTest{
    Map<String,List<Cookie>> cookies = new HashMap<>();
    public void cookieTest(){
        OkHttpClient okHttpClient = new OkHttpClient.Builder()
            .cookieJar(new CookieJar(){
                //saveFromResponse方法的作用是将服务器返回的数据回调给参数list
                @Override
                public void saveFromResponse(HttpUrl httpUrl, List<Cookie> list){
                    cookies.put(httpUrl.host(), list);
                }
                
                @Override
                public List<Cookie> loadForRequest(HttpUrl httpUrl){
                    List<Cookie> cookies = CookieUnitTest.this.cookies.get(httpUrl.host());
                    return cookies == null ? new ArrayList<>() : cookies;
                }
            })
            .build();
    
     	FormBody formBody = new FormBody.Builder().add("username", "lanceedu").add("password","123123").build();
        
    Request request = new Request.Builder().url("https://www.wanandroid.com/user/login").post(formBody).build();
  
	//获得准备执行请求的Call对象
	Call call = okHttpClient.newCall(request);
	try{
    	//执行请求得到响应
   	 	Response response = call.execute();
        Log.i(TAG, "getSync:" + response.isSuccessful());
    	Log.i(TAG, "getSync:" + response.body().string());
	}catch(IOException e){
    	e.printStackTrace();
	}
        
        
        //查看上述登录用户的文章收藏列表,如果没有设置Cookie,则查看不到
       request = new Request.Builder().url("https://www.wanandroid.com/lg/collect/list/0/json").build();
  
	//获得准备执行请求的Call对象  和上面登录使用的是同一个okHttpClient(设置了cookie)
	 call = okHttpClient.newCall(request);
	try{
    	//执行请求得到响应
   	 	Response response = call.execute();
    	Log.i(TAG, "getSync:" + response.body().string());
	}catch(IOException e){
    	e.printStackTrace();
	}       
}
}
}

不过,现在Cookie使用的也不是很多了,很多网络不是以Cookie来进行身份验证。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值