Okhttp使用和源码分析一(OkHttp2.x用法)

由Square团队发明的网络框架OkHttp,想必目前火过移动互联网半边天。从由Google发明的Volley停止了更新后,而OkHttp得到了官方的认可,并在不断优化。上篇文章我们简单分析和演示了Volley的源码,不过再怎么分装,OkHttp都会以强大的功能和网络请求的优化,怒甩Volley几条街!!!

首先根据本人自己的理解和使用总结,OkHttp的优势由以下这些(实在太多了):
1.会根据连接端口的时效性和网络状态的稳定性自动恢复连接。如果您的服务器配置了多个IP地址,当第一个IP连接失败的时候,OkHttp会自动尝试下一个IP;
2.OkHttp还处理了代理服务器问题和SSL握手失败问题,默认情况下,OKHttp会自动处理常见的网络问题,像二次连接、SSL的握手问题,如果你的应用程序中集成了OKHttp,Retrofit默认会使用OKHttp处理其他网络层请求;从Android4.4开始HttpURLConnection的底层实现采用的是okHttp
3.OKHttp是Android版Http客户端。非常高效,支持SPDY、连接池、GZIP和 HTTP 缓存。
4.从Android4.4开始HttpURLConnection的底层实现采用的是okHttp ,缓存响应避免重复的网络请求;
5.OkHttp使用Okio来大大简化数据的访问与存储,Okio是一个增强 java.io 和 java.nio的库,提高了数据的操作效率,相比Volley,Okio更具专向性,坚持了“逻辑与I/O分离”的原则;
6.更加灵活地支持了任务的取消策略;
7.利用Soket的传输优点,完美的扮演着传输层的角色;
…….
诸多优点,只有用了才知道!

目前,该封装库志支持:
• 一般的get请求
• 一般的post请求
• 基于Http的文件上传
• 文件下载
• 上传下载的进度回调
• 加载图片
• 支持请求回调,直接返回对象、对象集合
• 支持session的保持
• 支持自签名网站https的访问,提供方法设置下证书就行
• 支持取消某个请求

OkHttp目前主要有OkHttp2.x和OkHttp3.x两个版本,下面我们一一分析:

OkHttp2.x用法全解析

1.Android Studio 配置gradle:

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

2.异步GET请求

private void getAsynHttp() {
    //创建okHttpClient对象
    OkHttpClient mOkHttpClient = new OkHttpClient();
    final Request request = new Request.Builder()
            .url("http://www.baidu.com").tag(url)
            .build();
    Call call = mOkHttpClient.newCall(request);
    call.enqueue(new Callback() {
        @Override
        public void onFailure(Request request, IOException e) {
        }
        @Override
        public void onResponse(final Response response) throws IOException {
            String str = response.body().string();
            Log.i("yzw", str);
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(getApplication(), "请求成功", Toast.LENGTH_SHORT).show();
                }
            });
        }
    });
}

运行程序log打印出来的是百度首页的html文件,基本的步骤很简单,就是创建OkHttpClient、Request和Call,最后调用Call的enqueue()方法。但是每次这么写肯定是很麻烦,肯定是要进行封装的。需要注意的是onResponse回调并不是在UI线程。

3.同步GET请求

private String getSyncHttp() throws IOException{
       OkHttpClient mOkHttpClient = new OkHttpClient();
       //创建请求Request
       final Request request = new Request.Builder()
               .url("http://www.baidu.com").tag(url)
               .build();
       Call call = mOkHttpClient.newCall(request);
       Response mResponse=call.execute();
       if (mResponse.isSuccessful()) {
           return mResponse.body().string();
       } else {
           throw new IOException("Unexpected code " + mResponse);
       }
   }

同步Get请求和异步调用区别就是调用了call的execute()方法。

4.异步POST请求

private void postAsynHttp() {
    OkHttpClient mOkHttpClient = new OkHttpClient();
    RequestBody formBody = new FormEncodingBuilder()
            .add("size", "10")
            .build();
    Request request = new Request.Builder()
            .url("http://api.1-blog.com/biz/bizserver/article/list.do").tag(url)
            .post(formBody)
            .build();
    Call call = mOkHttpClient.newCall(request);
    call.enqueue(new Callback() {
        @Override
        public void onFailure(Request request, IOException e) {
        }
        @Override
        public void onResponse(Response response) throws IOException {
            String str = response.body().string();
            Log.i("yzw", str);
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    Toast.makeText(getApplicationContext(), "请求成功", Toast.LENGTH_SHORT).show();
                }
            });
        }
    });
}

post与get不同的就是要要创建RequestBody并传进Request中,同样onResponse回调不是在UI线程。

5.请求缓存设置
首先我们设置缓存路径和大小并设置给OkHttpClient:
mOkHttpClient = new OkHttpClient();
File sdcache = getExternalCacheDir();
int cacheSize = 10 * 1024 * 1024;
mOkHttpClient.setCache(new Cache(sdcache.getAbsoluteFile(), cacheSize));

接下来异步GET请求baidu:

private void getAsynHttp() {
       //创建请求Request
       final Request request = new Request.Builder()
               .url("http://www.baidu.com").tag(url)
               .build();
       Call call = mOkHttpClient.newCall(request);
       call.enqueue(new Callback() {
           @Override
           public void onFailure(Request request, IOException e) {
           }
           @Override
           public void onResponse(final Response response) throws IOException {
               if (null != response.cacheResponse()) {
                   String str = response.cacheResponse().toString();
                   Log.i("yzw", "cache---" + str);
               } else {
                   response.body().string();
                   String str=response.networkResponse().toString();
                   Log.i("yzw", "network---" + str);
               }
               runOnUiThread(new Runnable() {
                   @Override
                   public void run() {
                       Toast.makeText(getApplicationContext(), "请求成功", Toast.LENGTH_SHORT).show();
                   }
               });
           }
       });
   }

第一次请求会请求网络得到数据,第二次以及后面的请求则会从缓存中取出数据:
这里写图片描述
当然也有种情况是有的请求每次都需要最新的数据,则在创建Request,来设置cacheControl为“CacheControl.FORCE_NETWORK”,用来表示请求会一直请求网络得到数据:

final Request request = new Request.Builder()
              .url("http://www.baidu.com")
              .cacheControl(CacheControl.FORCE_NETWORK)
              .build();

运行程序结果为:
这里写图片描述

6.设置超时时间

另外我们也需要设置超时的时间用来处理各种网络超时的情况,超时的原因可能是网络问题也可能是服务器响应慢等问题,OkHttp当然不会忽略这一点,它支持连接、读取和写入超时的时间设置:

mOkHttpClient = new OkHttpClient();
mOkHttpClient.setConnectTimeout(15, TimeUnit.SECONDS);
mOkHttpClient.setWriteTimeout(20, TimeUnit.SECONDS);
mOkHttpClient.setReadTimeout(20, TimeUnit.SECONDS);

7.取消请求:

/**
     * 取消某单个请求任务
     */
    public void cancelRequest(CharSequence url) {
        try {
            if (mOkHttpClient != null)
                mOkHttpClient.cancel(url);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 取消全部请求任务
     */
    public void cancelAllRequest() {
        try {
            //handler.removeCallbacksAndMessages(null);
            //销毁这时候任务执行的线程池对象
            mOkHttpClient().getExecutorService().shutdown();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

这里分为取消单个任务和取消全部任务。取消单个任务主要是根据创建Request对象是加的tag作为每个执行对象Call的标记;mOkHttpClient.cancel(“’)方法源码是任务调度器Dispatcher中的方法:

/** Cancel all calls with the tag {@code tag}. */
  public synchronized void cancel(Object tag) {
    for (AsyncCall call : readyCalls) {
      if (Util.equal(tag, call.tag())) {
        call.cancel();
      }
    }

    for (AsyncCall call : runningCalls) {
      if (Util.equal(tag, call.tag())) {
        call.get().canceled = true;
        HttpEngine engine = call.get().engine;
        if (engine != null) engine.cancel();
      }
    }

    for (Call call : executedCalls) {
      if (Util.equal(tag, call.tag())) {
        call.cancel();
      }
    }
  }

而任务的全部取消这里采用的是直接关闭任务调度器中的线程池对象

8.代码的封装:

/**
 * Created by ethank on 17/5/19.
 */

public class OkHttp2Engine {

    private static OkHttp2Engine mInstance;

    private OkHttpClient okHttpClient = null;
    private int DEFAULT_HTTP_TIMEOUT = 15_000;
    private int SIZE_OF_CACHE = 5 * 1024 * 1024;
    private CharSequence StringEncode = "utf-8";
    private static final MediaType Json = MediaType.parse("application/json; charset=utf-8");

    private CharSequence POST = "post";
    private CharSequence GET = "get";

    private Handler handler = null;

    private boolean hasCache = true;

    public OkHttp2Engine() {
        super();
        handler = new Handler(Looper.getMainLooper());
        okHttpClient = new OkHttpClient();
        okHttpClient.setConnectTimeout(DEFAULT_HTTP_TIMEOUT, TimeUnit.SECONDS);// 单位秒
        okHttpClient.setReadTimeout(DEFAULT_HTTP_TIMEOUT, TimeUnit.SECONDS);
        okHttpClient.setWriteTimeout(DEFAULT_HTTP_TIMEOUT, TimeUnit.SECONDS);
        File cacheDirectory = new File(DefaultApplication.getInstance().getExternalCacheDir(), "HttpCache");
        Cache cache = new Cache(cacheDirectory, SIZE_OF_CACHE);
        okHttpClient.setCache(cache);
    }

    public static OkHttp2Engine getInstance() {
        if (mInstance == null) {
            synchronized (OkHttp2Engine.class) {
                if (mInstance == null) {
                    mInstance = new OkHttp2Engine();
                }
            }
        }
        return mInstance;
    }

    public <T> void fetchStringPost(CharSequence url, T resultBean, Map<CharSequence, CharSequence> map, FetchDataInterface fetchDatainterface) {
        fetchString(url.toString(), resultBean, map, POST, false, null, fetchDatainterface);
    }

    public <T> void fetchStringGet(CharSequence url, T resultBean, Map<CharSequence, CharSequence> map, FetchDataInterface fetchDatainterface) {
        fetchString(url.toString(), resultBean, map, GET, false, null, fetchDatainterface);
    }

    public <T> void fetchStringAsyncPost(CharSequence url, T resultBean, Map<CharSequence, CharSequence> map, FetchDataInterface fetchDatainterface) {
        AsyncfetchString(url.toString(), resultBean, map, POST, false, null, fetchDatainterface);
    }

    public <T> void fetchStringAsyncGet(CharSequence url, T resultBean, Map<CharSequence, CharSequence> map, FetchDataInterface fetchDatainterface) {
        AsyncfetchString(url.toString(), resultBean, map, GET, false, null, fetchDatainterface);
    }

    public <T> void fetchStringPostJson(CharSequence url, T resultBean, CharSequence json, FetchDataInterface fetchDatainterface) {
        fetchString(url.toString(), resultBean, null, POST, true, json, fetchDatainterface);
    }

    public <T> void fetchStringAsyncPostJson(CharSequence url, T resultBean, CharSequence json, FetchDataInterface fetchDatainterface) {
        AsyncfetchString(url.toString(), resultBean, null, POST, true, json, fetchDatainterface);
    }

    public void setOkHttpCache(boolean hasCache, Context mContext) {
        this.hasCache = hasCache;
        if (hasCache) {
            File cacheDirectory = new File(mContext.getExternalCacheDir(), "HttpCache");
            Cache cache = new Cache(cacheDirectory, SIZE_OF_CACHE);
            okHttpClient.setCache(cache);
        }
    }

    public boolean isHasCache() {
        return hasCache;
    }

    /**
     * 取消某单个请求任务
     */
    public void cancelRequest(CharSequence url) {
        try {
            if (okHttpClient != null)
                okHttpClient.cancel(url);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 取消全部请求任务
     */
    public void cancelAllRequest() {
        try {
            handler.removeCallbacksAndMessages(null);
            //销毁这时候任务执行的线程池对象
            okHttpClient.getDispatcher().getExecutorService().shutdown();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 回调接口
     */
    public interface FetchDataInterface {
        <T> void successful(T result);

        void failed(CharSequence message);
    }

    /**
     * 同步请求
     */
    private <T> void fetchString(CharSequence url, T resultBean, Map<CharSequence, CharSequence> map, CharSequence method, boolean isSendJson, CharSequence json, FetchDataInterface fetchDatainterface) {
        try {
            Request request = null;
            //HashMap<CharSequence, CharSequence> pMap = new HashMap<>();
            if (method.equals(POST)) {
                RequestBody body = null;
                if (isSendJson) {
                    body = RequestBody.create(Json, json.toString());
                } else {
                    //pMap.put("v", "1.0");
                    //pMap.put("param", JSONObject.toJSONString(map));
                    body = mapToRequestBody(map);
                }
                if (isHasCache())
                    request = new Request.Builder().tag(url).url(new URI(url.toString()).toURL()).post(body).build();
                else {
                    request = new Request.Builder().tag(url).url(new URI(url.toString()).toURL()).cacheControl(CacheControl.FORCE_NETWORK).post(body).build();
                }
            } else {
                //pMap.put("v", "1.0");
                //CharSequence param = setMapToParam(map);
                //pMap.put("param", param);
                if (isHasCache())
                    request = new Request.Builder().tag(url).url(new URI(builderGetUri(url.toString(), map).toString()).toURL()).get().build();
                else
                    request = new Request.Builder().tag(url).url(new URI(builderGetUri(url.toString(), map).toString()).toURL()).cacheControl(CacheControl.FORCE_CACHE).get().build();
            }
            Response response = okHttpClient.newCall(request).execute();
            if (null == response || !response.isSuccessful()) {
                sendCallBack("response isnull", false, fetchDatainterface);
                return;
            }
            byte[] bytes = response.body().bytes();
            if (null == bytes) {
                sendCallBack("responsebody isnull", false, fetchDatainterface);
                return;
            }
            //统一转码,防止出现乱码
            String result = new String(bytes, StringEncode.toString());
            if (TextUtils.isEmpty(result)) {
                sendCallBack("strcode isnull", false, fetchDatainterface);
                return;
            }

            /**
             * 判断返回的是否是json格式的数据
             */
            JSONObject jsonString = JSON.parseObject(result);
            T t = (T) JSON.parseObject(jsonString.toString(), resultBean.getClass());
            sendCallBack(t, true, fetchDatainterface);
        } catch (Exception e) {
            e.printStackTrace();
            sendCallBack(e.getMessage(), false, fetchDatainterface);
        }
    }

    /**
     * 异步请求
     */
    private <T> void AsyncfetchString(final CharSequence url, final T resultBean, Map<CharSequence, CharSequence> map, CharSequence method, boolean isSendJson, CharSequence json, final FetchDataInterface fetchDatainterface) {
        try {
            Request request = null;
            //HashMap<CharSequence, CharSequence> pMap = new HashMap<>();
            if (method.equals(POST)) {
                RequestBody body = null;
                if (isSendJson) {
                    body = RequestBody.create(Json, json.toString());
                } else {
                    //pMap.put("v", "1.0");
                    //pMap.put("param", JSONObject.toJSONString(map));
                    body = mapToRequestBody(map);
                }
                if (isHasCache())
                    request = new Request.Builder().tag(url).url(new URI(url.toString()).toURL()).post(body).build();
                else
                    request = new Request.Builder().tag(url).url(new URI(url.toString()).toURL()).cacheControl(CacheControl.FORCE_CACHE).post(body).build();
            } else {
                //pMap.put("v", "1.0");
                //CharSequence param = setMapToParam(map);
                //pMap.put("param", param);
                if (isHasCache())
                    request = new Request.Builder().tag(url).url(new URI(builderGetUri(url.toString(), map).toString()).toURL()).get().build();
                else
                    request = new Request.Builder().tag(url).url(new URI(builderGetUri(url.toString(), map).toString()).toURL()).cacheControl(CacheControl.FORCE_CACHE).get().build();
            }
            okHttpClient.newCall(request).enqueue(new Callback() {

                @Override
                public void onResponse(Response response) throws IOException {
                    if (null == response || !response.isSuccessful()) {
                        sendCallBack("response isnull", false, fetchDatainterface);
                        return;
                    }
                    byte[] bytes = response.body().bytes();
                    if (null == bytes) {
                        sendCallBack("responsebody isnull", false, fetchDatainterface);
                        return;
                    }
                    //统一转码,防止出现乱码
                    String result = new String(bytes, StringEncode.toString());
                    if (TextUtils.isEmpty(result)) {
                        sendCallBack("strcode isnull", false, fetchDatainterface);
                        return;
                    }
                    /**
                     * 判断返回的是否是json格式的数据
                     */
                    try {
                        JSONObject jsonString = JSON.parseObject(result);
                        T t = (T) JSON.parseObject(jsonString.toString(), resultBean.getClass());
                        sendCallBack(t, true, fetchDatainterface);
                    } catch (Exception e) {
                        e.printStackTrace();
                        sendCallBack(e.getMessage(), false, fetchDatainterface);
                    }
                }

                @Override
                public void onFailure(Request arg0, IOException arg1) {
                    sendCallBack(arg1.getMessage(), false, fetchDatainterface);
                }
            });
        } catch (Exception e) {
            e.printStackTrace();
            sendCallBack(e.getMessage(), false, fetchDatainterface);
        }
    }

    private RequestBody mapToRequestBody(Map<CharSequence, CharSequence> kv) throws IOException {
        FormEncodingBuilder formBody = new FormEncodingBuilder();
        for (CharSequence key : kv.keySet()) {
            formBody.add(key.toString(), kv.get(key).toString());
        }
        return formBody.build();
    }

    private CharSequence setMapToParam(Map<CharSequence, CharSequence> hashMap) {
        StringBuilder param = new StringBuilder();
        if (hashMap == null || hashMap.size() == 0) {
            return "";
        }
        for (Map.Entry<CharSequence, CharSequence> entry : hashMap.entrySet()) {
            // 如果请求参数中有中文,需要进行URLEncoder编码
            if (entry.getValue() != null) {
                try {
                    param.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue().toString(), StringEncode.toString()));
                    param.append("&");
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        }
        if (param.length() > 0) {
            param.deleteCharAt(param.length() - 1);
        }
        return param.toString();
    }

    private CharSequence builderGetUri(CharSequence uri, Map<CharSequence, CharSequence> map) {
        StringBuilder sb = new StringBuilder();
        try {
            while (uri.toString().endsWith("/")) {
                try {
                    uri = uri.toString().substring(0, uri.length() - 1);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
            sb.append(uri).append("?");
            if (map != null && map.size() != 0) {
                for (Map.Entry<CharSequence, CharSequence> entry : map.entrySet()) {
                    // 如果请求参数中有中文,需要进行URLEncoder编码
                    sb.append(entry.getKey()).append("=").append(URLEncoder.encode(entry.getValue().toString(), StringEncode.toString()));
                    sb.append("&");
                }
                sb.deleteCharAt(sb.length() - 1);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        Log.d("builderGetUri", sb.toString());
        return sb.toString();
    }

    /**
     * 文件上传
     *
     * @param url                上传的服务器地址
     * @param file               上传的本地文件
     * @param params             上传文件时带的参数
     * @param fetchDatainterface 上传完成后的回调接口
     */
    public void uploadFile(CharSequence url, File file, Map<CharSequence, CharSequence> params, final FetchDataInterface fetchDatainterface) throws Exception {
        OkHttpClientManager.Param[] value = new OkHttpClientManager.Param[params.size()];
        int sign = 0;
        for (CharSequence kv : params.keySet()) {
            value[sign] = new OkHttpClientManager.Param(kv.toString(), params.get(kv).toString());
            sign++;
        }
        OkHttpClientManager.postAsyn(okHttpClient, url.toString(), new OkHttpClientManager.ResultCallback<CharSequence>() {

            @Override
            public void onError(Request request, Exception e) {
                sendCallBack(e.getMessage(), false, fetchDatainterface);
            }

            @Override
            public void onResponse(CharSequence result) {
                sendCallBack(result, true, fetchDatainterface);
            }
        }, file, "mFile", value);
    }

    /**
     * 文件下载
     *
     * @param url                下载的服务器地址
     * @param localSavePath      下载后保存的本地地址
     * @param fetchDatainterface 下载完成后的回调接口
     */
    public void downloadFile(CharSequence url, CharSequence localSavePath, final FetchDataInterface fetchDatainterface) throws Exception {
        OkHttpClientManager.downloadAsyn(okHttpClient, url.toString(), localSavePath.toString(),
                new OkHttpClientManager.ResultCallback<String>() {
                    @Override
                    public void onError(Request request, Exception e) {
                        sendCallBack(e.getMessage(), false, fetchDatainterface);
                    }

                    @Override
                    public void onResponse(String response) {
                        //文件下载成功,这里回调的reponse为文件的absolutePath
                        sendCallBack(response, true, fetchDatainterface);
                    }
                });
    }

    private <T> void sendCallBack(final T result, final boolean isSccessful, final FetchDataInterface fetchDatainterface) {
        handler.post(new Runnable() {
            @Override
            public void run() {
                if (isSccessful)
                    fetchDatainterface.successful(result);
                else
                    fetchDatainterface.failed(result.toString());
            }
        });
    }

    /**
     * 图片下载并展示
     *
     * @param image 展示的控件
     * @param url   下载的地址
     */
    public void downloadImgShowImageView(ImageView image, CharSequence url) {
        OkHttpClientManager.displayImage(okHttpClient, image, url.toString());
    }
}

OkHttpClientManager.java

public class OkHttpClientManager {
    private static OkHttpClientManager mInstance;
    private OkHttpClient mOkHttpClient;
    private Handler mDelivery;
    private Gson mGson;

    private static final String TAG = "OkHttpClientManager";

    private OkHttpClientManager(OkHttpClient mOkHttpClient) {
        //cookie enabled
        this.mOkHttpClient = mOkHttpClient;
        mOkHttpClient.setCookieHandler(new CookieManager(null, CookiePolicy.ACCEPT_ORIGINAL_SERVER));
        mDelivery = new Handler(Looper.getMainLooper());
        mGson = new Gson();
    }

    public static OkHttpClientManager getInstance(OkHttpClient mOkHttpClient) {
        if (mInstance == null) {
            synchronized (OkHttpClientManager.class) {
                if (mInstance == null) {
                    mInstance = new OkHttpClientManager(mOkHttpClient);
                }
            }
        }
        return mInstance;
    }

    /**
     * 同步的Get请求
     *
     * @param url
     * @return Response
     */
    private Response _getAsyn(String url) throws IOException {
        final Request request = new Request.Builder()
                .url(url)
                .build();
        Call call = mOkHttpClient.newCall(request);
        Response execute = call.execute();
        return execute;
    }

    /**
     * 同步的Get请求
     *
     * @param url
     * @return 字符串
     */
    private String _getAsString(String url) throws IOException {
        Response execute = _getAsyn(url);
        return execute.body().string();
    }


    /**
     * 异步的get请求
     *
     * @param url
     * @param callback
     */
    private void _getAsyn(String url, final ResultCallback callback) {
        final Request request = new Request.Builder()
                .url(url)
                .build();
        deliveryResult(callback, request);
    }


    /**
     * 同步的Post请求
     *
     * @param url
     * @param params post的参数
     * @return
     */
    private Response _post(String url, Param... params) throws IOException {
        Request request = buildPostRequest(url, params);
        Response response = mOkHttpClient.newCall(request).execute();
        return response;
    }


    /**
     * 同步的Post请求
     *
     * @param url
     * @param params post的参数
     * @return 字符串
     */
    private String _postAsString(String url, Param... params) throws IOException {
        Response response = _post(url, params);
        return response.body().string();
    }

    /**
     * 异步的post请求
     *
     * @param url
     * @param callback
     * @param params
     */
    private void _postAsyn(String url, final ResultCallback callback, Param... params) {
        Request request = buildPostRequest(url, params);
        deliveryResult(callback, request);
    }

    /**
     * 异步的post请求
     *
     * @param url
     * @param callback
     * @param params
     */
    private void _postAsyn(String url, final ResultCallback callback, Map<String, String> params) {
        Param[] paramsArr = map2Params(params);
        Request request = buildPostRequest(url, paramsArr);
        deliveryResult(callback, request);
    }

    /**
     * 同步基于post的文件上传
     *
     * @param params
     * @return
     */
    private Response _post(String url, File[] files, String[] fileKeys, Param... params) throws IOException {
        Request request = buildMultipartFormRequest(url, files, fileKeys, params);
        return mOkHttpClient.newCall(request).execute();
    }

    private Response _post(String url, File file, String fileKey) throws IOException {
        Request request = buildMultipartFormRequest(url, new File[]{file}, new String[]{fileKey}, null);
        return mOkHttpClient.newCall(request).execute();
    }

    private Response _post(String url, File file, String fileKey, Param... params) throws IOException {
        Request request = buildMultipartFormRequest(url, new File[]{file}, new String[]{fileKey}, params);
        return mOkHttpClient.newCall(request).execute();
    }

    /**
     * 异步基于post的文件上传
     *
     * @param url
     * @param callback
     * @param files
     * @param fileKeys
     * @throws IOException
     */
    private void _postAsyn(String url, ResultCallback callback, File[] files, String[] fileKeys, Param... params) throws IOException {
        Request request = buildMultipartFormRequest(url, files, fileKeys, params);
        deliveryResult(callback, request);
    }

    /**
     * 异步基于post的文件上传,单文件不带参数上传
     *
     * @param url
     * @param callback
     * @param file
     * @param fileKey
     * @throws IOException
     */
    private void _postAsyn(String url, ResultCallback callback, File file, String fileKey) throws IOException {
        Request request = buildMultipartFormRequest(url, new File[]{file}, new String[]{fileKey}, null);
        deliveryResult(callback, request);
    }

    /**
     * 异步基于post的文件上传,单文件且携带其他form参数上传
     *
     * @param url
     * @param callback
     * @param file
     * @param fileKey
     * @param params
     * @throws IOException
     */
    private void _postAsyn(String url, ResultCallback callback, File file, String fileKey, Param... params) throws IOException {
        Request request = buildMultipartFormRequest(url, new File[]{file}, new String[]{fileKey}, params);
        deliveryResult(callback, request);
    }

    /**
     * 异步下载文件
     *
     * @param url
     * @param destFileDir 本地文件存储的文件夹
     * @param callback
     */
    private void _downloadAsyn(final String url, final String destFileDir, final ResultCallback callback) {
        final Request request = new Request.Builder()
                .url(url)
                .build();
        final Call call = mOkHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(final Request request, final IOException e) {
                sendFailedStringCallback(request, e, callback);
            }

            @Override
            public void onResponse(Response response) {
                InputStream is = null;
                byte[] buf = new byte[2048];
                int len = 0;
                FileOutputStream fos = null;
                try {
                    is = response.body().byteStream();
                    File file = new File(destFileDir, getFileName(url));
                    fos = new FileOutputStream(file);
                    while ((len = is.read(buf)) != -1) {
                        fos.write(buf, 0, len);
                    }
                    fos.flush();
                    //如果下载文件成功,第一个参数为文件的绝对路径
                    sendSuccessResultCallback(file.getAbsolutePath(), callback);
                } catch (IOException e) {
                    sendFailedStringCallback(response.request(), e, callback);
                } finally {
                    try {
                        if (is != null) is.close();
                    } catch (IOException e) {
                    }
                    try {
                        if (fos != null) fos.close();
                    } catch (IOException e) {
                    }
                }

            }
        });
    }

    private String getFileName(String path) {
        int separatorIndex = path.lastIndexOf("/");
        return (separatorIndex < 0) ? path : path.substring(separatorIndex + 1, path.length());
    }

    /**
     * 加载图片
     *
     * @param view
     * @param url
     * @throws IOException
     */
    private void _displayImage(final ImageView view, final String url, final int errorResId) {
        final Request request = new Request.Builder().url(url).build();
        Call call = mOkHttpClient.newCall(request);
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Request request, IOException e) {
                setErrorResId(view, errorResId);
            }

            @Override
            public void onResponse(Response response) {
                InputStream is = null;
                try {
                    is = response.body().byteStream();
                    ImageUtils.ImageSize actualImageSize = ImageUtils.getImageSize(is);
                    ImageUtils.ImageSize imageViewSize = ImageUtils.getImageViewSize(view);
                    int inSampleSize = ImageUtils.calculateInSampleSize(actualImageSize, imageViewSize);
                    try {
                        is.reset();
                    } catch (IOException e) {
                        response = _getAsyn(url);
                        is = response.body().byteStream();
                    }

                    BitmapFactory.Options ops = new BitmapFactory.Options();
                    ops.inJustDecodeBounds = false;
                    ops.inSampleSize = inSampleSize;
                    final Bitmap bm = BitmapFactory.decodeStream(is, null, ops);
                    mDelivery.post(new Runnable() {
                        @Override
                        public void run() {
                            view.setImageBitmap(bm);
                        }
                    });
                } catch (Exception e) {
                    setErrorResId(view, errorResId);

                } finally {
                    if (is != null) try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        });


    }

    private void setErrorResId(final ImageView view, final int errorResId) {
        mDelivery.post(new Runnable() {
            @Override
            public void run() {
                view.setImageResource(errorResId);
            }
        });
    }


    //*************对外公布的方法************


    public static Response getAsyn(OkHttpClient mOkHttpClient, String url) throws IOException {
        return getInstance(mOkHttpClient)._getAsyn(url);
    }

    public static String getAsString(OkHttpClient mOkHttpClient, String url) throws IOException {
        return getInstance(mOkHttpClient)._getAsString(url);
    }

    public static void getAsyn(OkHttpClient mOkHttpClient, String url, ResultCallback callback) {
        getInstance(mOkHttpClient)._getAsyn(url, callback);
    }

    public static Response post(OkHttpClient mOkHttpClient, String url, Param... params) throws IOException {
        return getInstance(mOkHttpClient)._post(url, params);
    }

    public static String postAsString(OkHttpClient mOkHttpClient, String url, Param... params) throws IOException {
        return getInstance(mOkHttpClient)._postAsString(url, params);
    }

    public static void postAsyn(OkHttpClient mOkHttpClient, String url, final ResultCallback callback, Param... params) {
        getInstance(mOkHttpClient)._postAsyn(url, callback, params);
    }


    public static void postAsyn(OkHttpClient mOkHttpClient, String url, final ResultCallback callback, Map<String, String> params) {
        getInstance(mOkHttpClient)._postAsyn(url, callback, params);
    }


    public static Response post(OkHttpClient mOkHttpClient, String url, File[] files, String[] fileKeys, Param... params) throws IOException {
        return getInstance(mOkHttpClient)._post(url, files, fileKeys, params);
    }

    public static Response post(OkHttpClient mOkHttpClient, String url, File file, String fileKey) throws IOException {
        return getInstance(mOkHttpClient)._post(url, file, fileKey);
    }

    public static Response post(OkHttpClient mOkHttpClient, String url, File file, String fileKey, Param... params) throws IOException {
        return getInstance(mOkHttpClient)._post(url, file, fileKey, params);
    }

    public static void postAsyn(OkHttpClient mOkHttpClient, String url, ResultCallback callback, File[] files, String[] fileKeys, Param... params) throws IOException {
        getInstance(mOkHttpClient)._postAsyn(url, callback, files, fileKeys, params);
    }

    public static void postAsyn(OkHttpClient mOkHttpClient, String url, ResultCallback callback, File file, String fileKey) throws IOException {
        getInstance(mOkHttpClient)._postAsyn(url, callback, file, fileKey);
    }

    public static void postAsyn(OkHttpClient mOkHttpClient, String url, ResultCallback callback, File file, String fileKey, Param... params) throws IOException {
        getInstance(mOkHttpClient)._postAsyn(url, callback, file, fileKey, params);
    }

    public static void displayImage(OkHttpClient mOkHttpClient, ImageView view, String url, int errorResId) throws IOException {
        getInstance(mOkHttpClient)._displayImage(view, url, errorResId);
    }

    public static void displayImage(OkHttpClient mOkHttpClient, ImageView view, String url) {
        getInstance(mOkHttpClient)._displayImage(view, url, -1);
    }

    public static void downloadAsyn(OkHttpClient mOkHttpClient, String url, String destDir, ResultCallback callback) {
        getInstance(mOkHttpClient)._downloadAsyn(url, destDir, callback);
    }

    //****************************


    private Request buildMultipartFormRequest(String url, File[] files,
                                              String[] fileKeys, Param[] params) {
        params = validateParam(params);

        MultipartBuilder builder = new MultipartBuilder()
                .type(MultipartBuilder.FORM);

        for (Param param : params) {
            builder.addPart(Headers.of("Content-Disposition", "form-data; name=\"" + param.key + "\""),
                    RequestBody.create(null, param.value));
        }
        if (files != null) {
            RequestBody fileBody = null;
            for (int i = 0; i < files.length; i++) {
                File file = files[i];
                String fileName = file.getName();
                fileBody = RequestBody.create(MediaType.parse(guessMimeType(fileName)), file);
                //TODO 根据文件名设置contentType
                builder.addPart(Headers.of("Content-Disposition",
                        "form-data; name=\"" + fileKeys[i] + "\"; filename=\"" + fileName + "\""),
                        fileBody);
            }
        }

        RequestBody requestBody = builder.build();
        return new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
    }

    private String guessMimeType(String path) {
        FileNameMap fileNameMap = URLConnection.getFileNameMap();
        String contentTypeFor = fileNameMap.getContentTypeFor(path);
        if (contentTypeFor == null) {
            contentTypeFor = "application/octet-stream";
        }
        return contentTypeFor;
    }


    private Param[] validateParam(Param[] params) {
        if (params == null)
            return new Param[0];
        else return params;
    }

    private Param[] map2Params(Map<String, String> params) {
        if (params == null) return new Param[0];
        int size = params.size();
        Param[] res = new Param[size];
        Set<Map.Entry<String, String>> entries = params.entrySet();
        int i = 0;
        for (Map.Entry<String, String> entry : entries) {
            res[i++] = new Param(entry.getKey(), entry.getValue());
        }
        return res;
    }

    private static final String SESSION_KEY = "Set-Cookie";
    private static final String mSessionKey = "JSESSIONID";

    private Map<String, String> mSessions = new HashMap<String, String>();

    private void deliveryResult(final ResultCallback callback, Request request) {
        mOkHttpClient.newCall(request).enqueue(new Callback() {
            @Override
            public void onFailure(final Request request, final IOException e) {
                sendFailedStringCallback(request, e, callback);
            }

            @Override
            public void onResponse(final Response response) {
                try {
                    final String string = response.body().string();
                    if (callback.mType == String.class) {
                        sendSuccessResultCallback(string, callback);
                    } else {
                        Object o = mGson.fromJson(string, callback.mType);
                        sendSuccessResultCallback(o, callback);
                    }


                } catch (IOException e) {
                    sendFailedStringCallback(response.request(), e, callback);
                } catch (com.google.gson.JsonParseException e)//Json解析的错误
                {
                    sendFailedStringCallback(response.request(), e, callback);
                }

            }
        });
    }

    private void sendFailedStringCallback(final Request request, final Exception e, final ResultCallback callback) {
        mDelivery.post(new Runnable() {
            @Override
            public void run() {
                if (callback != null)
                    callback.onError(request, e);
            }
        });
    }

    private void sendSuccessResultCallback(final Object object, final ResultCallback callback) {
        mDelivery.post(new Runnable() {
            @Override
            public void run() {
                if (callback != null) {
                    callback.onResponse(object);
                }
            }
        });
    }

    private Request buildPostRequest(String url, Param[] params) {
        if (params == null) {
            params = new Param[0];
        }
        FormEncodingBuilder builder = new FormEncodingBuilder();
        for (Param param : params) {
            builder.add(param.key, param.value);
        }
        RequestBody requestBody = builder.build();
        return new Request.Builder()
                .url(url)
                .post(requestBody)
                .build();
    }


    public static abstract class ResultCallback<T> {
        Type mType;

        public ResultCallback() {
            mType = getSuperclassTypeParameter(getClass());
        }

        static Type getSuperclassTypeParameter(Class<?> subclass) {
            Type superclass = subclass.getGenericSuperclass();
            if (superclass instanceof Class) {
                throw new RuntimeException("Missing type parameter.");
            }
            ParameterizedType parameterized = (ParameterizedType) superclass;
            return $Gson$Types.canonicalize(parameterized.getActualTypeArguments()[0]);
        }

        public abstract void onError(Request request, Exception e);

        public abstract void onResponse(T response);
    }

    public static class Param {
        public Param() {
        }

        public Param(String key, String value) {
            this.key = key;
            this.value = value;
        }
        String key;
        String value;
    }
}

封装的原理很简单,就是创建了一个单例的OkHttp2Engine对象,例如get的请求:

OkHttp2Engine.getInstance().fetchStringAsyncGet("http://www.baidu.com", new String(), null, new OkHttp2Engine.FetchDataInterface() {
            @Override
            public <T> void successful(T result) {
                Log.i("yzw", result);
                Toast.makeText(getApplicationContext(), "请求成功,result="+result, Toast.LENGTH_SHORT).show();
            }

            @Override
            public void failed(CharSequence message) {

            }
        });

参照的博文有:
http://liuwangshu.cn/application/network/5-okhttp2x.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值