zoukankan      html  css  js  c++  java
  • 安卓网络编程学习(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.

  • 相关阅读:
    109 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 03 新增功能及实现 05 问题解析--通过一个方法完成学生和专业的双向关联
    108 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 03 新增功能及实现 04 问题解析--数组未实例化造成的空指针异常
    107 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 03 新增功能及实现 03 编写方法完成学生个数统计功能
    106 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 03 新增功能及实现 02 新增属性完成学生信息存储
    105 01 Android 零基础入门 02 Java面向对象 03 综合案例(学生信息管理) 03 新增功能及实现 01 新增需求及分析
    session与cookie的区别和联系
    session和cookie的区别
    Web服务器主动推送技术
    webSocket的场景应用
    TCP、Http和Socket 优劣比较
  • 原文地址:https://www.cnblogs.com/wushenjiang/p/12944345.html
Copyright © 2011-2022 走看看