okhttp是一个第三方类库,用于android中请求网络。这是一个开源项目,是安卓端最火热的轻量级框架,由移动支付Square公司贡献(该公司还贡献了Picasso和LeakCanary) 。用于替代HttpUrlConnection和Apache HttpClient(android API23 里已移除HttpClient)。

  1. implementation \'com.squareup.okhttp3:okhttp:4.4.0\'

我使用了http://www.sosoapi.com/ 来创建了一个访问接口,用来验证OkHttp是否请求成功。如果你有兴趣了解,可以直接进入网站,里面有详细的demo演示。后续我将不在赘述这段。

我在请求响应里添加了一段JSON数据:

  1. [
  2. {
  3. "name": "get测试",
  4. "content": "你成功获取了数据"
  5. }
  6. ]

这里我写一下解析JSON数据的方法,来解析get或者post得到的JSON数据。后续我将不在赘述这段。

  1. /**
  2. * JSON 解析方法
  3. * @param jsonData
  4. * @return
  5. */
  6. public String readJSONContent(String jsonData){
  7. try {
  8. StringBuffer sb = new StringBuffer();
  9. JSONArray jsonArray = new JSONArray(jsonData);
  10. for (int i=0;i<jsonArray.length();i++){
  11. JSONObject jsonObject = jsonArray.getJSONObject(i);
  12. sb.append(jsonObject.getString("name")+"\n");
  13. sb.append(jsonObject.getString("content")+"\n");
  14. }
  15. return sb.toString();
  16. } catch (JSONException e) {
  17. Log.e("JSONException错误", "readContent: "+e.toString());
  18. return e.toString();
  19. }
  20. }
  1. /**
  2. * 同步请求
  3. */
  4. public void synchro(){
  5. Thread thread = new Thread(new Runnable() {
  6. @Override
  7. public void run() {
  8. OkHttpClient okHttpClient = new OkHttpClient();//创建单例
  9. Request request = new Request.Builder()//创建请求
  10. .url("http://www.sosoapi.com/pass/mock/12003/test/gettest")
  11. .build();
  12. try {
  13. Response response = okHttpClient.newCall(request).execute();//执行请求
  14. mContent = response.body().string();//得到返回响应,注意response.body().string() 只能调用一次!
  15. runOnUiThread(new Runnable() {
  16. @Override
  17. public void run() {
  18. mtextView.setText(readJSONContent(mContent));
  19. }
  20. });
  21. } catch (IOException e) {
  22. e.printStackTrace();
  23. Log.e("OkHttpActivity", e.toString() );
  24. }
  25. }
  26. });
  27. thread.start();
  28. }

注意!response.body().string() 只能调用一次! 因为响应主体 RessponseBody 持有的资源可能会很大,所以 OkHttp 并不会将其直接保存到内存中,只是持有数据流连接。只有当我们需要时,才会从服务器获取数据并返回。同时,考虑到应用重复读取数据的可能性很小,所以将其设计为一次性流(one-shot),读取后即 \’关闭并释放资源\’

 

注意1:异步请求方式,请求的回调会在子线程里,所以如果需要更新UI你需要切换到主线程。且你不需要在new 一个线程包裹这个异步请求了。另外如何切换到主线程请使用 Handler 例子:

注意2:在异步请求方法里,请不要将 public void onResponse(Call call, final Response response)回调里的response回调数据放到UI线程里解析,因为有一个天坑,有可能在UI线程里解析的时候response里面却还没有塞入数据(我也觉得很神奇,不知道写okhttp的公司是怎么想的,为什么不处理完所有数据在提供回调)

创建异步请求

  1. /**
  2. * get异步请求
  3. */
  4. public void asynchronous(){
  5. OkHttpClient okHttpClient = new OkHttpClient();
  6. Request request = new Request.Builder()
  7. .url("http://www.sosoapi.com/pass/mock/12003/test/gettest")
  8. .build();
  9. okHttpClient.newCall(request).enqueue(new Callback() {
  10. @Override
  11. public void onFailure(Call call, IOException e) {
  12. //失败回调
  13. }
  14. @Override
  15. public void onResponse(Call call, final Response response) throws IOException {
                mContent = readJSONContent(response.body().string());//注意response.body().string() 只能调用一次!
  16. //响应成功,这个回调在子线程中,所以不需要创建线程
  17. if (response.isSuccessful()){
  18. //isSuccessful方法:如果代码位于(200…300)中,则返回true,这意味着请求已成功接收
  19. runOnUiThread(new Runnable() {
  20. @Override
  21. public void run() {
  22. try {
  23. //因为在子线程,所以我们需要回到主线程中更新UI数据
  24. mtextView.setText(mContent);
  25. } catch (IOException e) {
  26. e.printStackTrace();
  27. }
  28. }
  29. });
  30. }
  31. }
  32. });
  33. }

post请求也同时有同步与异步方法,与上面一致,所以这里就不展示了,下面我们来看看post请求发送

  1. /**
  2. * post请求
  3. */
  4. public void post(){
  5. new Thread(new Runnable() {
  6. @Override
  7. public void run() {
  8. //实例
  9. OkHttpClient okHttpClient = new OkHttpClient();
  10. //创建post请求数据表单
  11. RequestBody requestBody = new FormBody.Builder()
  12. .add("name","请求post")
  13. .add("password","123456")
  14. .build();
  15. //创建请求
  16. final Request request = new Request.Builder()
  17. .url("http://www.sosoapi.com/pass/mock/12003/test/posttest")
  18. .post(requestBody)//添加post请求
  19. .build();
  20. try {
  21. //发送请求得到响应
  22. final Response response = okHttpClient.newCall(request).execute();
  23. runOnUiThread(new Runnable() {
  24. @Override
  25. public void run() {
  26. try {
  27. mtextView.setText(readJSONContent(response.body().string()));//注意response.body().string() 只能调用一次!
  28. } catch (IOException e) {
  29. e.printStackTrace();
  30. }
  31. }
  32. });
  33. } catch (IOException e) {
  34. e.printStackTrace();
  35. }
  36. }
  37. }).start();
  38. }

效果图:

取消okhttp的网络请求很简单只需要

  1. call.cancel();

如何鉴别是网络异常还是主动取消,请求取消的回调在onFailure(Call call, IOException e)里回调,这个时候我们需要再次判断onFailure里回调的是我们自己主动取消的还是网络异常报错的

  1. mCall.enqueue(new Callback() {//发送请求
  2. @Override
  3. public void onFailure(final Call call, final IOException e) {
  4. if (call.isCanceled()){
  5. listener.onCancel();
  6. }else {
  7. listener.onFailure(call, e);
  8. }
  9. }
  10. //省略下面代码...

RequestBody是okhttp  post发送数据配置类.在这之前我们先了解下回顾一下body类型

 

http有四种body类型,Content-Type POST提交数据的方式:
  • application/x-www-form-urlencoded 表单数据
  • multipart/form-data 表单文件上传
  • application/json 序列化JSON数据
  • text/xml XML数据

这些body类型需要在http header头部就写上,但是okhttp不需要我们手动在header写上类型了.okhttp提供了FormBody和MultipartBody的类型,方便你的快速创建application/x-www-form-urlencoded 与 multipart/form-data

  1. /**
  2. * 此body是 默认application/x-www-form-urlencoded,你可以进入FormBody类查看,第一行静态常量就是这个
  3. */
  4. public void FormBody(){
  5. FormBody.Builder builder = new FormBody.Builder();
  6. builder.add("key","content");
  7. builder.build();
  8. }

 

  1. /**
  2. * multipart/form-data
  3. */
  4. public void MultipartBody(){
  5. RequestBody requestBody = new RequestBody() {
  6. @Override
  7. public MediaType contentType() {
  8. return null;
  9. }
  10. @Override
  11. public void writeTo(BufferedSink sink) throws IOException {
  12. //上传流 sink.write()
  13. }
  14. };
  15. MultipartBody.Builder builder = new MultipartBody.Builder();
  16. builder.addFormDataPart("key","content");//表单数据
  17. builder.addFormDataPart("file_key","/path/image.jpg",requestBody);//文件数据
  18. MultipartBody multipartBody = builder.build();
  19. }

当然,有特殊需求你还可以添加手动其他body类型,create也支持好几种数据的上传形式

  1. /**
  2. * 手动创建4种body
  3. */
  4. public void RequestBody(){
  5. RequestBody applicationFormUrlencodedBody = RequestBody.create(MediaType.parse("application/x-www-form-urlencoded; charset=utf-8"),new String("demo").getBytes());
  6. RequestBody multipartBody = RequestBody.create(MediaType.parse("multipart/form-data; charset=utf-8"),new File("/path/image.jpg"));
  7. RequestBody jsonBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"),"content");
  8. RequestBody textbody = RequestBody.create(MediaType.parse("text/xml; charset=utf-8"),"content");
  9. }
  1. public class OkHttpClientCreate {
  2. private static final boolean IS_RETRY = false;//失败是否重连
  3. private static final int CONNECT_TIME = 10;//设置连接超时时间 单位:秒
  4. private static final int READ_TIME = 10;//设置读取超时时间
  5. private static final int WRITE_TIME = 10;//设置写入超时间
  6. private static OkHttpClient mOkHttpClient;
  7. public static OkHttpClient CreateClient(){
  8. if (mOkHttpClient == null){
  9. return mOkHttpClient = new OkHttpClient.Builder()
  10. .retryOnConnectionFailure(IS_RETRY)
  11. .connectTimeout(CONNECT_TIME,TimeUnit.SECONDS)//连接超时
  12. .readTimeout(READ_TIME,TimeUnit.SECONDS)//读取超时
  13. .writeTimeout(WRITE_TIME,TimeUnit.SECONDS)//写入超时
  14. // .callTimeout()//呼叫超时,设置此参数为整体流程请求的超时时间
  15. // .addInterceptor() //设置拦截器
  16. // .authenticator() //设置认证器
  17. // .proxy()//设置代理
  18. .build();
  19. }
  20. return mOkHttpClient;
  21. }
  22. public static void destroy(){
  23. mOkHttpClient = null;
  24. }
  25. }

版权声明:本文为guanxinjing原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://www.cnblogs.com/guanxinjing/p/9708575.html