Okhttp3使用及Utils封装

现在Okhttp作为一款很实用的高效的Http客户端,它使用起来高效便捷。

OkHttp3的基本特性:

http://square.github.io/okhttp/这是官网URL

1.支持HTTP/2,允许多个请求共享一个socket连接。

2.减少请求延时。

3.GZIP压缩服务器响应数据的大小等。

ps:详情请关注官网,我在使用中也只是比赛时研究过一段时间,将爬坑经历写在微博上供大家参考。

话不多说,上代码:

package com.example.hgz.myapplication;

import android.util.Log;
import java.io.IOException;
import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;


public class OkHttpUtils {
    private String backInfo;

    public String getInfo(String url) {
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder()
                .url(url)
                .build();
        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.d("info:", "filed");
            }
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response.isSuccessful()) {
                    Log.d("info:", "success");
                    Log.d("code:", "response.code()==" + response.code());

                    backInfo= response.body().string();
//                    请勿多次调用 response.body().string() 会出现: java.lang.IllegalStateException: closed错
                    Log.d("ResponseBody:", "response.body().string()==" + backInfo);
                }
            }
        });

        return backInfo;
    }

    public String postInfo(String url,String json){
        OkHttpClient client = new OkHttpClient();//创建OkHttpClient对象。

        MediaType JSON = MediaType.parse("application/json; charset=utf-8");//数据类型为json格式,

        RequestBody body = RequestBody.create(JSON, json);
        Request request = new Request.Builder()
                .url(url)
                .post(body)
                .build();

        client.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.d("info:", "filed");
            }
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                if (response.isSuccessful()) {//回调的方法执行在子线程。
                    Log.d("info:", "success");
                    Log.d("code:", "response.code()==" + response.code());
                    backInfo= response.body().string();
//                    请勿多次调用 response.body().string() 会出现: java.lang.IllegalStateException: closed错
                    Log.d("ResponseBody:", "response.body().string()==" + backInfo);
                }
            }
        });
        return backInfo;
    }
}

PS:这是一个封装的util,但是这个工具类仅供参考使用,可能会出现问题。

如何使用Okhttp3:

1.添加okhttp封装的okhttp的jar包和okhttp的iojar包。

或者引用github上的官网提供的依赖。

compile 'com.squareup.okhttp3:okhttp:3.2.0'

compile 'com.squareup.okio:okio:1.7.0'

ps:如需最新依赖,请去官网查阅使用。

2.最重要的是在Android的配置文件中加入网络权限:

3.在Android平台开发中,由于涉及线程安全,需要在子线程中进行网络访问,所以涉及线程方面的知识,话不多说,上代码:

package com.example.hgz.myapplication;

import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

public class OkHttpThreadTest extends Thread{
    private Handler handler;

    public OkHttpThreadTest(Handler handler) {
        this.handler = handler;
    }

    @Override
    public void run() {
        super.run();
        OkHttpUtils utils = new OkHttpUtils();
        String time = utils.getInfo("http://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp");
        if (time!=null){
            Log.e("time",time);
            Bundle build = new Bundle();
            build.putString("time",time);
            Message message = handler.obtainMessage();
            message.setData(build);
            handler.sendMessage(message);
        }
    }
}

这里调用的是淘宝的时间API。

当然这里涉及到了如何将信息从子线程中传输到UI线程中,这里就使用了Handler消息处理机制。通过同一个对象的handler通过

handler.obtainMessage();消息池的概念进行消息传输。

4.在MainActivity中通过

 class Myhandler extends Handler{
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            textView.setText(msg.getData().getString("time"));
        }
    }
msg.getData().getString("time")通过键值对中的键来获取消息池中存放的数据。

5.最后开启线程进行跑起来。

 Handler handler = new Myhandler();
        new OkHttpThreadTest(handler).start();

切记一定要start()线程,不然一切无用功。

注:如果需要定时请求不断请求更新,除了设置timer定时器的方式进行,可以通过while的死循环进行,下面上修改上文线程中的代码案例:

package com.example.hgz.myapplication;

import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;

public class OkHttpThreadTest extends Thread{
    private Handler handler;

    public OkHttpThreadTest(Handler handler) {
        this.handler = handler;
    }

    @Override
    public void run() {
        super.run();
        OkHttpUtils utils = new OkHttpUtils();
      while (true){
          try {
//              线程每隔1000毫秒执行一次
              Thread.sleep(1000);
          } catch (InterruptedException e) {
              e.printStackTrace();
          }
//          切记将utils写在while的死循环里面,否者emmmm你懂的
          String time = utils.getInfo("http://api.m.taobao.com/rest/api3.do?api=mtop.common.getTimestamp");
          if (time!=null){
              Log.e("time",time);
              Bundle build = new Bundle();
              build.putString("time",time);
              Message message = handler.obtainMessage();
              message.setData(build);
              handler.sendMessage(message);
          }
      }
    }
}

基本使用到此结束,如果有问题可以留言,现在说采坑中遇到的一些小问题。

1.response.body().string();重复调用出错问题。、

java.lang.IllegalStateException: closed,我们经常会在获取值or传至的过程中打个Log或sout出来,由于有打Log的习惯,所以爆出了上述的错误,范围的response.body消息体在使用中不可以重复调用。原因很简单,我们先查看源码:

public final String string() throws IOException {
    BufferedSource source = source();
    try {
      Charset charset = Util.bomAwareCharset(source, charset());
      return source.readString(charset);
    } finally {
      Util.closeQuietly(source);
    }
  }
这是Response下的Response下的一段代码,很简洁的写出了string后已经关闭了流,所以你再次调用时,流已经关闭了,所以无法再次调用,调用出来也是抛出的异常。

ResponseBody代码:

//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//

package okhttp3;

import java.io.Closeable;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.nio.charset.Charset;
import okhttp3.internal.Util;
import okio.Buffer;
import okio.BufferedSource;

public abstract class ResponseBody implements Closeable {
    private Reader reader;

    public ResponseBody() {
    }

    public abstract MediaType contentType();

    public abstract long contentLength();

    public final InputStream byteStream() {
        return this.source().inputStream();
    }

    public abstract BufferedSource source();

    public final byte[] bytes() throws IOException {
        long contentLength = this.contentLength();
        if (contentLength > 2147483647L) {
            throw new IOException("Cannot buffer entire body for content length: " + contentLength);
        } else {
            BufferedSource source = this.source();

            byte[] bytes;
            try {
                bytes = source.readByteArray();
            } finally {
                Util.closeQuietly(source);
            }

            if (contentLength != -1L && contentLength != (long)bytes.length) {
                throw new IOException("Content-Length and stream length disagree");
            } else {
                return bytes;
            }
        }
    }

    public final Reader charStream() {
        Reader r = this.reader;
        return r != null ? r : (this.reader = new InputStreamReader(this.byteStream(), this.charset()));
    }

    public final String string() throws IOException {
        return new String(this.bytes(), this.charset().name());
    }

    private Charset charset() {
        MediaType contentType = this.contentType();
        return contentType != null ? contentType.charset(Util.UTF_8) : Util.UTF_8;
    }

    public void close() {
        Util.closeQuietly(this.source());
    }

    public static ResponseBody create(MediaType contentType, String content) {
        Charset charset = Util.UTF_8;
        if (contentType != null) {
            charset = contentType.charset();
            if (charset == null) {
                charset = Util.UTF_8;
                contentType = MediaType.parse(contentType + "; charset=utf-8");
            }
        }

        Buffer buffer = (new Buffer()).writeString(content, charset);
        return create(contentType, buffer.size(), buffer);
    }

    public static ResponseBody create(MediaType contentType, byte[] content) {
        Buffer buffer = (new Buffer()).write(content);
        return create(contentType, (long)content.length, buffer);
    }

    public static ResponseBody create(final MediaType contentType, final long contentLength, final BufferedSource content) {
        if (content == null) {
            throw new NullPointerException("source == null");
        } else {
            return new ResponseBody() {
                public MediaType contentType() {
                    return contentType;
                }

                public long contentLength() {
                    return contentLength;
                }

                public BufferedSource source() {
                    return content;
                }
            };
        }
    }
}

有兴趣的小伙伴可以看看人家封装的源码,其实挺有意思的。

2.在使用工具类的回调方法中会出一大堆麻烦,贴的第一个工具类是为了高大上才整的,但是没有我下面贴的这个来的实在:

package com.jmi.jingsai;

import android.os.Handler;

import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.util.concurrent.TimeUnit;

import okhttp3.Call;
import okhttp3.Callback;
import okhttp3.MediaType;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;
import okhttp3.Response;

/**
 * Created by Huguanzhong on 2018/3/23.
 */

public class OkHttpUtil {
    public String getPostInfo(String url,String json) {
        String s = null;
        MediaType mediaType = MediaType.parse("application/json");
        OkHttpClient client = new OkHttpClient();
        RequestBody body = RequestBody.create(mediaType,json);
        Request request = new Request.Builder().url(url).post(body).build();
        try {
            Response response = client.newCall(request).execute();
            String  str = response.body().string();
             JSONObject jsonObject = new JSONObject(str);
             s = jsonObject.getString("value");

        } catch (IOException e) {
            e.printStackTrace();
        } catch (JSONException e) {
            e.printStackTrace();
        }
        return  s;
    }
    public String getInfo(String url,String json) throws IOException {
        String s = null;
        MediaType mediaType = MediaType.parse("application/json");
        OkHttpClient client = new OkHttpClient();
        RequestBody body = RequestBody.create(mediaType,json);
        Request request = new Request.Builder().url(url).post(body).build();

            Response response = client.newCall(request).execute();
              s = response.body().string();



        return  s;
    }
    public String getWeather(String url){
        String s = null;
        OkHttpClient client = new OkHttpClient();
        Request request = new Request.Builder().url(url).build();

        try {
            Response response =client.newCall(request).execute();
            s = response.body().string();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return s;
    }

}

虽然这代码写得糟,但是很实用有没有。return很轻松。

3.在线程执行时,需要在子线程中执行或者在UI线程中执行。

子线程中执行不多说了,UI线程中执行如下:

runOnUiThread(new Runnable() {
    @Override
    public void run() {
        //执行方法
    }
});

个人不建议,因为不安全。但是安全又是个宽泛的概念,具体怎样才安全,谁知道呢,对吧。这篇博客也写完了,也只是浅显的介绍一下okhttp使用和如何爬坑,因为现在在家无法访问外网,等我有机会访问外网时,会具体详细的阐述一下Okhttp的使用流程。

你可能感兴趣的:(Okhttp3使用及Utils封装)