OkHttp使用笔记

1.首先添加依赖库

compile 'com.squareup.okhttp3:okhttp:3.5.0'
compile 'com.squareup.okio:okio:1.11.0'
compile 'com.facebook.stetho:stetho-okhttp3:1.4.2'

上面引入了三个库,分别是okhttp框架包,okhttp操作流的包,最后一个是facebook公司开发的用于检测okhttp日志的插件包,用于在chrome浏览器中调试okhttp网络访问数据非常方便。

stetho需要在Application中初始化

Stetho.initializeWithDefaults(this);

然后在chrome中输入地址:chrome://inspect/

2.okhttp的Get请求+封装

本身OkHttp的请求分为三步:
1.拿到OkHttpClient

OkHttpClient client = new OkHttpClient();

2.构造Request对象

Request request = new Request.Builder()
                .get()
                .url("https:www.baidu.com")
                .build();

3 . 将Request封装为Call

Call call = client.newCall(request);

4 . 根据需要调用同步或者异步请求方法
//同步调用,返回Response,会抛出IO异常
Response response = call.execute();
//异步调用,并设置回调函数
call.enqueue(new Callback() {
@Override
public void onFailure(Call call, IOException e) {
Toast.makeText(OkHttpActivity.this, "get failed", Toast.LENGTH_SHORT).show();
}

@Override
public void onResponse(Call call, final Response response) throws IOException {
    final String res = response.body().string();
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            contentTv.setText(res);
        }
    });
}

});

注意:
同步调用会阻塞主线程,一般不适用
异步调用的回调函数是在子线程,我们不能在子线程更新UI,需要借助于runOnUiThread()方法或者Handler来处理

但每次都写这样的四步对于程序员来说肯定是痛苦的,所以下面进行封装处理,新建一个OkHttpUtils工具类用于统一的处理网络请求

package cq.cake.okhttpdemo;

import android.content.Context;

import com.facebook.stetho.okhttp3.StethoInterceptor;

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

import okhttp3.Cache;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;


/**
 * MyApplication --  cq.cake.okhttpdemo
 * Created by Small Cake on  2016/12/26 16:02.
 * 全局统一使用的OkHttpClient工具
 */

public class OkHttpUtils {

    public static final long DEFAULT_READ_TIMEOUT_MILLIS = 15 * 1000;
    public static final long DEFAULT_WRITE_TIMEOUT_MILLIS = 20 * 1000;
    public static final long DEFAULT_CONNECT_TIMEOUT_MILLIS = 20 * 1000;
    private static final long HTTP_RESPONSE_DISK_CACHE_MAX_SIZE = 10 * 1024 * 1024;
    private static volatile OkHttpUtils sInstance;
    private OkHttpClient mOkHttpClient;

    private OkHttpUtils() {


        mOkHttpClient = new OkHttpClient.Builder()
                .readTimeout(DEFAULT_READ_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
                .writeTimeout(DEFAULT_WRITE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
                .connectTimeout(DEFAULT_CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
                //FaceBook 网络调试器,可在Chrome调试网络请求,查看SharePreferences,数据库等
                .addNetworkInterceptor(new StethoInterceptor())
                //http数据log,日志中打印出HTTP请求&响应数据
                .addInterceptor(new LoggingInterceptor())
                .build();


    }

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

    public OkHttpClient getOkHttpClient() {
        return mOkHttpClient;
    }

    public void setCache(Context appContext) {
        final File baseDir = appContext.getApplicationContext().getCacheDir();
        if (baseDir != null) {
            final File cacheDir = new File(baseDir, "HttpResponseCache");
            mOkHttpClient.newBuilder().cache((new Cache(cacheDir, HTTP_RESPONSE_DISK_CACHE_MAX_SIZE)));
        }
    }


    public static void getAsyn(String url, Callback callBack){
        OkHttpClient okHttpClient = OkHttpUtils.getInstance().getOkHttpClient();
        Request request = new Request.Builder().url(url).build();
        okHttpClient.newCall(request).enqueue(callBack);
    }
 
}

这样每次访问数据的时候我们只需要,通过在Activity中调用getAsyn方法就可以了,方便很多。

OkHttpUtils.getAsyn("http://m.yuzetianxia.com", new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
//                System.out.println(response.body().string().toString());
               final String str = response.body().string();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tvView.setText(decodeUnicode(str));
                    }
                });
            }
        });

注意:
这里返回的数据因为是异步请求,所以是运行在子线程中的,那么想要显示在UI控件上就要用到runOnUiThread方式,或者Handler。

3.okhttp的POST请求+封装

有了get请求的封装,post也是类似的封装,不过多加了一个请求体RequestBody,在Activity中请求的时候我们是用的RequestBody的子类FormBody.Builder构造来写入键值对的,不再使用Map的方式!
在OkHttpUtils中加入方法:

public static void postAsyn(String url, RequestBody body, Callback callBack){
        OkHttpClient okHttpClient = OkHttpUtils.getInstance().getOkHttpClient();
        Request request = new Request.Builder().url(url).post(body).build();
        okHttpClient.newCall(request).enqueue(callBack);
    }

然后在Activity中使用:



        FormBody.Builder builder = new FormBody.Builder();
        builder.add("account","888888");
        builder.add("pwd","123456");

      OkHttpUtils.postAsyn("http://www.baidu.com/Api/Login/doLogin/",builder.build(),new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
//                Log.i("post>>>>",response.body().string().toString());
                final String str = response.body().string();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tvView.setText(decodeUnicode(str));
                    }
                });
            }
        });

4.okhttp的上传文件+封装

在OkHttpUtils中加入方法:

public static void upFile(String url, RequestBody body, Callback callBack){
        OkHttpClient okHttpClient = OkHttpUtils.getInstance().getOkHttpClient();
        Request request = new Request.Builder().url(url).post(body).build();
        okHttpClient.newCall(request).enqueue(callBack);
    }

在使用的时候需要自己构建文件File并用MultipartBody构建参数

int time = TimeUtils.getTime();

        File file = new File(Environment.getExternalStorageDirectory(), "1.png");
        if (!file.exists()){
            Toast.makeText(this, "文件不存在", Toast.LENGTH_SHORT).show();
            return;
        }
        RequestBody muiltipartBody = new MultipartBody.Builder()
                //一定要设置这句
                .setType(MultipartBody.FORM)
                .addFormDataPart("mid", "3")
                .addFormDataPart("time", time+"")
                .addFormDataPart("sign", MD5.getSign("3", time))
                .addFormDataPart("pic", "1.png", RequestBody.create(MediaType.parse("application/octet-stream"), file))
                .build();

        OkHttpUtils.upFile("http://m.hxfuuu.cn/Api/Manage/setHeadpic",muiltipartBody,new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }
            @Override
            public void onResponse(Call call, Response response) throws IOException {
//                Log.i("post>>>>",response.body().string().toString());
                final String str = response.body().string();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tvView.setText(decodeUnicode(str));
                    }
                });
            }
        });

5.okhttp的下载文件+封装

在OkHttpUtils中加入方法:

public static void getDownload(String url, Callback callBack){
        OkHttpClient okHttpClient = OkHttpUtils.getInstance().getOkHttpClient();
        Request request = new Request.Builder().url(url).build();
        okHttpClient.newCall(request).enqueue(callBack);
    }

在得到回调结果的时候对流进行处理,不再是单纯的数据。

OkHttpUtils.getDownload("http://m.hxfuuu.cn/Public/upload/headpic/3.jpg", new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                //1.拿到下载文件的总长度
                final long total = response.body().contentLength();
                //2.在while循环中每次递增我们读取的buf的长度
                long sum = 0L;
                //拿到字节流
                InputStream is = response.body().byteStream();
                int len = 0;
                File file  = new File(Environment.getExternalStorageDirectory(), "n.png");
                FileOutputStream fos = new FileOutputStream(file);
                byte[] buf = new byte[128];

                while ((len = is.read(buf)) != -1){
                    fos.write(buf, 0, len);
                    //每次递增
                    sum += len;
                    final long finalSum = sum;
                    Log.d("pyh1", "onResponse: " + finalSum + "/" + total);
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            //将进度设置到TextView中
                            tvView.setText(finalSum + "/" + total);
                        }
                    });
                    try {
                        Thread.sleep(50);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }

                fos.flush();

                //关闭流
                fos.close();
                is.close();
            }
        });

写了这些后,你会发现其实下载文件getDownload方法和getAsyn方法,上传文件upFile方法和postAsyn方法内部方法体都是一样的。确实是一样的,不同的是在Activity中发出请求前的处理和得到数据后的处理不同而已。所以后面两个方法其实都可以省略,关键要知道在具体的请求时应该做什么就可以了!

6.okhttp的https请求

okhttp默认是支持https请求的,比如你用get方法去访问https://www.baidu.com是可以直接访问的,但是针对有的个人自建证书或不被认可的证书,就需要特殊处理一下了!
我们一般是把证书(.crt文件)放在资源文件assets下,然后在okhttp的配置中去配置sslSocketFactory用于访问自建的证书。
下面是完整的OkHttpUtils封装类,方便大家根据自己的需要修改。

package cq.cake.okhttpdemo;

import android.content.Context;

import com.facebook.stetho.okhttp3.StethoInterceptor;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
import java.security.KeyStore;
import java.security.cert.CertificateFactory;
import java.util.Arrays;
import java.util.Collection;
import java.util.concurrent.TimeUnit;

import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

import okhttp3.Cache;
import okhttp3.Callback;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.RequestBody;


/**
 * MyApplication --  cq.cake.okhttpdemo
 * Created by Small Cake on  2016/12/26 16:02.
 * 全局统一使用的OkHttpClient工具
 */

public class OkHttpUtils {

    public static final long DEFAULT_READ_TIMEOUT_MILLIS = 15 * 1000;
    public static final long DEFAULT_WRITE_TIMEOUT_MILLIS = 20 * 1000;
    public static final long DEFAULT_CONNECT_TIMEOUT_MILLIS = 20 * 1000;
    private static final long HTTP_RESPONSE_DISK_CACHE_MAX_SIZE = 10 * 1024 * 1024;
    private static volatile OkHttpUtils sInstance;
    private OkHttpClient mOkHttpClient;

    /**
     * 需要访问https,且证书只能在本地访问
     * @param context
     */
    private OkHttpUtils(Context context) {
        X509TrustManager trustManager = null;
        SSLSocketFactory sslSocketFactory = null;
        try {
        final InputStream inputStream;
            inputStream = context.getAssets().open("yuzetianxia.com.crt"); // 得到证书的输入流


                trustManager = trustManagerForCertificates(inputStream);//以流的方式读入证书
                SSLContext sslContext = SSLContext.getInstance("TLS");
                sslContext.init(null, new TrustManager[]{trustManager}, null);
                sslSocketFactory = sslContext.getSocketFactory();

            } catch (GeneralSecurityException e) {
                throw new RuntimeException(e);
            } catch (IOException e) {
            e.printStackTrace();
        }
        mOkHttpClient = new OkHttpClient.Builder()
                .readTimeout(DEFAULT_READ_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
                .writeTimeout(DEFAULT_WRITE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
                .connectTimeout(DEFAULT_CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
                //FaceBook 网络调试器,可在Chrome调试网络请求,查看SharePreferences,数据库等
                .addNetworkInterceptor(new StethoInterceptor())
                //http数据log,日志中打印出HTTP请求&响应数据
                .addInterceptor(new LoggingInterceptor())
                .sslSocketFactory(sslSocketFactory, trustManager)
                .build();


    }
    private OkHttpUtils() {


        mOkHttpClient = new OkHttpClient.Builder()
                .readTimeout(DEFAULT_READ_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
                .writeTimeout(DEFAULT_WRITE_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
                .connectTimeout(DEFAULT_CONNECT_TIMEOUT_MILLIS, TimeUnit.MILLISECONDS)
                //FaceBook 网络调试器,可在Chrome调试网络请求,查看SharePreferences,数据库等
                .addNetworkInterceptor(new StethoInterceptor())
                //http数据log,日志中打印出HTTP请求&响应数据
                .addInterceptor(new LoggingInterceptor())
                .build();


    }

    public static OkHttpUtils getInstance(Context context) {
        if (sInstance == null) {
            synchronized (OkHttpUtils.class) {
                if (sInstance == null) {
                    sInstance = new OkHttpUtils(context);
                }
            }
        }
        return sInstance;
    }
    public static OkHttpUtils getInstance() {
        if (sInstance == null) {
            synchronized (OkHttpUtils.class) {
                if (sInstance == null) {
                    sInstance = new OkHttpUtils();
                }
            }
        }
        return sInstance;
    }

    public OkHttpClient getOkHttpClient() {
        return mOkHttpClient;
    }

    public void setCache(Context appContext) {
        final File baseDir = appContext.getApplicationContext().getCacheDir();
        if (baseDir != null) {
            final File cacheDir = new File(baseDir, "HttpResponseCache");
            mOkHttpClient.newBuilder().cache((new Cache(cacheDir, HTTP_RESPONSE_DISK_CACHE_MAX_SIZE)));
        }
    }

    public static void getAsyn(Context context,String url, Callback callBack){
        OkHttpClient okHttpClient = OkHttpUtils.getInstance(context).getOkHttpClient();
        Request request = new Request.Builder().url(url).build();
        okHttpClient.newCall(request).enqueue(callBack);
    }
    public static void postAsyn(Context context,String url, RequestBody body, Callback callBack){
        OkHttpClient okHttpClient = OkHttpUtils.getInstance(context).getOkHttpClient();
        Request request = new Request.Builder().url(url).post(body).build();
        okHttpClient.newCall(request).enqueue(callBack);
    }

        public static void getAsyn(String url, Callback callBack){
        OkHttpClient okHttpClient = OkHttpUtils.getInstance().getOkHttpClient();
        Request request = new Request.Builder().url(url).build();
        okHttpClient.newCall(request).enqueue(callBack);
    }
    public static void postAsyn(String url, RequestBody body, Callback callBack){
        OkHttpClient okHttpClient = OkHttpUtils.getInstance().getOkHttpClient();
        Request request = new Request.Builder().url(url).post(body).build();
        okHttpClient.newCall(request).enqueue(callBack);
    }
    public static void upFile(String url, RequestBody body, Callback callBack){
        OkHttpClient okHttpClient = OkHttpUtils.getInstance().getOkHttpClient();
        Request request = new Request.Builder().url(url).post(body).build();
        okHttpClient.newCall(request).enqueue(callBack);
    }
    public static void getDownload(String url, Callback callBack){
        OkHttpClient okHttpClient = OkHttpUtils.getInstance().getOkHttpClient();
        Request request = new Request.Builder().url(url).build();
        okHttpClient.newCall(request).enqueue(callBack);
    }


    /**
     * 以流的方式添加信任证书
     */
    /**
     * Returns a trust manager that trusts {@code certificates} and none other. HTTPS services whose
     * certificates have not been signed by these certificates will fail with a {@code
     * SSLHandshakeException}.
     * 

*

This can be used to replace the host platform's built-in trusted certificates with a custom * set. This is useful in development where certificate authority-trusted certificates aren't * available. Or in production, to avoid reliance on third-party certificate authorities. *

*

*

Warning: Customizing Trusted Certificates is Dangerous!

*

*

Relying on your own trusted certificates limits your server team's ability to update their * TLS certificates. By installing a specific set of trusted certificates, you take on additional * operational complexity and limit your ability to migrate between certificate authorities. Do * not use custom trusted certificates in production without the blessing of your server's TLS * administrator. */ private X509TrustManager trustManagerForCertificates(InputStream in) throws GeneralSecurityException { CertificateFactory certificateFactory = CertificateFactory.getInstance("X.509"); Collection certificates = certificateFactory.generateCertificates(in); if (certificates.isEmpty()) { throw new IllegalArgumentException("expected non-empty set of trusted certificates"); } // Put the certificates a key store. char[] password = "password".toCharArray(); // Any password will work. KeyStore keyStore = newEmptyKeyStore(password); int index = 0; for (java.security.cert.Certificate certificate : certificates) { String certificateAlias = Integer.toString(index++); keyStore.setCertificateEntry(certificateAlias, certificate); } // Use it to build an X509 trust manager. KeyManagerFactory keyManagerFactory = KeyManagerFactory.getInstance( KeyManagerFactory.getDefaultAlgorithm()); keyManagerFactory.init(keyStore, password); TrustManagerFactory trustManagerFactory = TrustManagerFactory.getInstance( TrustManagerFactory.getDefaultAlgorithm()); trustManagerFactory.init(keyStore); TrustManager[] trustManagers = trustManagerFactory.getTrustManagers(); if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) { throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers)); } return (X509TrustManager) trustManagers[0]; } /** * 添加password * @param password * @return * @throws GeneralSecurityException */ private KeyStore newEmptyKeyStore(char[] password) throws GeneralSecurityException { try { KeyStore keyStore = KeyStore.getInstance(KeyStore.getDefaultType()); // 这里添加自定义的密码,默认 InputStream in = null; // By convention, 'null' creates an empty key store. keyStore.load(in, password); return keyStore; } catch (IOException e) { throw new AssertionError(e); } } }

使用的时候需要多传入一个资源文件

OkHttpUtils.getAsyn(this,"https://m.yuzetianxia.com", new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {

            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
//                System.out.println(response.body().string().toString());
               final String str = response.body().string();
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        tvView.setText(decodeUnicode(str));
                    }
                });
            }
        });

未完待续。。。

你可能感兴趣的:(OkHttp使用笔记)