okhttp3的使用

本文主要讲解okhttp3的使用方法,包括get请求,post请求,文件上传下载。

首先要知道,如果我们不设置缓存,okhttp默认是没有做数据缓存的,需要自己手动添加缓存


1.简单的get请求,异步请求(即直接在主线程发起的请求,okhttp内部实际是开启了子线程处理网络请求,但是回调方法还是在子线程,需要手动切换到主线程更新UI)
//创建okhttp客户端对象
        OkHttpClient okHttpClient = new OkHttpClient();
        //创建请求对象
        Request request = new Request.Builder().get().url(url).build();
        //创建回调对象
        Call call = okHttpClient.newCall(request);
        //发起请求
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.e("result", e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                final String content = response.body().string();
                //返回的时候在子线程,需要handler更新UI
                runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        mTextView.setText(content);
                    }
                });
            }
        });

同步get请求,主要区别在于创建请求对象时就发起请求,回调方法在发起请求的同一个线程,尽管如此,由于发起网络请求是耗时操作,也需要在子线程执行,更新UI需要切换到主线程

new Thread(new Runnable() {
    @Override
    public void run() {
        //创建客户端对象
        OkHttpClient okHttpClient = new OkHttpClient();
        //创建请求对象
        Request request = new Request.Builder()
                .get()
                .url(url).build();
        //创建响应对象时就发起请求
        try {
            Response response = okHttpClient.newCall(request).execute();
            final String string = response.body().string();
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mTextView.setText(string);
                }
            });
        } catch (IOException e) {
            e.printStackTrace();
        }

    }
}).start();
2.post请求,需要添加请求体,可以添加请求头
new Thread(new Runnable() {
        @Override
        public void run() {
            String name = mEtname.getText().toString().trim();
            String pasw = mEtpsw.getText().toString().trim();
            OkHttpClient okHttpClient = new OkHttpClient();
            //创建请求体
            /**
             * 注意,okhttp3.FormBody instead of FormEncodingBuilder.
             * (OkHttp3.x,FormEncodingBuilder已被FormBody取代)
             */
            FormBody body = new FormBody.Builder()
                    .add("name",name)
                    .add("pasw",pasw)
                    .build();
            //创建请求对象
            Request request = new Request.Builder()
                    .post(body)
                    .url(url)
                    .build();
            try {
                Response response = okHttpClient.newCall(request).execute();
                final String string = response.body().string();
               runOnUiThread(new Runnable() {
                   @Override
                   public void run() {
                       mTextView.setText(string);
                   }
               });
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }).start();

okhttp文件上传还比较麻烦,先使用okhttputis进行上传

okhttputuils文件上传

    //拿到SD卡路径
    File directory = Environment.getExternalStorageDirectory();
    //拼接路径
    File file = new File(directory, "MobiSafe.apk");

    //先使用okhttputils执行文件上传
    OkHttpUtils
            .postFile()
            .url(url)
            .file(file)
            .build()
            .execute(new Callback() {

                @Override
                public void inProgress(float progress, long total, int id) {
                    super.inProgress(progress, total, id);
                    //上传或下载进度的回调,返回的Progress从0到1
                    mProgressBar.setProgress((int) (progress * 100));
                }

                @Override
                public Object parseNetworkResponse(Response response, int id) throws Exception {
                    return null;
                }

                @Override
                public void onError(Call call, Exception e, int id) {
                    mTextView.setText(e.getMessage());

                }

                @Override
                public void onResponse(Object response, int id) {
                        mTextView.setText("上传成功");

                }
            });

服务器端使用流的形式直接写入硬盘,这里只是为了测试自己写了个简单的servlet,实际的服务器逻辑要复杂多了。

 */
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // TODO Auto-generated method stub
//      doGet(request, response);

    request.setCharacterEncoding("utf-8");
    response.setCharacterEncoding("utf-8");

    /*String name = request.getParameter("type");
    System.out.println(name);*/
    PrintWriter writer = response.getWriter();

        //创建目录保存上船的图片
        File dir = new File("E:/uploadFile");
        if(!dir.exists()){
            dir.mkdir();
        }

        String setName = UUID.randomUUID() + ".zip";

        File file = new File(dir,setName);

        ServletInputStream inputStream = request.getInputStream();

        if(inputStream!=null){
            FileOutputStream fos = new FileOutputStream(file);

            byte[] buffer = new byte[1024];
            int len = 0;

            while((len=inputStream.read(buffer))!=-1){
                fos.write(buffer,0,len);
            }

            inputStream.close();
            fos.close();
            writer.write("上傳成功");
            System.out.println("上傳成功");
        }else{
            writer.write("上傳失敗");
        }

okhttputils文件下载,设置下载进度时候,需要服务器设置response.setContentLength

    String finleName = "meizi.jpg";//保存的文件名
    String fileDir = directory.getAbsolutePath();//保存路径
    OkHttpUtils
            .get()
            .url(url)
            .addParams("type","downLoad")
            .build()
            .execute(new FileCallBack(fileDir, finleName) {
                @Override
                public void inProgress(float progress, long total, int id) {
                    super.inProgress(progress, total, id);
                    //如果服务器没有设置长度,输出结果是负数
                    Log.e("result", "progress=" + progress);
                    mProgressBar.setProgress((int) (progress*100));
                }

                @Override
                public void onError(Call call, Exception e, int id) {
                    mTextView.setText(e.getMessage());
                }

                @Override
                public void onResponse(File response, int id) {
                    mTextView.setText("下载成功!");
                }
            });

服务器端下载对应的代码

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    response.setCharacterEncoding("utf-8");


    ServletOutputStream outputStream = response.getOutputStream();
    String type = request.getParameter("type");
    if("downLoad".equals(type)){
        String file = "E:/uploadFile/src.zip";
        FileInputStream fis = new FileInputStream(file);

        File calcFile = new File(file);
        long length = calcFile.length();
        response.setContentLength((int) length);

        byte[] buffer = new byte[1024];
        int len = 0;
        while((len=fis.read(buffer))!=-1){
            outputStream.write(buffer,0,len);
        }

        fis.close();
        outputStream.close();
        System.out.println("下載成功");

    }else{

        System.out.println("沒有下載");
    }

3.OKHttp文件上传

好了,理解okhttputils的上传下载方式,现在来看okhttp上传,以表单的形式

private void uploadByOk(final File directory) {

    new Thread(new Runnable() {
        @Override
        public void run() {
            //要上传的文件
            File file = new File(directory, "src.zip");
            //创建客户端对象
            OkHttpClient okHttpClient = new OkHttpClient();
            //指定上传的文件类型,application/octet-stream指的是二进制流,可以上传任意类型
            Request request = getFileRequest(url, file, null);
            //创建回调对象
            Call call = okHttpClient.newCall(request);
            call.enqueue(new okhttp3.Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    Log.e("result", e.getMessage());

                }

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

}

public static Request  getFileRequest(String url,File file,Map<String, String> maps){
    //设置为表单的形式提交
    MultipartBody.Builder builder=  new MultipartBody.Builder().setType(MultipartBody.FORM);

    //这个name="file",相当于表单的name=file,在服务器上通过request.getPart("file");然后通过part.write(fileName)写到文件中
    // 传入这个键才能得到对应part的文件
    //这个搞了我一个晚上,操!

    if(maps==null){
        //如果是参数,则通过addFormDataPart添加  如果是文件,则通过addPart添加
        //图片的格式"image/png",如果是流的格式application/octet-stream

        builder.addPart( Headers.of("Content-Disposition", "form-data; name=\"file\";filename=\"file.jpg\""),
                RequestBody.create(MediaType.parse("application/octet-stream"),file)
        ).build();

    }else{
        for (String key : maps.keySet()) {
            //这里相当于添加参数
            builder.addFormDataPart(key, maps.get(key));
        }

        builder.addPart( Headers.of("Content-Disposition", "form-data; name=\"file\";filename=\"file.jpg\""),
                RequestBody.create(MediaType.parse("application/octet-stream"),file)
        );

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

}

4.okhttp下载

private void downLoadByOK(final File directory) {
    //用okhttp下载
    new Thread(new Runnable() {
        @Override
        public void run() {
            //直接在url上添加参数
            String newurl = url + "?type=downLoad";
            //创建客户端对象
            OkHttpClient okHttpClient = new OkHttpClient();
            //创建请求对象
            Request request = new Request.Builder()
                    .get()
                    .url(newurl)
                    .build();
            //创建回调对象
            Call call = okHttpClient.newCall(request);
            call.enqueue(new okhttp3.Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    Log.e("result", "结果:" + e.getMessage());
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    InputStream inputStream = response.body().byteStream();
                    long lenth = response.body().contentLength();
                    Log.e("result", "长度=" + lenth);

                    File file = new File(directory, "src.zip");
                    FileOutputStream fos = new FileOutputStream(file);

                    byte[] buffer = new byte[1024];
                    int len = 0;
                    int progress = 0;
                    while ((len = inputStream.read(buffer)) != -1) {
                        fos.write(buffer, 0, len);
                        progress = progress + len;
                        mProgressBar.setProgress((int) (progress * 100 / lenth));
                    }

                    inputStream.close();
                    fos.close();
                }
            });
        }
    }).start();

对比Okhttputils和okhttp,其实Okhttputils是对okhttp的封装,所以使用上okhttputils会比较方便省事,但自定义的内容相对较少了。比如下载时不能自定义每次读取的缓存数组容量,就是byte[ ]数组。

6.设置缓存

虽然OKHttp支持缓存,但默认不会帮我们设置缓存,所以需要我们自己手动设置,这也是合理的,因为okhttp不知道我们要怎么缓存,缓存空间多大,这些需要我们自己实现。
服务器支持缓存

如果服务器支持缓存,请求返回的Response会带有这样的Header:Cache-Control, max-age=xxx,这种情况下我们只需要手动给okhttp设置缓存就可以让okhttp自动帮你缓存了。这里的max-age的值代表了缓存在你本地存放的时间,可以根据实际需要来设置其大小。

  • 首先我们要提供了一个文件路径用来存放缓存,出于安全性的考虑,在Android中我们推荐使用Context.getCacheDir()来作为缓存的存放路径,另外还需要指定缓存的大小就可以创建一个缓存了。如下所示:

    public Cache provideCache() {
    return new Cache(mContext.getCacheDir(), 10240*1024);
    }
    
  • 创建了这个缓存后我们还需要将其设置到okttpClient对象里面:

    OkHttpClient okHttpClient = new OkHttpClient();
    OkHttpClient newClient = okHttpClient.newBuilder()
           .cache(cache)
           .connectTimeout(20, TimeUnit.SECONDS)
           .readTimeout(20, TimeUnit.SECONDS)
           .build();
    
服务器不支持缓存
  • 如果服务器不支持缓存就可能没有指定这个头部,或者指定的值是如no-store等,但是我们还想在本地使用缓存的话要怎么办呢?这种情况下我们就需要使用Interceptor来重写Respose的头部信息,从而让okhttp支持缓存。
  • 如下所示,我们重写的Response的Cache-Control字段

        public class CacheInterceptor implements Interceptor {
            @Override
            public Response intercept(Chain chain) throws IOException {
                Request request = chain.request();
                Response response = chain.proceed(request);
                Response response1 = response.newBuilder()
                        .removeHeader("Pragma")
                        .removeHeader("Cache-Control")
                        //cache for 30 days
                        .header("Cache-Control", "max-age=" + 3600 * 24 * 30)
                        .build();
                return response1;
            }
        }
    
  • 然后将该Intercepter作为一个NetworkInterceptor加入到okhttpClient中

    OkHttpClient okHttpClient = new OkHttpClient();
    
    OkHttpClient newClient = okHttpClient.newBuilder()
            .addNetworkInterceptor(new CacheInterceptor())
            .cache(cache)
            .connectTimeout(20, TimeUnit.SECONDS)
            .readTimeout(20, TimeUnit.SECONDS)
            .build();
    

这样我们就可以在服务器不支持缓存的情况下使用缓存了。

为了使用同一个okhttp对象,可以在Application中设置全局单例

    //创建客户端
    okHttpClient = new OkHttpClient();
  • 然后在Protocol类中根据需要是否设置缓存

    package org.skxy.www.okhttpdemo;
    
    import android.os.Handler;
    import android.os.Message;
    import android.support.annotation.NonNull;
    import android.util.Log;
    
    import java.io.File;
    import java.io.IOException;
    import java.util.concurrent.TimeUnit;
    
    import okhttp3.Cache;
    import okhttp3.Call;
    import okhttp3.Callback;
    import okhttp3.OkHttpClient;
    import okhttp3.Request;
    import okhttp3.Response;
    
    /**
     * ClassName : MyTaskProtocol
     * Created by: skxy on 2016/10/19.
     * DES :网络请求类
     */
    public class MyTaskProtocol implements Runnable {
        public static final int SUCCESS = 1;
        public static final int FAIL = 0;
        private boolean isCache = true;
        private long maxSize = 10*1024*1024;//设置缓存为10M
    
        private final String url;
    
        public MyTaskProtocol(String url,OnNetworkResultListener mListener,boolean isCache) {
            this.url = url;
            this.mListener = mListener;
            this.isCache = isCache;
        }
    
        //访问网络的方法
        public void getDatas(String url) {
            //为了实现全局单例,将客户端对象放在application中初始化
            OkHttpClient okHttpClient = MyApplication.getClient();
            //创建请求对象
            Request request = new Request.Builder()
                    .get()
                    .url(url)
                    .build();
            //可以直接创建响应对象发起请求,同步请求
           /* try {
                Response response =okHttpClient.newCall(request).execute();
                response.body().string();
            } catch (IOException e) {
                e.printStackTrace();
            }*/
    
            //根据是否需要做缓存创建回调对象,有些需要实事更新的页面不需要缓存
            Call call;
            if (isCache){
                //有设置缓存
                OkHttpClient client = getOkHttpCacheClient(okHttpClient);
                call = client.newCall(request);
            }else {//没有设置缓存
                call = okHttpClient.newCall(request);
            }
            //发起请求
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    Message msg = Message.obtain();
                    msg.what = FAIL;
                    msg.obj = e.getMessage();
                    mHandler.sendMessage(msg);
                    Log.e("result", "onResponse: 错误返回" );
                }
    
                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    Message msg = Message.obtain();
                    msg.what = SUCCESS;
                    msg.obj = response.body().string();
                    mHandler.sendMessage(msg);
                    Log.e("result", "onResponse: 成功返回" );
                }
            });
        }
    
        @NonNull
        private OkHttpClient getOkHttpCacheClient(OkHttpClient okHttpClient) {
            //设置缓存
            File file = MyApplication.getContext().getCacheDir();
            Cache cache = new Cache(file, maxSize);
            //设置缓存到客户端
            OkHttpClient client = okHttpClient.newBuilder()
                    .addNetworkInterceptor(new CacheInterceptor())
                    .cache(cache)
                    .connectTimeout(10, TimeUnit.SECONDS)
                    .readTimeout(10, TimeUnit.SECONDS)
                    .build();
            return client;
        }
    
        /**
         * 创建handler将返回的数据推送到主线程
         */
        Handler mHandler = new Handler(){
            @Override
            public void handleMessage(Message msg) {
                super.handleMessage(msg);
                String result = (String) msg.obj;
                int what = msg.what;
                switch (what) {
                    case FAIL:
                        mListener.onFail(result);
                    break; case SUCCESS:
                        mListener.onSuccess(result);
                    break;
                }
            }
        };
    
        /**
         * 创建回调监听,获取网络返回的数据
         */
        private OnNetworkResultListener mListener;
    
        public interface OnNetworkResultListener {
    
            void onFail(String result);//失败回调
    
            void onSuccess(String result);//成功回调
        }
    
       /* public void setOnNetworkResultListener(OnNetworkResultListener listener) {
            this.mListener = listener;
        }*/
    
        /**
         * 执行网络请求
         */
        @Override
        public void run() {
            getDatas(url);
        }
    }
    

不同的Protocol对象发起的网络请求,他们之间的缓存是互不干扰的。好了,OKHttp的使用先介绍到这里,下一篇再介绍OKHttp的原理。




  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于OkHttp3的封装使用,你可以按照以下步骤进行: 1. 添加OkHttp3依赖:在你的项目中的build.gradle文件中添加以下依赖: ```groovy dependencies { implementation 'com.squareup.okhttp3:okhttp:4.9.1' } ``` 2. 创建OkHttpClient实例:在你的代码中创建一个OkHttpClient实例,可以设置一些参数,如连接超时时间、读写超时时间等。 ```java OkHttpClient client = new OkHttpClient.Builder() .connectTimeout(10, TimeUnit.SECONDS) // 设置连接超时时间为10秒 .readTimeout(10, TimeUnit.SECONDS) // 设置读取超时时间为10秒 .writeTimeout(10, TimeUnit.SECONDS) // 设置写入超时时间为10秒 .build(); ``` 3. 创建Request对象:根据你的请求需求,创建一个Request对象,包括请求的URL、请求方法(GET、POST等)、请求头、请求体等。 ```java Request request = new Request.Builder() .url("http://www.example.com/api") // 设置请求的URL .addHeader("Authorization", "Bearer token") // 设置请求头,如添加认证信息 .post(RequestBody.create(MediaType.parse("application/json"), requestBody)) // 设置请求体,如发送JSON数据 .build(); ``` 4. 发送请求并处理响应:使用OkHttpClient实例发送请求,并处理返回的响应。 ```java try { Response response = client.newCall(request).execute(); if (response.isSuccessful()) { String responseBody = response.body().string(); // 处理响应结果 } else { // 处理请求失败 } } catch (IOException e) { e.printStackTrace(); // 处理异常 } ``` 这是一个基本的OkHttp3的封装使用示例,你可以根据自己的需求进行进一步定制和扩展。希望对你有帮助!如果有其他问题,可以继续问我。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值