zoukankan      html  css  js  c++  java
  • Android学习——使用okhttp

    要使用OkHttp,必须在项目中先导入OkHttp,在app模块的build.gradle文件中,加入下面的代码:

    dependencies {
        compile fileTree(dir: 'libs', include: ['*.jar'])
        testCompile 'junit:junit:4.12'
        compile 'com.android.support:appcompat-v7:23.1.1'
        compile 'com.squareup.okhttp3:okhttp:3.2.0'
    }

    这样就将OkHttp导入到项目中了。

    (1)GET请求

    最简单的GET请求用法如下:

    //简单的Get请求,不带参数
    public void simpleGetClick(View view) {
        okHttpClient = new OkHttpClient();
        Request request = new Request.Builder()
                .url("http://192.168.1.170:8088/okhttp/test_simple_get.php")
                .build();
        okHttpClient.newCall(request).enqueue(callback);
    }

    如果请求中要添加Header头和参数,可以用下面的方式:

    //带参数的Get请求
    public void addParamGetClick(View view) {
        okHttpClient = new OkHttpClient();
        Request request = new Request.Builder()
                .addHeader("token", "asdlfjkasdljfaskdjfalsjkljalk")  //请求头中加入参数
                .url("http://192.168.1.170:8088/okhttp/test_param_get.php?username=zhangsan&phone=13888888888") //携带参数
                .build();
        okHttpClient.newCall(request).enqueue(callback);
    }

    需要注意的是,上面的代码中,callback是请求后的回调接口,代码如下:

    //请求后的回调接口
    private Callback callback = new Callback() {
        @Override
        public void onFailure(Call call, IOException e) {
            setResult(e.getMessage(), false);
        }
    
        @Override
        public void onResponse(Call call, Response response) throws IOException {
            setResult(response.body().string(), true);
        }
    };

    这个回调接口需要注意的是,onResponse和onFailure都不是在UI线程中执行的,所以如果我们要在onResponse或onFailure中进行UI相关的操作,需要在UI线程中进行。 

    (2)POST请求

    比较简单的POST请求,用法如下:

    //简单的带参数和Header的post请求
    public void simplePostClick(View view) {
        okHttpClient = new OkHttpClient();
        RequestBody requestBody = new FormBody.Builder()
                .add("username", "wangwu")
                .add("password", "hello12345")
                .add("gender", "female")
                .build();
        Request request = new Request.Builder()
                .url("http://192.168.1.170:8088/okhttp/test_simple_post.php")
                .post(requestBody)
                .addHeader("token", "helloworldhelloworldhelloworld")
                .build();
        okHttpClient.newCall(request).enqueue(callback);
    }

    这里我们需要先构造一个RequestBody,然后把需要携带的参数放到RequestBody中,然后使用这个RequestBody构建一个Request请求,最后将这个请求放入队列中执行

    如果我们的POST请求稍微复杂点,比如携带的参数既有文本类型的,又有文件类型的,那么可以用下面的方式来请求:

     
    //带文本参数和文件参数的post请求
    public void filePostClick(View view) {
        RequestBody fileBody = RequestBody.create(MediaType.parse("text/plain; charset=utf-8"), tempFile);
        RequestBody requestBody = new MultipartBody.Builder()
                .setType(MultipartBody.FORM)
                .addFormDataPart("username", "wangwu")
                .addFormDataPart("password", "hello12345")
                .addFormDataPart("gender", "female")
                .addFormDataPart("file", "info.txt", fileBody)
                .build();
        Request request = new Request.Builder()
                .url("http://192.168.1.170:8088/okhttp/test_param_post.php")
                .post(requestBody)
                .addHeader("token", "helloworldhelloworldhelloworld")
                .build();
        okHttpClient.newCall(request).enqueue(callback);
    }

    上面的代码中,tempFile是一个文本文件,为了POST提交文件和一些其他的参数,我们使用MultipartBody来构建一个请求体,需要注意的是,因为POST的内容含有文件,所以我们必须为这个请求体设置setType(MultipartBody.FORM)

    (3)文件的上传

    文件上传并显示进度,这个代码稍微有些复杂,下面直接上代码:

    package com.test.testokhttp;
    
    import android.os.Environment;
    import android.support.v7.app.AppCompatActivity;
    import android.os.Bundle;
    import android.view.View;
    import android.widget.ProgressBar;
    import android.widget.TextView;
    import android.widget.Toast;
    
    import java.io.File;
    import java.io.IOException;
    import java.util.concurrent.TimeUnit;
    
    import okhttp3.Call;
    import okhttp3.Callback;
    import okhttp3.Interceptor;
    import okhttp3.MediaType;
    import okhttp3.MultipartBody;
    import okhttp3.OkHttpClient;
    import okhttp3.Request;
    import okhttp3.RequestBody;
    import okhttp3.Response;
    import okhttp3.ResponseBody;
    import okio.Buffer;
    import okio.BufferedSink;
    import okio.BufferedSource;
    import okio.ForwardingSink;
    import okio.ForwardingSource;
    import okio.Okio;
    import okio.Sink;
    import okio.Source;
    
    public class UploadActivity extends AppCompatActivity {
    
        private OkHttpClient okHttpClient;
        private TextView resultTextView;
        private ProgressBar progressBar;
        private File tempFile;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_upload);
            setTitle("上传文件并显示进度");
    
            resultTextView = (TextView) findViewById(R.id.result_textview);
            progressBar = (ProgressBar) findViewById(R.id.progress_bar);
            progressBar.setMax(100);
    
            okHttpClient = new OkHttpClient.Builder()
                    .readTimeout(30, TimeUnit.SECONDS)
                    .connectTimeout(10, TimeUnit.SECONDS)
                    .writeTimeout(60, TimeUnit.SECONDS)
                    .build();
        }
    
        //点击按钮开始上传文件
        public void startUploadClick(View view) {
            tempFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "test.pdf");
            RequestBody requestBody = new MultipartBody.Builder()
                    .setType(MultipartBody.FORM)
                    .addFormDataPart("file", "test.pdf", RequestBody.create(MediaType.parse("application/pdf; charset=utf-8"), tempFile))
                    .build();
            ProgressRequestBody progressRequestBody = new ProgressRequestBody(requestBody, progressListener);
            Request request = new Request.Builder()
                    .url("http://192.168.1.170:8088/okhttp/test_upload_file.php")
                    .post(progressRequestBody)
                    .build();
            okHttpClient.newCall(request).enqueue(callback);
        }
    
        //通过实现进度回调接口中的方法,来显示进度
        private ProgressListener progressListener = new ProgressListener() {
            @Override
            public void update(long bytesRead, long contentLength, boolean done) {
                int progress = (int) (100.0 * bytesRead / contentLength);
                progressBar.setProgress(progress);
            }
        };
    
        //请求后的回调方法
        private Callback callback = new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                setResult(e.getMessage(), false);
            }
    
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                setResult(response.body().string(), true);
            }
        };
    
        //显示请求返回的结果
        private void setResult(final String msg, final boolean success) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    if (success) {
                        Toast.makeText(UploadActivity.this, "请求成功", Toast.LENGTH_SHORT).show();
                    } else {
                        Toast.makeText(UploadActivity.this, "请求失败", Toast.LENGTH_SHORT).show();
                    }
                    resultTextView.setText(msg);
                }
            });
        }
    
        //自定义的RequestBody,能够显示进度
        public class ProgressRequestBody extends RequestBody {
            //实际的待包装请求体
            private final RequestBody requestBody;
            //进度回调接口
            private final ProgressListener progressListener;
            //包装完成的BufferedSink
            private BufferedSink bufferedSink;
    
            /**
             * 构造函数,赋值
             *
             * @param requestBody      待包装的请求体
             * @param progressListener 回调接口
             */
            public ProgressRequestBody(RequestBody requestBody, ProgressListener progressListener) {
                this.requestBody = requestBody;
                this.progressListener = progressListener;
            }
    
            /**
             * 重写调用实际的响应体的contentType
             *
             * @return MediaType
             */
            @Override
            public MediaType contentType() {
                return requestBody.contentType();
            }
    
            /**
             * 重写调用实际的响应体的contentLength
             *
             * @return contentLength
             * @throws IOException 异常
             */
            @Override
            public long contentLength() throws IOException {
                return requestBody.contentLength();
            }
    
            /**
             * 重写进行写入
             *
             * @param sink BufferedSink
             * @throws IOException 异常
             */
            @Override
            public void writeTo(BufferedSink sink) throws IOException {
                if (bufferedSink == null) {
                    //包装
                    bufferedSink = Okio.buffer(sink(sink));
                }
                //写入
                requestBody.writeTo(bufferedSink);
                //必须调用flush,否则最后一部分数据可能不会被写入
                bufferedSink.flush();
    
            }
    
            /**
             * 写入,回调进度接口
             *
             * @param sink Sink
             * @return Sink
             */
            private Sink sink(Sink sink) {
                return new ForwardingSink(sink) {
                    //当前写入字节数
                    long bytesWritten = 0L;
                    //总字节长度,避免多次调用contentLength()方法
                    long contentLength = 0L;
    
                    @Override
                    public void write(Buffer source, long byteCount) throws IOException {
                        super.write(source, byteCount);
                        if (contentLength == 0) {
                            //获得contentLength的值,后续不再调用
                            contentLength = contentLength();
                        }
                        //增加当前写入的字节数
                        bytesWritten += byteCount;
                        //回调
                        progressListener.update(bytesWritten, contentLength, bytesWritten == contentLength);
                    }
                };
            }
        }
    
        //进度回调接口
        interface ProgressListener {
            void update(long bytesRead, long contentLength, boolean done);
        }
    
    }

    如果我们在项目中直接使用上面的代码来进行http请求的话,势必会比较麻烦,所以这里我们需要封装上面的代码,尽量在项目中能用简短的代码完成网络请求。另外,一个项目中肯定会有很多个网络请求,我们没必要在每次网络请求中都创建一个OkHttpClient对象,所有的请求公用一个OkHttpClient就可以了。

  • 相关阅读:
    第八周作业
    第八周上机练习
    第七周作业
    第七次上机练习
    第六周作业
    4.9上机作业
    第五周作业
    第四次JAVA作业
    第四周作业
    第十六次作业
  • 原文地址:https://www.cnblogs.com/ltw222/p/14911849.html
Copyright © 2011-2022 走看看