• 安卓网络编程学习(2)——使用OkHttp框架


    写在前面

    本文承接https://www.cnblogs.com/wushenjiang/p/12937857.html,接着上文继续学习。
    前几篇博客我们主要学习了使用java原生网络编程来进行一些经典的操作。现在我们使用OKhttp将之前的操作再重新操作一遍。

    OkHttp优点

    • 1.请求同一主机的时候,一般是指同一域名,支持共享同一个socket.
    • 2.通过连接池减少请求延时
    • 3.传输通过GZIP压缩,减少下载内容的体积
    • 4.用缓存的方式避免重复的请求

    可以看到,OkHttp其实是对原生http请求的一个简单封装,并做了额外的一些工作让我们的请求访问更加简单通畅。

    OkHttp入门

    首先要导入依赖,我们可以使用AndroidStudio或者去github搜索然后copy依赖地址都可以。
    首先我们就来用OkHttp来进行一个最基本的异步get请求:

     public void getRequest(View v) {
            //要有客户端,类似我们要有一个浏览器
            OkHttpClient okHttpClient = new OkHttpClient.Builder()
                    .connectTimeout(10000, TimeUnit.MILLISECONDS)
                    .build();
            //创建请求内容
            Request request = new Request.Builder()
                    .get()
                    .url(BASE_URL + "/get/text")
                    .build();
            //用client去创建请求任务
            Call task = okHttpClient.newCall(request);
            //异步请求
            task.enqueue(new Callback() {
                @Override
                public void onFailure(@NotNull Call call, @NotNull IOException e) {
                    Log.d(TAG, "onFailure... -->" + e);
                }
    
                @Override
                public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                    int code = response.code();
                    if (code == HttpURLConnection.HTTP_OK) {
                        Log.d(TAG, "code -->" + code);
                        ResponseBody body = response.body();
                        Log.d(TAG, "body -->" + body.string());
                    }
                }
            });
    
        }
    

    可以看到,使用OkHttp的封装使得我们相比最基础的java原生网络编程要方便的多,我们只需要按照步骤来就可以很简单的使用网络请求了。当然我们还需要设置网络权限,详情可以看上上篇博客。

    OkHttp的异步Post请求

    上面学习了异步Get请求,那我们再学习一下异步Post请求吧:

     //先有client
            OkHttpClient okHttpClient = new OkHttpClient.Builder()
                    .connectTimeout(10000, TimeUnit.MILLISECONDS)
                    .build();
            //要提交的内容
            CommentItem commentItem = new CommentItem("234134123", "我是评论内容...哈哈");
            Gson gson = new Gson();
            String jsonStr = gson.toJson(commentItem);
            MediaType mediaType = MediaType.parse("application/json");
            RequestBody requestBody = RequestBody.create(jsonStr, mediaType);
    
            Request request = new Request.Builder()
                    .post(requestBody)
                    .url(BASE_URL + "/post/comment")
                    .build();
            //用client去创建任务
            Call task = okHttpClient.newCall(request);
            //异步请求
            task.enqueue(new Callback() {
                @Override
                public void onFailure(@NotNull Call call, @NotNull IOException e) {
                    Log.d(TAG, "onFailure -->" + e.toString());
                }
    
                @Override
                public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                    int code = response.code();
                    Log.d(TAG, "code -->" + code);
                    if (code == HttpURLConnection.HTTP_OK) {
                        ResponseBody body = response.body();
                        if (body != null) {
                            Log.d(TAG, "result -->" + body.string());
                        }
                    }
                }
            });
    

    比起Get请求,我们多了封装请求内容的部分代码。仔细观察我们可以看到,这部分代码很简单:首先我们new一个请求对象出来,然后通过Gson将其转换成json类型字符串,并标志为json类型即可放入请求头。其余的部分我们就发现基本是一致的。
    至于带参数的get和post请求,我们只需要在url里拼接字符串即可,这里不再过多的叙述了。

    Post方式文件上传

    我们先来贴代码:

    public void postFile(View v) {
            //先有client
            OkHttpClient okHttpClient = new OkHttpClient.Builder()
                    .connectTimeout(10000, TimeUnit.MILLISECONDS)
                    .build();
            File file = new File("/storage/emulated/0/Android/data/com.androidlearing.androidnetworkdemo/files/Pictures10.png");
            MediaType fileType = MediaType.parse("image/png");
            RequestBody fileBody = RequestBody.create(file, fileType);
            RequestBody requestBody = new MultipartBody.Builder()
                    .addFormDataPart("file", file.getName(), fileBody)
                    .build();
            //创建请求内容
            Request request = new Request.Builder()
                    .url(BASE_URL + "/file/upload")
                    .post(requestBody)
                    .build();
            //创建请求任务
            Call task = okHttpClient.newCall(request);
            //异步执行
            task.enqueue(new Callback() {
                @Override
                public void onFailure(@NotNull Call call, @NotNull IOException e) {
                    Log.d(TAG, "onFailure -->" + e.toString());
                }
    
                @Override
                public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                    int code = response.code();
                    Log.d(TAG, "code ==>" + code);
                    if (code == HttpURLConnection.HTTP_OK) {
                        ResponseBody body = response.body();
                        if (body != null) {
                            String string = body.string();
                            Log.d(TAG, "result -->" + string);
                        }
                    }
                }
            });
        }
    

    可以看到,我们的代码和上面的post请求并无太大差别,同样需要设置一个请求头。但这里我们由于是文件,就用到了RequestBody的实现类MultipartBody建造者模式下的addFormDataPart方法即可。
    具体也很简单,构造一下即可。

    多文件下载

    上面我们注意到是addFormDataPart方法,一般add都是可以添加很多内容的,我们点进去方法看看注解:

    我们可以看到,这里明显是把Part类进行了foreach循环,然后拼接起来了。说明我们的猜想没有错。我们可以直接在拼接请求头时添加多个文件:

    public void postFiles(View v) {
            //先有client
            OkHttpClient okHttpClient = new OkHttpClient.Builder()
                    .connectTimeout(10000, TimeUnit.MILLISECONDS)
                    .build();
            File fileOne = new File("/storage/emulated/0/Android/data/com.androidlearing.androidnetworkdemo/files/Pictures10.png");
            File fileTwo = new File("/storage/emulated/0/Download/rBsADV64HDWAI6i_AAhJfxL8eXE287.png");
            File fileThree = new File("/storage/emulated/0/Download/rBsADV64ILeAfwQMAAdBpy-0H04021.png");
            File fileFour = new File("/storage/emulated/0/Download/shop-ad.png");
            MediaType fileType = MediaType.parse("image/png");
            RequestBody fileOneBody = RequestBody.create(fileOne, fileType);
            RequestBody fileTwoBody = RequestBody.create(fileTwo, fileType);
            RequestBody fileThreeBody = RequestBody.create(fileThree, fileType);
            RequestBody fileFourBody = RequestBody.create(fileFour, fileType);
            RequestBody requestBody = new MultipartBody.Builder()
                    .addFormDataPart("files", fileOne.getName(), fileOneBody)
                    .addFormDataPart("files", fileTwo.getName(), fileTwoBody)
                    .addFormDataPart("files", fileThree.getName(), fileThreeBody)
                    .addFormDataPart("files", fileFour.getName(), fileFourBody)
                    .build();
            //创建请求内容
            Request request = new Request.Builder()
                    .url(BASE_URL + "/files/upload")
                    .post(requestBody)
                    .build();
            //创建请求任务
            Call task = okHttpClient.newCall(request);
            //异步执行
            task.enqueue(new Callback() {
                @Override
                public void onFailure(@NotNull Call call, @NotNull IOException e) {
                    Log.d(TAG, "onFailure -->" + e.toString());
                }
    
                @Override
                public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                    int code = response.code();
                    Log.d(TAG, "code ==>" + code);
                    if (code == HttpURLConnection.HTTP_OK) {
                        ResponseBody body = response.body();
                        if (body != null) {
                            String string = body.string();
                            Log.d(TAG, "result -->" + string);
                        }
                    }
                }
            });
        }
    
    

    可以看到除了拼接头部部分其余部分基本一模一样。
    这里拼接请求头,和上面基本一样,改个名字即可。

    下载文件

    我们先看核心部分:

        private void downloadFile(InputStream inputStream, Headers headers) throws IOException {
            for (int i = 0; i < headers.size(); i++) {
                String key = headers.name(i);
                String value = headers.value(i);
                Log.d(TAG, key + " ==" + value);
            }
            String contentType = headers.get("Content-disposition");
            String fileName = contentType.replace("attachment; filename=", "");
            File outFile = new File(OkhttpActivity.this.getExternalFilesDir(Environment.DIRECTORY_PICTURES) + File.separator + fileName);
            if (!outFile.getParentFile().exists()) {
                outFile.mkdirs();
            }
            if (!outFile.exists()) {
                outFile.createNewFile();
            }
            FileOutputStream fos = new FileOutputStream(outFile);
            byte[] buffer = new byte[1024];
            int len;
            while ((len = inputStream.read(buffer, 0, buffer.length)) != -1) {
                fos.write(buffer, 0, len);
            }
            fos.flush();
            IOUtils.ioClose(fos);
            IOUtils.ioClose(inputStream);
        }
    
    

    可以看到,下载文件其实就是获取filename和路径并且将二进制文件进行解析写入的过程。整体其实和我们在java原生网络编程的使用并无太大差别。
    下面是全部文件下载的代码:

     public void downFile(View v) {
            //先有client
            OkHttpClient okHttpClient = new OkHttpClient.Builder()
                    .connectTimeout(10000, TimeUnit.MILLISECONDS)
                    .build();
            Request request = new Request.Builder()
                    .get()
                    .url(BASE_URL + "/download/15")
                    .build();
            final Call call = okHttpClient.newCall(request);
            call.enqueue(new Callback() {
                @Override
                public void onFailure(@NotNull Call call, @NotNull IOException e) {
                    Log.d(TAG, "onFailure -->" + e.toString());
                }
    
                @Override
                public void onResponse(@NotNull Call call, @NotNull Response response) throws IOException {
                    int code = response.code();
                    Log.d(TAG, "code -->" + code);
                    if (code == HttpURLConnection.HTTP_OK) {
                        downloadFile(response.body().byteStream(),response.headers());
                    }
                }
            });
    

    总结

    可以看到,使用OkHttp极大的减少了我们的重复代码,但可以看到封装的还是不够彻底。接下来我们学习一个二次封装的框架:Retrofit.

  • 相关阅读:
    ML_入门
    subnet partition
    科比投球预测-python实例
    javascript高级程序设计》第18章 javascript与xml
    《javascript高级程序设计》第17章 错误处理与调试
    《javascript高级程序设计》 第16章 HTML5 脚本编程
    《javascript高级程序设计》 第14章 表单脚本
    《javascript高级程序设计》第13章 事件event
    《javascript高级程序设计》第12 章 DOM2 和DOM3
    《javascript高级程序设计》第11章 DOM 扩展DOM Extensions
  • 原文地址:https://www.cnblogs.com/wushenjiang/p/12944345.html
Copyright © 2020-2023  润新知