欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

OkHttp基本使用

程序员文章站 2022-03-11 16:16:55
简介OkHttp是一个高效的HTTP客户端,它有以下默认特性:支持HTTP/2,允许所有同一个主机地址的请求共享同一个socket连接连接池减少请求延时透明的GZIP压缩减少响应数据的大小缓存响应内容,避免一些完全重复的请求当网络出现问题的时候OkHttp依然坚守自己的职责,它会自动恢复一般的连接问题,如果你的服务有多个IP地址,当第一个IP请求失败时,OkHttp会交替尝试你配置的其他IP,OkHttp使用现代TLS技术(SNI, ALPN)初始化新的连接,当握手失败时会回退到TLS...

简介

OkHttp是一个高效的HTTP客户端,它有以下默认特性:

支持HTTP/2,允许所有同一个主机地址的请求共享同一个socket连接


连接池减少请求延时

透明的GZIP压缩减少响应数据的大小

缓存响应内容,避免一些完全重复的请求

当网络出现问题的时候OkHttp依然坚守自己的职责,它会自动恢复一般的连接问题,如果你的服务有多个IP地址,当第一个IP请求失败时,OkHttp会交替尝试你配置的其他IP,OkHttp使用现代TLS技术(SNI, ALPN)初始化新的连接,当握手失败时会回退到TLS 1.0。

note: OkHttp 支持 Android 2.3 及以上版本Android平台, 对应于 Java, JDK 1.7及以上.
二.使用

OkHttp的使用是非常简单的. 它的请求/响应 API 使用构造器模式builders来设计,它支持阻塞式的同步请求和带回调的异步请求。


官网:https://github.com/square/okhttp


添加依赖:implementation 'com.squareup.okhttp3:okhttp:3.11.0'

讲解案例,前四个,案例图:
OkHttp基本使用

GET异步请求

-导入依赖

-new OkHttpClient;

-构造Request对象;

-通过前两步中的对象构建Call对象;

-通过Call#enqueue(Callback)方法来提交异步请求;

注意:1.onResponse属于次线程,不能更新UI主线程中的组件,需要handler
2.response.body().string() 只能执行一次,原因:把inputStream数据流打开读取完数据后,会close关闭流

``
String url = “http://gank.io/api/data/%E7%A6%8F%E5%88%A9/10/3”;
OkHttpClient okHttpClient = new OkHttpClient();
final Request request = new Request.Builder()
.url(url)
.get()//默认就是GET请求,可以不写
.build();
Call call = okHttpClient.newCall(request);
call.enqueue(new Callback() {
@Override //失败的方法
public void onFailure(Call call, IOException e) {
Log.d(TAG, "onFailure: ");
}
@Override //成功的方法,得到响应的json数据
public void onResponse(Call call, Response response) throws IOException {
String json = response.body().string(); //此方法只能调用一次,因为会关闭数据流
Log.d(TAG, "onResponse: " + json);
//注意:此方法属于次线程,如果更新UI组件,需要Handler等处理
//后续可以进行:json解析,展示数据在RecyclerView上
}
});


异步发起的请求会被加入到 Dispatcher 中的 runningAsyncCalls双端队列中通过线程池来执行。

GET同步请求

    前面几个步骤和异步方式一样,只是最后一部是通过 Call#execute() 来提交请求,注意这种方式会阻塞调用线程,所以在Android中应放在子线程中执行,否则有可能引起ANR异常,Android3.0 以后已经不允许在主线程访问网络。


String url = "http://gank.io/api/data/%E7%A6%8F%E5%88%A9/10/3";

OkHttpClient okHttpClient = new OkHttpClient();
final Request request = new Request.Builder()
.url(url)
.build();

final Call call = okHttpClient.newCall(request);

new Thread(new Runnable() {

@Override
public void run() {
    try {
        Response response = call.execute();
        Log.d(TAG, "run: " + response.body().string());
    } catch (IOException e) {
        e.printStackTrace();
    }
}}).start();

POST方式异步提交String

这种方式与前面的区别就是在构造Request对象时,需要多构造一个RequestBody对象,用它来携带我们要提交的数据。在构造 RequestBody 需要指定MediaType,用于描述请求/响应 body 的内容类型,关于 MediaType 的更多信息可以查看 https://tools.ietf.org/html/rfc2045,RequstBody的几种构造方式:
OkHttp基本使用

MediaType mediaType = MediaType.parse("text/x-markdown; charset=utf-8");


RequestBody requestBody = RequestBody.create(mediaType, "i am jerry");//创建请求的体:数据

Request request = new Request.Builder()
        .url("https://api.github.com/markdown/raw")
        .post(requestBody)
        .build();

OkHttpClient okHttpClient = new OkHttpClient();

okHttpClient.newCall(request).enqueue(new Callback() {

    @Override
    public void onFailure(Call call, IOException e) {
        Log.d(TAG, "onFailure: " + e.getMessage());

    }

    @Override
    public void onResponse(Call call, Response response) throws IOException {

        Log.d(TAG, response.protocol() + " " +response.code() + " " + response.message());

        Headers headers = response.headers();

        for (int i = 0; i < headers.size(); i++) {
            Log.d(TAG, headers.name(i) + ":" + headers.value(i));
        }
        Log.d(TAG, "onResponse: " + response.body().string());
    }
});

POST方式同步提交String:同步部分和GET请求的同步写法一致

OKHttp结合项目案例:创建一个新的model
OkHttp基本使用

技术点:

1.OKHttp网络请求 2.下拉刷新上拉加载 3.缓存 4.存储的读写权限的动态申请

接口:http://gank.io/api/data/%E7%A6%8F%E5%88%A9/10/3

2.6SmartRefreshLayout实现下拉刷新,上拉加载

依赖:

implementation 'com.scwang.smartrefresh:SmartRefreshLayout:1.0.4-7'

implementation 'com.scwang.smartrefresh:SmartRefreshHeader:1.0.4-7'

在界面中引入SmartRefreshLayout,包裹 列表组件:RecyclerView或ListView等

<com.scwang.smartrefresh.layout.SmartRefreshLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:id="@+id/smartRe" >
        <android.support.v7.widget.RecyclerView
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:id="@+id/myrec" />
    </com.scwang.smartrefresh.layout.SmartRefreshLayout>

添加OnRefreshListener监听,实现下来刷新,OnLoadMoreListener监听,实现上拉加载

//添加下拉刷新监听器
mSmartRe.setOnRefreshListener(new OnRefreshListener() {
     @Override
     public void onRefresh(@NonNull RefreshLayout refreshLayout) {

    //下拉刷新
    }
});
//添加上拉加载监听器
 mSmartRe.setOnLoadMoreListener(new OnLoadMoreListener() {
    @Override
    public void onLoadMore(@NonNull RefreshLayout refreshLayout) {
     //上拉加载
     }
});

OKHttp缓存,自带缓存功能,默认不添加缓存,添加缓存,需要自行添加:

long maxSize  = 1024*1024*100; //100m大小
//手动指定缓存路径
Cache cache = new Cache(new File("/storage/emulated/0/day1_cache"), maxSize);
//使用系统指定的缓存路径
// Cache cache1 = new Cache(getExternalCacheDir(), maxSize);
OkHttpClient okHttpClient = new OkHttpClient.Builder()
   .cache(cache)//设置缓存
   .build();

POST方式提交表单:登录

OkHttpClient okHttpClient = new OkHttpClient();
RequestBody requestBody = new FormBody.Builder()
                .add("username", "qawsedrf")  //用户名和密码可用   zhangsan12   123456
                .add("password", "qazwsxedc")
                .build();
Request request = new Request.Builder()
        .url("https://www.wanandroid.com/user/login")
        .post(requestBody)
        .build();
        
okHttpClient.newCall(request).enqueue(new Callback() {
    @Override
    public void onFailure(Call call, IOException e) {
        Log.d(TAG, "onFailure: " + e.getMessage());  //加断点跟踪
    }
    
    @Override
    public void onResponse(Call call, Response response) throws IOException {
        String str = response.body().string();
        Log.i(TAG, "onResponse成功: " + str);
        //json解析
        LoginResultBean loginResultBean = new Gson().fromJson(str, LoginResultBean.class);
        int errorCode = loginResultBean.getErrorCode();
        //把errorCode发给handler判断登录 成功还是失败

        handler.sendMessage(handler.obtainMessage(1, errorCode));
    }

});

Handler handler = new Handler() {
    @Override
    public void handleMessage(Message msg) {
        super.handleMessage(msg);
        if (msg.what == 1) {
            int errorCode = (int) msg.obj;
            if (errorCode == 0) {//成功,跳转到成功页面

                startActivity(new Intent(MainActivity.this, LoginSuccessActivity.class));

            } else {
                Toast.makeText(MainActivity.this, "账号密码不匹配!请检查",Toast.LENGTH_SHORT).show();
            }
        } 
    }

};

POST请求上传文件


// String filePath = Environment.getExternalStorageDirectory().getPath() + "/mm.png"; //通过代码获得存储路径

//File f2 = new File(filePath);

OkHttpClient okHttpClient = new OkHttpClient();

MediaType mediaType = MediaType.parse("application/octet-stream");

// File file = new File("/storage/emulated/legacy/mm.png");//模拟器的路径

File file = new File("/storage/emulated/0/mm.png");//真机的路径
if (file.exists()) {//判断图片文件是否存在  file.exists() true表示存在
    RequestBody requestBody = RequestBody.create(mediaType, file);
    MultipartBody multipartBody = new MultipartBody.Builder()
        .setType(MultipartBody.FORM)
        .addFormDataPart("file", file.getName(), requestBody)
        .build();
    Request request = new Request.Builder()
        .url("http://yun918.cn/study/public/file_upload.php")
        .post(multipartBody)
        .build();

    okHttpClient.newCall(request).enqueue(new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            String str = e.getMessage();
            Log.i(TAG, "onResponse上传失败: " + str);
        }
        @Override
        public void onResponse(Call call, Response response) throws IOException {

            String str = response.body().string();
            Log.i(TAG, "onResponse上传成功: " + str);
            //得到的是一个 字符串 分三行,最后一行是一个json串,所以用 换行符\n 切割
            String[] split = str.split("\n");
            str = split[split.length - 1];//得到第三个结果  json串   也可以用gson解析了
            //UploadResultBean  是由成功的json串生成的解析类
            UploadResultBean uploadResultBean = new Gson().fromJson(str, UploadResultBean.class);
            int code = uploadResultBean.getCode();

            if (code == 200) {//表示成功,继续得到 url   不然,失败,不要进行处理
                String url = (String) uploadResultBean.getData().getUrl();
                Log.i(TAG, "onResponse  图片的路径: " + url);
                handler.sendMessage(handler.obtainMessage(2, url));
            }
        }
    });

}

Handler handler = new Handler() {

    String url = (String) msg.obj;
    Glide.with(MainActivity.this).load(url).into(mHeaderImg);//加载为头像

}



header请求头:有些请求需要添加请求头header,服务器才能通过请求


OkHttpClient okHttpClient = new OkHttpClient();
Request request = new Request.Builder()
    .get()
    .url(headerUrl)
    .header("Authorization", "APPCODE db33b75c89524a56ac94d6519e106a59")//设置请求头,已过期不可用
//   .addHeader("Authorization","APPCODE db33b75c89524a56ac94d6519e106a59")//设置请求头  两种都可以
    .build();

okHttpClient.newCall(request).enqueue(new Callback() {

    @Override
    public void onFailure(Call call, IOException e) {
    
    }
    @Override
    public void onResponse(Call call, Response response) throws IOException {

        Log.i(TAG, "onResponse: " + response.body().string());

        String s = "";
    }

});



其他

1.推荐让 OkHttpClient 保持单例,用同一个 OkHttpClient 实例来执行你的所有请求,因为每一个 OkHttpClient 实例都拥有自己的连接池和线程池,重用这些资源可以减少延时和节省资源,如果为每个请求创建一个 OkHttpClient 实例,显然就是一种资源的浪费。

2.每一个Call(其实现是RealCall)只能执行一次,否则会报异常,具体参见 RealCall#execute()

3.response.body().string()只调用一次

HttpURLconnection及OkHttp3的对比分析

1,HttpUrlConnection,google官方提供的用来访问网络,但是实现的比较简单,只支持1.0/1.1

2,并没有多路复用,如果碰到app大量网络请求的时候,性能比较差,

3,HttpUrlConnection底层也是用Socket来实现的

4,OkHttp像HttpUrlConnection一样,实现了一个网络连接的过程。

5,OkHttp和HttpUrlConnection是一级的,用socket实现了网络连接,OkHttp更强大,

6,HttpUrlConnection在IO方面用到的是InputStream和OutputStream,但OkHttp用的是sink和source,这两个是在Okio这个开源库里的, feredSink(支持缓冲)、GzipSink(支持Gzip压缩)、ForwardingSink和InflaterSink(后面这两者服务于GzipSink)

7,多个相同host和port的stream可以共同使用一个socket,而RealConnection就是处理连接的,那也就是说一个RealConnection上可能有很多个Stream

8,OkHttp代码比HttpURLConnection精简的多

四 OkHttp的封装

推荐用同一个 OkHttpClient 实例来执行你的所有请求,因为每一个 OkHttpClient 实例都拥有自己的连接池和线程池,重用这些资源可以减少延时和节省资源,如果为每个请求创建一个 OkHttpClient 实例,显然就是一种资源的浪费。让 OkHttpClient 保持单例,对OkHttp进一步封装

public class OkHttpUtil {
    private static OkHttpUtil okHttpUtil;
    private final OkHttpClient  okHttpClient;
    private OkHttpUtil(){
        okHttpClient = new OkHttpClient.Builder()
                .connectTimeout(5, TimeUnit.SECONDS)
                .readTimeout(5,TimeUnit.SECONDS)
                .writeTimeout(5,TimeUnit.SECONDS)
                .build();
    }

    //单例模式 保证只有一个OkHttpUtil对象,同时只有一个okHttpClient对象
    public static OkHttpUtil getInstance(){
        if(okHttpUtil == null){
            synchronized (OkHttpUtil.class){
                if (okHttpUtil == null) {
                    okHttpUtil = new OkHttpUtil();
                }
            }
        }
        return okHttpUtil;
    }

   //异步  get 无参,参数在url中
    public void get(String url, ResultCallback resultCallback){
        callBackIsNull(resultCallback);
        Request request = getRequestGet(url);
        enqueue(resultCallback,request);

    }

    //异步  post 有参  ,参数
    public void postString(String url, String data, ResultCallback resultCallback){
        callBackIsNull(resultCallback);
        MediaType type = MediaType.parse("text/x-markdown;charset=utf-8");
        RequestBody body = RequestBody.create(type,data);
        Request request = getRequestPost(url, body);
        enqueue(resultCallback,request);

    }

    public void postForm(String url, Map<String, String> data, ResultCallback resultCallback){
        callBackIsNull(resultCallback);
        FormBody.Builder builder = new FormBody.Builder();
        Set<Map.Entry<String, String>> entries = data.entrySet();
        for (Map.Entry<String, String> entry : entries) {
            String key = entry.getKey();
            String  value = entry.getValue();
            builder.add(key, value);
        }

        RequestBody body = builder.build();
        Request request = getRequestPost(url, body);
        enqueue(resultCallback, request);

    }

    public void postFile(String url, String filePath, ResultCallback resultCallback){
        callBackIsNull(resultCallback);
        MediaType type = MediaType.parse("application/octet-stream");//设置请求数据类型  是数据流
//        File file = new File("/storage/emulated/legacy/mm.png");//上传的的文件
        File file = new File(filePath);
        if(file.exists()){
            RequestBody fileBody = RequestBody.create(type, file);//创建带文件的请求体对象
            RequestBody body = new MultipartBody.Builder()  //通过分块的流数据体,结合带文件的请求体对象 创建最终的 form表单格式的请求体 body
                    .setType(MultipartBody.FORM)
                    .addFormDataPart("file", file.getName(), fileBody)
                    .build();
            Request request = getRequestPost(url, body);
            enqueue(resultCallback, request);
        }

    }
    //自定义回调接口,供Callback使用
    public interface ResultCallback{

        //失败的回调
        void onFailure(IOException e);

        //成功的回调
        void onResponse(Response response) throws IOException;

    }

//判断resultCallback是否为空

    private void callBackIsNull(ResultCallback resultCallback) {
        //判断callBack是否为null,
        if (resultCallback == null){

            throw new  IllegalArgumentException("callBack is null");
        }

    }

   //把异步执行的具体操作enqueue提取出来
    private void enqueue(final ResultCallback resultCallback, Request request){
        okHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                resultCallback.onFailure(e);
            }
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                resultCallback.onResponse(response);
            }
        });
    }

//获取get请求的request对象
    private Request getRequestGet(String url){
        return new Request.Builder()
                .get()
                .url(url)
                .build();

    }

   //获取post请求的request对象
    private Request getRequestPost(String url, RequestBody requestBody){
        return new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();

    }

}
调用:
 OkHttpUtil.getInstance().get(headerUrl, new OkHttpUtil.ResultCallback() {
    @Override
    public void onFailure(IOException e) {

    }

    @Override
    public void onResponse(Response response) throws IOException {


    }
 });

本文地址:https://blog.csdn.net/weixin_44832024/article/details/107942022

相关标签: java android