1、在模块中下载或者添加依赖:
implementation 'com.squareup.okhttp3:okhttp:4.7.2'当你看到这的时候,可能最新的稳定版已经不是3.10.0了,你需要移步官方GitHub来查看最新版本。 官方地址 https://github.com/square/okhttp,另外不要忘了在清单文件声明访问Internet的权限,如果使用 DiskLruCache,那还得声明写外存的权限。
2、okhttp使用
a、异步GET请求
-new OkHttpClient; -构造Request对象; -通过前两步中的对象构建Call对象; -通过Call#enqueue(Callback)方法来提交异步请求;
String url = "http://wwww.baidu.com"; 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 public void onResponse(Call call, Response response) throws IOException { Log.d(TAG, "onResponse: " + response.body().string()); } });b、同步GET请求
前面几个步骤和异步方式一样,只是最后一部是通过 Call#execute() 来提交请求,注意这种方式会阻塞调用线程,所以在Android中应放在子线程中执行,否则有可能引起ANR异常,Android3.0 以后已经不允许在主线程访问网络。
String url = "http://wwww.baidu.com"; 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();c、POST方式提交String
这种方式与前面的区别就是在构造Request对象时,需要多构造一个RequestBody对象,用它来携带我们要提交的数据。在构造 RequestBody 需要指定MediaType,用于描述请求/响应 body 的内容类型,关于 MediaType 的更多信息可以查看 RFC 2045,RequstBody的几种构造方式:
MediaType mediaType = MediaType.parse("text/x-markdown; charset=utf-8"); String requestBody = "I am Jdqm."; Request request = new Request.Builder() .url("https://api.github.com/markdown/raw") .post(RequestBody.create(mediaType, 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()); } });响应内容
http/1.1 200 OK Date:Sat, 10 Mar 2018 05:23:20 GMT Content-Type:text/html;charset=utf-8 Content-Length:18 Server:GitHub.com Status:200 OK X-RateLimit-Limit:60 X-RateLimit-Remaining:52 X-RateLimit-Reset:1520661052 X-CommonMarker-Version:0.17.4 Access-Control-Expose-Headers:ETag, Link, Retry-After, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval Access-Control-Allow-Origin:* Content-Security-Policy:default-src 'none' Strict-Transport-Security:max-age=31536000; includeSubdomains; preload X-Content-Type-Options:nosniff X-Frame-Options:deny X-XSS-Protection:1; mode=block X-Runtime-rack:0.019668 Vary:Accept-Encoding X-GitHub-Request-Id:1474:20A83:5CC0B6:7A7C1B:5AA36BC8 onResponse: <p>I am Jdqm.</p>d、POST方式提交流
RequestBody requestBody = new RequestBody() { @Nullable @Override public MediaType contentType() { return MediaType.parse("text/x-markdown; charset=utf-8"); } @Override public void writeTo(BufferedSink sink) throws IOException { sink.writeUtf8("I am Jdqm."); } }; 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()); } });e、POST提交文件
MediaType mediaType = MediaType.parse("text/x-markdown; charset=utf-8"); OkHttpClient okHttpClient = new OkHttpClient(); File file = new File("test.md"); Request request = new Request.Builder() .url("https://api.github.com/markdown/raw") .post(RequestBody.create(mediaType, file)) .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 { 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()); } });f、POST方式提交表单
OkHttpClient okHttpClient = new OkHttpClient(); RequestBody requestBody = new FormBody.Builder() .add("search", "Jurassic Park") .build(); Request request = new Request.Builder() .url("https://en.wikipedia.org/w/index.php") .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 { 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()); } });提交表单时,使用 RequestBody 的实现类FormBody来描述请求体,它可以携带一些经过编码的 key-value 请求体,键值对存储在下面两个集合中:
private final List<String> encodedNames; private final List<String> encodedValues;
3、封装okhttp
a、定义接口OnFunHttpCallBack
public interface OnFunHttpCallBack { void onFailure(int errorCode); void onSuccess(String url, String result); }b、HttpMethod.java
//okhttp3封装 public class HttpMethod { private final static String TAG = HttpMethod.class.getSimpleName(); private final static int TIME = 10000; public final static int NETWORK_ACCESS_ERROR = 0x0001; public final static int SERVER_BACK_ERROR = 0x0002; private static HttpMethod m_instance = null; private static OkHttpClient m_okHttpClient = null; /** * 单一实例 */ public static HttpMethod getInstance() { if (m_instance == null) { m_instance = new HttpMethod(); if (m_okHttpClient == null) { m_okHttpClient = new OkHttpClient(); //m_okHttpClient = new OkHttpClient.Builder().connectTimeout(TIME, TimeUnit.SECONDS).readTimeout(TIME, TimeUnit.SECONDS).build(); } } return m_instance; } private class HttpCallback { private String m_strUrl = ""; private OnFunHttpCallBack m_back_http = null; //任务的回调函数 public HttpCallback(String url, OnFunHttpCallBack back) { m_strUrl = url; m_back_http = back; } /** * AsyncHttp的回调函数 */ private Callback m_handler = new Callback() { @Override public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException { if(response.code() == 200){ String result = response.body().string(); if(m_back_http != null){ m_back_http.onSuccess(m_strUrl, result); } if (response.body()!=null){ response.body().close(); } Log.i(TAG, "HTTP-Response-Url: " + m_strUrl + "-----" + result); }else{ if(m_back_http != null){ m_back_http.onFailure(SERVER_BACK_ERROR); } Log.e(TAG, "HTTP-Request-Url: " + m_strUrl + " 服务器错误(Server error) " + response.code()); } } @Override public void onFailure(@NotNull Call call, @NotNull IOException e) { if(m_back_http != null){ m_back_http.onFailure(NETWORK_ACCESS_ERROR); } Log.e(TAG, "HTTP-Request-Url: " + m_strUrl + " 访问失败(Access failed)"); } }; } /** * 异步GET请求 * * @param url * 发送请求的URL * @param para * 请求参数,请求参数应该是name1=value1&name2=value2的形式。 * @return URL所代表远程资源的响应 */ public void clientGet(String url, String para, OnFunHttpCallBack back) { Log.i(TAG, "HTTP-Request-Url: " + url + "?" + para); String reqUrl = url; if(para != null && !para.equals("")){ reqUrl = url + "?" + para; } //执行get方法 Request request = new Request.Builder() .url(reqUrl) .get()//默认就是GET请求,可以不写 .build(); m_okHttpClient.newCall(request).enqueue(new HttpCallback(url, back).m_handler); } /** * POST方式提交表单 * * @param url * 发送请求的URL * @param para * 请求参数,请求参数应该是name1=value1&name2=value2的形式。 * @return URL所代表远程资源的响应 */ public void clientPost(String url, String para, OnFunHttpCallBack back) { Log.i(TAG, "HTTP-Request-Url: " + url + "?" + para); String[] tmp1 = null; String[] tmp2 = null; int size = 0; //构建表单参数 FormBody.Builder requestBuild=new FormBody.Builder(); //解析出各个参数 if (para != null && !para.equals("")) { tmp1 = para.split("&"); size = tmp1.length; for (int i = 0; i < size; i++) { tmp2 = tmp1[i].split("="); if (tmp2.length != 2) { //return; continue; } //设置请求的参数名和参数值 requestBuild.add(tmp2[0], tmp2[1]); } } //执行post方法 Request request = new Request.Builder() .url(url) .post(requestBuild.build()) .build(); m_okHttpClient.newCall(request).enqueue(new HttpCallback(url, back).m_handler); } /** * post文件上传 * * @param url * url * @param file * 文件 * @param back * 回调接口 */ public void upLoad(String url, File file, OnFunHttpCallBack back) { MediaType mediaType = MediaType.parse("text/x-markdown; charset=utf-8"); Request request = new Request.Builder() .url(url) .post(RequestBody.create(file, mediaType)) .build(); m_okHttpClient.newCall(request).enqueue(new HttpCallback(url, back).m_handler); } }c、HttpTask.java
public class HttpTask { private String m_strUrl = ""; private String m_strPara = ""; private File m_file = null; private OnFunHttpCallBack m_back_http = null;// 任务的回调函数 public HttpTask(String url, String para, OnFunHttpCallBack back) { m_strUrl = url; m_strPara = para; m_back_http = back; } public HttpTask(String url, File file, OnFunHttpCallBack back) { m_strUrl = url; m_file = file; m_back_http = back; } public void runPost() { HttpMethod.getInstance().clientPost(m_strUrl, m_strPara, m_back_http); } public void runGet() { HttpMethod.getInstance().clientGet(m_strUrl, m_strPara, m_back_http); } public void upLoad() { HttpMethod.getInstance().upLoad(m_strUrl, m_file, m_back_http); } }