• Android学习——使用okhttp


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

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

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

    (1)GET请求

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

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

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

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

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

     1 //请求后的回调接口
     2 private Callback callback = new Callback() {
     3     @Override
     4     public void onFailure(Call call, IOException e) {
     5         setResult(e.getMessage(), false);
     6     }
     7  
     8     @Override
     9     public void onResponse(Call call, Response response) throws IOException {
    10         setResult(response.body().string(), true);
    11     }
    12 };

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

    (2)POST请求

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

     1 //简单的带参数和Header的post请求
     2 public void simplePostClick(View view) {
     3     okHttpClient = new OkHttpClient();
     4     RequestBody requestBody = new FormBody.Builder()
     5             .add("username", "wangwu")
     6             .add("password", "hello12345")
     7             .add("gender", "female")
     8             .build();
     9     Request request = new Request.Builder()
    10             .url("http://192.168.1.170:8088/okhttp/test_simple_post.php")
    11             .post(requestBody)
    12             .addHeader("token", "helloworldhelloworldhelloworld")
    13             .build();
    14     okHttpClient.newCall(request).enqueue(callback);
    15 }

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

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

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

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

    (3)文件的上传

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

      1 package com.test.testokhttp;
      2  
      3 import android.os.Environment;
      4 import android.support.v7.app.AppCompatActivity;
      5 import android.os.Bundle;
      6 import android.view.View;
      7 import android.widget.ProgressBar;
      8 import android.widget.TextView;
      9 import android.widget.Toast;
     10  
     11 import java.io.File;
     12 import java.io.IOException;
     13 import java.util.concurrent.TimeUnit;
     14  
     15 import okhttp3.Call;
     16 import okhttp3.Callback;
     17 import okhttp3.Interceptor;
     18 import okhttp3.MediaType;
     19 import okhttp3.MultipartBody;
     20 import okhttp3.OkHttpClient;
     21 import okhttp3.Request;
     22 import okhttp3.RequestBody;
     23 import okhttp3.Response;
     24 import okhttp3.ResponseBody;
     25 import okio.Buffer;
     26 import okio.BufferedSink;
     27 import okio.BufferedSource;
     28 import okio.ForwardingSink;
     29 import okio.ForwardingSource;
     30 import okio.Okio;
     31 import okio.Sink;
     32 import okio.Source;
     33  
     34 public class UploadActivity extends AppCompatActivity {
     35  
     36     private OkHttpClient okHttpClient;
     37     private TextView resultTextView;
     38     private ProgressBar progressBar;
     39     private File tempFile;
     40  
     41     @Override
     42     protected void onCreate(Bundle savedInstanceState) {
     43         super.onCreate(savedInstanceState);
     44         setContentView(R.layout.activity_upload);
     45         setTitle("上传文件并显示进度");
     46  
     47         resultTextView = (TextView) findViewById(R.id.result_textview);
     48         progressBar = (ProgressBar) findViewById(R.id.progress_bar);
     49         progressBar.setMax(100);
     50  
     51         okHttpClient = new OkHttpClient.Builder()
     52                 .readTimeout(30, TimeUnit.SECONDS)
     53                 .connectTimeout(10, TimeUnit.SECONDS)
     54                 .writeTimeout(60, TimeUnit.SECONDS)
     55                 .build();
     56     }
     57  
     58     //点击按钮开始上传文件
     59     public void startUploadClick(View view) {
     60         tempFile = new File(Environment.getExternalStorageDirectory().getAbsolutePath() + File.separator + "test.pdf");
     61         RequestBody requestBody = new MultipartBody.Builder()
     62                 .setType(MultipartBody.FORM)
     63                 .addFormDataPart("file", "test.pdf", RequestBody.create(MediaType.parse("application/pdf; charset=utf-8"), tempFile))
     64                 .build();
     65         ProgressRequestBody progressRequestBody = new ProgressRequestBody(requestBody, progressListener);
     66         Request request = new Request.Builder()
     67                 .url("http://192.168.1.170:8088/okhttp/test_upload_file.php")
     68                 .post(progressRequestBody)
     69                 .build();
     70         okHttpClient.newCall(request).enqueue(callback);
     71     }
     72  
     73     //通过实现进度回调接口中的方法,来显示进度
     74     private ProgressListener progressListener = new ProgressListener() {
     75         @Override
     76         public void update(long bytesRead, long contentLength, boolean done) {
     77             int progress = (int) (100.0 * bytesRead / contentLength);
     78             progressBar.setProgress(progress);
     79         }
     80     };
     81  
     82     //请求后的回调方法
     83     private Callback callback = new Callback() {
     84         @Override
     85         public void onFailure(Call call, IOException e) {
     86             setResult(e.getMessage(), false);
     87         }
     88  
     89         @Override
     90         public void onResponse(Call call, Response response) throws IOException {
     91             setResult(response.body().string(), true);
     92         }
     93     };
     94  
     95     //显示请求返回的结果
     96     private void setResult(final String msg, final boolean success) {
     97         runOnUiThread(new Runnable() {
     98             @Override
     99             public void run() {
    100                 if (success) {
    101                     Toast.makeText(UploadActivity.this, "请求成功", Toast.LENGTH_SHORT).show();
    102                 } else {
    103                     Toast.makeText(UploadActivity.this, "请求失败", Toast.LENGTH_SHORT).show();
    104                 }
    105                 resultTextView.setText(msg);
    106             }
    107         });
    108     }
    109  
    110     //自定义的RequestBody,能够显示进度
    111     public class ProgressRequestBody extends RequestBody {
    112         //实际的待包装请求体
    113         private final RequestBody requestBody;
    114         //进度回调接口
    115         private final ProgressListener progressListener;
    116         //包装完成的BufferedSink
    117         private BufferedSink bufferedSink;
    118  
    119         /**
    120          * 构造函数,赋值
    121          *
    122          * @param requestBody      待包装的请求体
    123          * @param progressListener 回调接口
    124          */
    125         public ProgressRequestBody(RequestBody requestBody, ProgressListener progressListener) {
    126             this.requestBody = requestBody;
    127             this.progressListener = progressListener;
    128         }
    129  
    130         /**
    131          * 重写调用实际的响应体的contentType
    132          *
    133          * @return MediaType
    134          */
    135         @Override
    136         public MediaType contentType() {
    137             return requestBody.contentType();
    138         }
    139  
    140         /**
    141          * 重写调用实际的响应体的contentLength
    142          *
    143          * @return contentLength
    144          * @throws IOException 异常
    145          */
    146         @Override
    147         public long contentLength() throws IOException {
    148             return requestBody.contentLength();
    149         }
    150  
    151         /**
    152          * 重写进行写入
    153          *
    154          * @param sink BufferedSink
    155          * @throws IOException 异常
    156          */
    157         @Override
    158         public void writeTo(BufferedSink sink) throws IOException {
    159             if (bufferedSink == null) {
    160                 //包装
    161                 bufferedSink = Okio.buffer(sink(sink));
    162             }
    163             //写入
    164             requestBody.writeTo(bufferedSink);
    165             //必须调用flush,否则最后一部分数据可能不会被写入
    166             bufferedSink.flush();
    167  
    168         }
    169  
    170         /**
    171          * 写入,回调进度接口
    172          *
    173          * @param sink Sink
    174          * @return Sink
    175          */
    176         private Sink sink(Sink sink) {
    177             return new ForwardingSink(sink) {
    178                 //当前写入字节数
    179                 long bytesWritten = 0L;
    180                 //总字节长度,避免多次调用contentLength()方法
    181                 long contentLength = 0L;
    182  
    183                 @Override
    184                 public void write(Buffer source, long byteCount) throws IOException {
    185                     super.write(source, byteCount);
    186                     if (contentLength == 0) {
    187                         //获得contentLength的值,后续不再调用
    188                         contentLength = contentLength();
    189                     }
    190                     //增加当前写入的字节数
    191                     bytesWritten += byteCount;
    192                     //回调
    193                     progressListener.update(bytesWritten, contentLength, bytesWritten == contentLength);
    194                 }
    195             };
    196         }
    197     }
    198  
    199     //进度回调接口
    200     interface ProgressListener {
    201         void update(long bytesRead, long contentLength, boolean done);
    202     }
    203  
    204 }

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

  • 相关阅读:
    ElementInject/Provide调用组件中的方法
    CSS样式的继承
    CSS 背景图片
    CSS内外间距
    CSS列表属性
    CSS文件属性设置
    CSS文件属性的设置03
    CSS margin(外)间距案例
    CSS 清除float(浮动)属性案例Windows系统logo
    CSS伪类选择器扩展
  • 原文地址:https://www.cnblogs.com/znjy/p/14909061.html
Copyright © 2020-2023  润新知