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

Android流行框架OkHttp的使用

程序员文章站 2022-03-16 13:01:21
这么多网络框架为什么使用OkHttp?因为不仅在接口封装上做的简单易用,在底层实现上也上自成一派,比起原声的HttpURLConnection,可以说上有过之而无不及,现在已经成了广大Android开发者首选的网络通信库。OkHttp项目主页:https://github.com/square/okhttp使用OkHttp学习常见的网络请求GET普通POST form请求Content- Type: application/x-www-form-urlencoded支持文件上传的POST fo...

这么多网络框架为什么使用OkHttp?因为不仅在接口封装上做的简单易用,在底层实现上也上自成一派,比起原声的HttpURLConnection,可以说上有过之而无不及,现在已经成了广大Android开发者首选的网络通信库。

OkHttp项目主页:https://github.com/square/okhttp

使用OkHttp学习常见的网络请求

  • GET请求
  • 普通POST form请求
    Content- Type: application/x-www-form-urlencoded
  • 支持文件上传的POST form请求
    Content-Type:multipart/form-data; boundary=
  • POST JSON字符串

Android网络请求注意事项

1.使用HTTP协议的URL 从Android P开始,默认不再允许直接访问HTTP请求;
2.通过设置Network Security Configuration支持;

网络请求测试接口
http://www.imooc.com/api/okhttp/getmethod
http://www.imooc.com/api/okhttp/postmethod
http://www.imooc.com/api/okhttp/postjson

一、OkHttp的GET请求

1.使用前的配置

首先在app/build.gradle中添加依赖库SDK最低版本为21。(进入项目主页可以找到最新版本)

android {
	compileOptions {
        sourceCompatibility JavaVersion.VERSION_1_8
        targetCompatibility JavaVersion.VERSION_1_8
    }
}

dependencies {
	implementation("com.squareup.okhttp3:okhttp:4.9.0")
}

添加网络安全配置,在res目录下新建xml文件写入代码。以 Android 6.0(API 级别 23)及更低版本为目标平台的应用的默认配置如下所示。

具体可以参考:Android开发者文档网络安全配置
Android流行框架OkHttp的使用

<?xml version="1.0" encoding="utf-8"?>
<network-security-config>
    <base-config cleartextTrafficPermitted="true">
        <trust-anchors>
            <certificates src="system" />
            <certificates src="user" />
        </trust-anchors>
    </base-config>
</network-security-config>

在AndroidManifest.xml文件中声明权限

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

<application
	android:networkSecurityConfig="@xml/network_security_config">
</application>

2.同步请求

  • 创建请求: Request.Builder() -> Request对象
  • 通过Request得到Call对象:client.newCall(request) -> Call对象
  • 执行Call :同步call.execute(),异步call.enqueue()
  • 得到Response对象

新建一个OkHttpUtils类,使用单例模式

public class OkHttpUtils {
    private OkHttpClient okHttpClient;

    //设置单例模式
    private OkHttpUtils(){}
    private static OkHttpUtils sInstance = new OkHttpUtils();
    public static OkHttpUtils getInstance() {
        return sInstance;
    }
}

OkHttpUtils类中创建一个方法

//url接口 http://www.imooc.com/api/okhttp/getmethod?username=David
//需要自己开一个线程,或者使用handler处理请求到的数据
public String doGetBySync(String url) {
    try {
        //1.拿到OkHttpClient对象
        OkHttpClient client = new OkHttpClient();
        //2.构造Request对象
        Request request = new Request.Builder()
                .url(url)
                .build();
        //3.将Request封装为Call
        Call call = client.newCall(request);
        //4.调用同步请求方法
        Response response = call.execute();
        //返回应答
        return response.body().string();
    } catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

MainActivity中声明全局变量

//传入将主线程中的Looper,也就是说handleMessage会运行在主线程中
private Handler handler = new Handler();

使用按键调用该方法 doGetBySync();

new Thread() {
    @Override
    public void run() {
        String content = OkHttpUtils.getInstance()
                .doGetBySync("http://www.imooc.com/api/okhttp/getmethod?username=David&password=123");
        //子线程不能处理UI,使用Handler的Post
        handler.post(new Runnable() {
            @Override
            public void run() {
               //将收到的内容现实在TextView上
               mTvContent.setText(content);
            }
        });
    }
}.start();

3.异步请求

此方法使用到了回调,可以参考这篇文章学习:Android自定义回调函数
首先创建一个接口 INetCallBack

public interface INetCallBack {
    void onFailed(Throwable ex);
    void onSuccess(String response);
}

OkHttpUtils类中声明全局变量

//传入主线程Looper
private final Handler mHandler = new Handler(Looper.getMainLooper());

OkHttpUtils类中创建一个方法

public void doGetByAsync(String url, INetCallBack callBack) {
    //1.拿到OkHttpClient对象
    OkHttpClient client = new OkHttpClient();
    //2.构造Request对象
    Request request = new Request.Builder()
            .url(url)
            .build();
    //3.将Request封装为Call
    Call call = client.newCall(request);
    //4.调用异步请求方法,重写回调方法
    call.enqueue(new Callback() {
        @Override
        public void onFailure(@NotNull Call call, @NotNull IOException e) {
            //处理UI线程
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    //调用回调方法
                    callBack.onFailed(e);
                }
            });
        }

        @Override
        public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
            String str = null;
            try {
                str = response.body().string();
            } catch (IOException e) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        callBack.onFailed(e);
                    }
                });
                return;
            }
            final String rspStr = str;
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    callBack.onSuccess(rspStr);
                }
            });
        }
    });
}

使用按键调用该方法 doGetByAsync();

OkHttpUtils.getInstance().doGetByAsync(
		"http://www.imooc.com/api/okhttp/getmethod?username=David&password=123",
        new INetCallBack() {
            @Override
            public void onFailed(Throwable ex) {
            //写回调方法
                Toast.makeText(MainActivity.this, "获取数据失败", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onSuccess(String response) {
                mTvContent.setText(response);
            }
        }
);

最终运行结果
Android流行框架OkHttp的使用

二、OkHttp的POST请求

1.使用Logging Interceptor打印信息

参考文章:Logging Interceptor

添加依赖库

dependencies {
    implementation("com.squareup.okhttp3:logging-interceptor:4.9.0")
}

在构造函数中创建LoggingInterceptor对象

private OkHttpUtils(){
    //LoggingInterceptor配置
    HttpLoggingInterceptor logging = new HttpLoggingInterceptor(new HttpLoggingInterceptor.Logger() {
        @Override
        public void log(@NotNull String s) {
            Log.d("Interceptor", s);
        }
    });
    //设置log等级
    logging.setLevel(HttpLoggingInterceptor.Level.BODY);

    //OkHttpClient 建造者模式
    //https://blog.csdn.net/bingjianit/article/details/53607856
    client = new OkHttpClient.Builder()
    	    //.connectTimeout()
            .addInterceptor(logging)//添加拦截器,打印请求结果
            .build();
}

这样每次使用OkHttp的请求时就可以查看Log的信息了

运行结果

D/Interceptor: --> GET http://www.imooc.com/api/okhttp/getmethod?username=David&password=123
D/Interceptor: --> END GET
D/Interceptor: <-- 200 OK http://www.imooc.com/api/okhttp/getmethod?username=David&password=123 (134ms)
D/Interceptor: Server: openresty
D/Interceptor: Date: Thu, 03 Dec 2020 23:46:40 GMT
D/Interceptor: Content-Type: text/html; charset=UTF-8
D/Interceptor: Transfer-Encoding: chunked
D/Interceptor: Connection: keep-alive
D/Interceptor: Vary: Accept-Encoding
D/Interceptor: Access-Control-Allow-Origin: *
D/Interceptor: X-Varnish: 1048639445
D/Interceptor: Age: 0
D/Interceptor: Via: 1.1 varnish (Varnish/6.0)
D/Interceptor: X-Cache: MISS from CS42
D/Interceptor: Accept-Ranges: bytes
D/Interceptor: {"errorCode":1,"data":{"ip":"42.80.244.194","headers":{"X-Varnish":"1048639446","X-Forwarded-For":"...}
D/Interceptor: <-- END HTTP (290-byte body)

2.POST 普通form

OkHttp进行Post请求提交键值对

public void doPost(String url, HashMap<String, String> headers,
		 HashMap<String, String> params, INetCallBack callBack) {

    //1.构建FormBody,传入参数
	//FormBody formBody = new FormBody.Builder()
	//.add("username", "admin")
	//.add("password", "admin")
	//.build();
    FormBody.Builder formBodyBuilder = new FormBody.Builder();
        if (params != null) {
            for (String param : params.keySet()) {
                formBodyBuilder.add(param, params.get(param));
            }
        }

    //2.添加头部信息
    Request.Builder requestBuilder = new Request.Builder();
    addHeader(requestBuilder, headers);

    //3.构建Request,将FormBody作为Post方法的参数传入
    Request request = requestBuilder
            .url(url)
            .post(formBodyBuilder.build())
            .build();

    //4.调用请求,重写回调方法
    executeRequest(callBack, request);
}

private void addHeader(Request.Builder requestBuilder, HashMap<String, String> headers) {
    requestBuilder = new Request.Builder();
    if (headers != null) {
        for (String key : headers.keySet()) {
            requestBuilder.addHeader(key, headers.get(key));
        }
    }
}

private void executeRequest(INetCallBack callBack, Request request) {
    Call call = client.newCall(request);
    call.enqueue(new Callback() {
        @Override
        public void onFailure(@NotNull Call call, @NotNull IOException e) {
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    callBack.onFailed(e);
                }
            });
        }

        @Override
        public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
            String respStr = null;
            try {
                respStr = response.body().string();
            } catch (IOException e) {
                mHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        callBack.onFailed(e);
                    }
                });
                return;
            }
            String finalRespStr = respStr;
            mHandler.post(new Runnable() {
                @Override
                public void run() {
                    callBack.onSuccess(finalRespStr);
                }
            });
        }
    });
}

执行代码

HashMap<String, String> params = new HashMap<>();
params.put("username", "David");
params.put("password", "123");

HashMap<String, String> headers = new HashMap<>();
headers.put("author_header","David");

OkHttpUtils.getInstance().doPostMultiPart("http://www.imooc.com/api/okhttp/postmethod",
        params,
        headers,
        new INetCallBack() {
            @Override
            public void onFailed(Throwable ex) {
                Toast.makeText(MainActivity.this, "网络发生错误", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onSuccess(String response) {
                mTvContent.setText(response);
            }
        }
);

运行结果
Android流行框架OkHttp的使用

3.POST 文件上传form

关于上传文件可以参考:OkHttp进行Post请求上传文件

代码部分和之前的POST差不多

public void doPostMultiPart(String url, HashMap<String, String> headers, 
		HashMap<String, String> params, INetCallBack callBack) {
	//1.构建FormBody,传入参数
    MultipartBody.Builder multipartBodyBuilder = new MultipartBody.Builder();
    //设置类型
    multipartBodyBuilder.setType(MultipartBody.FORM);
    if (params != null) {
        for (String param : params.keySet()) {
            multipartBodyBuilder.addFormDataPart(param, params.get(param));
        }
    }

    //2.添加头部信息
    Request.Builder requestBuilder = new Request.Builder();
    addHeader(requestBuilder, headers);

    //3.构建Request,将multipartBodyBuilder作为Post方法的参数传入
    Request request = requestBuilder
            .url(url)
            .post(multipartBodyBuilder.build())
            .build();

    //4.调用请求,重写回调方法
    executeRequest(callBack, request);
}

执行代码

HashMap<String, String> params = new HashMap<>();
params.put("username", "David");
params.put("password", "123");

HashMap<String, String> headers = new HashMap<>();
headers.put("author_header","David");

OkHttpUtils.getInstance().doPostMultiPart("http://www.imooc.com/api/okhttp/postmethod",
        params,
        headers,
        new INetCallBack() {
            @Override
            public void onFailed(Throwable ex) {
                Toast.makeText(MainActivity.this, "网络发生错误", Toast.LENGTH_SHORT).show();
            }

            @Override
            public void onSuccess(String response) {
                mTvContent.setText(response);
            }
        }
);

运行结果
Android流行框架OkHttp的使用
可以看出POST的类型为Content-Type: multipart/form-data;

4.POST JSON

public void doPostJson(String url, HashMap<String, String> headers,
		 String jsonStr, INetCallBack callBack) {
		 
	//传入字符串格式
    MediaType jsonMediaType = MediaType.get("application/json");
    RequestBody requestBody = RequestBody.create(jsonStr, jsonMediaType);

    Request.Builder requestBuilder = new Request.Builder();
    addHeader(requestBuilder, headers);

    Request request = requestBuilder
            .url(url)
            .post(requestBody)
            .build();

    executeRequest(callBack, request);
}
HashMap<String,String> headers = new HashMap<>();
headers.put("author_header","david");

OkHttpUtils.getInstance().doPostJson("http://www.imooc.com/api/okhttp/postjson",
        headers,
        "{\"name\":\"david\",\"age\":12}",
        new INetCallBack() {
            @Override
            public void onSuccess(String response) {
                mTvContent.setText(response);
            }

            @Override
            public void onFailed(Throwable ex) {
                Toast.makeText(MainActivity.this, "网络发生错误", Toast.LENGTH_SHORT).show();
            }
        }
);

三、自定义Intercepter

创建MyIntercepter类

public class MyIntercepter implements Interceptor {

    @NotNull
    @Override
    public Response intercept(@NotNull Chain chain) throws IOException {

        Request originRequest = chain.request();
        Request newRequest = originRequest.newBuilder()
                .addHeader("author", "david_intercepter")
                .build();

        return chain.proceed(newRequest);
    }
}

在OkHttpClient.Builder() 中添加自定义Interceptor

client = new OkHttpClient.Builder()
		.addInterceptor(new MyInterceptor())
		.addInterceptor(logging)//添加拦截器,打印请求结果
		.build();

这样就不需要和上面那样添加header了
Android流行框架OkHttp的使用

扩展:Builder 设计模式

本文地址:https://blog.csdn.net/Blue3Red1/article/details/110586416