RxJavaAndroid开发积累安卓网络

RxJava<第三十篇>:Android开发必须了解

2019-04-02  本文已影响17人  NoBugException
(1)添加依赖库
implementation 'com.squareup.okhttp3:okhttp:3.14.0'
(2)解决引入依赖库之后的异常

引入依赖库之后需要对Java8的编译支持,否则会报错,在build.gradle中添加:

compileOptions {
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
}
图片.png
(3)添加网络权限
<uses-permission android:name="android.permission.INTERNET" />
(4)Get请求

使用call.execute()实现同步调用,但是从Android3.0之后出现一个新的策略,凡是网络请求必须在异步线程执行,不能在UI线程执行,否则抛出异常,所以以下代码的网络请求部分必须在子线程执行

            //(1)创建client对象
            OkHttpClient client = new OkHttpClient.Builder().build();
            //(2)创建Request对象
            Request request = new Request.Builder()
                    .get()
                    .url("https:www.baidu.com")
                    .build();
            //(3)将Request封装成Call
            Call call = client.newCall(request);

            new Thread(new Runnable() {
                @Override
                public void run() {
                    try {
                        //(4)开始Get请求
                        Response response = call.execute();
                        if(response.isSuccessful()){

                        }else{

                        }
                        Log.d("aaa", response.body().toString());
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }).start();

在平时,我们应当尽量避免在UI线程执行网络请求,因为网络请求必然会阻塞UI线程。
其实call.execute()是可以在UI线程执行的,我们可以通过代码取消Android3.0对网络请求不能在UI线程执行的限制

    StrictMode.ThreadPolicy policy=new StrictMode.ThreadPolicy.Builder().permitAll().build();
    StrictMode.setThreadPolicy(policy);

onCreate方法中添加这两句代码就可以让call.execute()在主线程执行。

            //(1)创建client对象
            OkHttpClient client = new OkHttpClient.Builder().build();
            //(2)创建Request对象
            Request request = new Request.Builder()
                    .get()
                    .url("https:www.baidu.com")
                    .build();
            //(3)将Request封装成Call
            Call call = client.newCall(request);

            //(4)开始Get请求
            Response response = null;
            try {
                response = call.execute();
                if(response.isSuccessful()){
                    
                }else{
                    
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            Log.d("aaa", response.body().toString());

异步调用onFailureonResponse是在非UI线程上执行的。

(5)Post请求
            //创建client对象
            OkHttpClient client = new OkHttpClient();
            //创建FormBody对象,并传参
            FormBody formBody = new FormBody.Builder()
                    .add("username", "admin")
                    .add("password", "admin")
                    .build();
            //创建request对象
            Request request = new Request.Builder()
                    .url("http://www.jianshu.com/")
                    .post(formBody)
                    .build();
            //将Request封装成Call
            Call call = client.newCall(request);
            //开始网络请求
            call.enqueue(new Callback() {
                @Override
                public void onFailure(Call call, IOException e) {
                    Log.d("aaa", "11111111111111");
                }

                @Override
                public void onResponse(Call call, Response response) throws IOException {
                    String res = response.body().string();
                    Log.d("aaa", "22222:"+res);

                }
            });

同步调用和Get请求一致。

(6)OkHttpClient

OkHttpClient可配置的属性有

        OkHttpClient client=new OkHttpClient.Builder()
                .connectTimeout(60, TimeUnit.SECONDS)       //设置连接超时
                .readTimeout(60, TimeUnit.SECONDS)          //设置读超时
                .writeTimeout(60,TimeUnit.SECONDS)          //设置写超时
                .retryOnConnectionFailure(true)             //是否自动重连
                .build();                                   //构建OkHttpClient对象

内存的释放

            client.dispatcher().executorService().shutdown();   //清除并关闭线程池
            client.connectionPool().evictAll();                 //清除并关闭连接池
            client.cache().close();                             //清除cache

newBuilder的使用

OkHttpClient eagerClient = client.newBuilder() 
       .readTimeout(500, TimeUnit.MILLISECONDS)
       .build();

这样创建的实例与原实例共享线程池、连接池和其他设置项,只需进行少量配置就可以实现特殊需求。

(7)Request

Request是网络请求的对象,其本身的构造函数是private的,只能通过Request.Builder来构建(建造者设计模式)。下面代码展示了常用的设置项。

    Request request = new Request.Builder()
            .url("https://api.github.com/repos/square/okhttp/issues")                          //设置访问url
            .get()                                                                             //类似的有post、delete、patch、head、put等方法,对应不同的网络请求方法
            .header("User-Agent", "OkHttp Headers.java")                                       //设置header
            .addHeader("Accept", "application/json; q=0.5")                                    //添加header
            .removeHeader("User-Agent")                                                        //移除header
            .headers(new Headers.Builder().add("User-Agent", "OkHttp Headers.java").build())   //移除原有所有header,并设置新header
            .addHeader("Accept", "application/vnd.github.v3+json")
            .build();
(8)RequestBodyFormBodyMultipartBody
图片.png

从上图可知,创建RequestBody请求体支持文件、byte数组以及字符串。

就以字符串为例

            JSONObject jsonObject = new JSONObject();
            try {
                jsonObject.put("username", "admin");
                jsonObject.put("password", "admin");
            } catch (JSONException e) {
                e.printStackTrace();
            }
            RequestBody requestBody = RequestBody.create(MediaType.parse("application/json; charset=utf-8"), jsonObject.toString());

另外,requestBody可以获取以下属性

图片.png

contentLength: 消息体长度
isDuplex: 是否支持双工
isOneShot: 是否支持单工
contentType: 获取MediaType

这里还需要重点介绍一下MediaType,可分为::

json: application/json
xml: application/xml
png: image/png
jpg: image/jpeg
gif: imge/gif
form: application/x-www-form-urlencoded

使用时最好带上编码:MediaType.parse("application/json; charset=utf-8")

FromBody用于提交表单键值对,其作用类似于HTML中的<form>标记。

FormBody是RequestBody的子类,从源码可以看出它默认MediaType是application/x-www-form-urlencoded

图片.png

FormBody支持设置键值对

            RequestBody formBody = new FormBody.Builder()
                    .add("username", "admin")
                    .add("password", "admin")
                    .addEncoded(URLEncoder.encode("A"), URLEncoder.encode("B"))
                    .build();

FormBody 的两个方法addaddEncoded可以添加键值对。

FormBody对象可以获取到的值如图所示:

图片.png

encodedName: 指定角标,获取已编码的key;
encodedValue: 指定角标,获取已编码的value;
name: 指定角标获取key;
value: 指定角标获取value;
contentLength: 获取请求体的长度;
contentType: 获取MediaType类型;
size: 获取键值对的数量

使用MultipartBody.Builder可以构建与HTML文件上传格式兼容的复杂请求体。多块请求体中每块请求都是一个独立的请求体,都可以定义自己的请求头。这些请求头应该用于描述对应的请求体,例如Content-Disposition,Content-Length,和Content-Type会自动被添加到请求头中。

它有五种MediaType,分别是:

MultipartBody.MIXED: "multipart/mixed"
MultipartBody.ALTERNATIVE: "multipart/alternative"
MultipartBody.DIGEST: "multipart/digest"
MultipartBody.PARALLEL: "multipart/parallel"
MultipartBody.FORM: "multipart/form-data"

MultipartBody.FORM 比较常用,其他四种查询了很多资料也没有完全理清楚。

multipartBody可调用的方法有:

图片.png

setType: 设置MediaType
addFormDataPart:

图片.png
两个参数:键值对
三个参数:键值对+文件消息体(一般用于文件上传)

addPart: 每个Part(块)都会封装一个请求体

图片.png

代码如下:

            RequestBody multipartBody = new MultipartBody.Builder()
                    .setType(MultipartBody.FORM)
                    .addPart(
                            Headers.of("Content-Disposition", "form-data; name=\"title\""),
                            RequestBody.create(null, "Logo"))
                    .addPart(
                            Headers.of("Content-Disposition", "form-data; name=\"image\""),
                            RequestBody.create(MediaType.parse("image/png"), new File("website/static/logo.png")))
                    .addFormDataPart("discription","beautiful")
                    .build();
(9)Call

Call对象表示一个已经准备好可以执行的请求,用这个对象可以查询请求的执行状态,或者取消当前请求。它具有以下方法:

    Call call=client.newCall(request);              //获取Call对象
    Response response=call.execute();               //同步执行网络请求,不要在主线程执行
    call.enqueue(new Callback());                   //异步执行网络请求
    call.cancel();                                  //取消请求
    call.isCanceled();                              //查询是否取消
    call.isExecuted();                              //查询是否被执行过

要注意的是,每个Call对象只能执行一次请求。如果想重复执行相同的请求,可以:

Call reCall=client.newCall(call.request());     //获取另一个相同配置的Call对象
(10)Response

Response是网络请求的结果下面是一些常用方法:

    Response response=call.execute();               //获取Response对象
    response.code();                                //请求的状态码
    response.isSuccessful();                        //如果状态码为[200..300),则表明请求成功
    Headers headers=response.headers();              //获取响应头
    List<String> names=response.headers("name");     //获取响应头中的某个字段
    ResponseBody body=response.body();             //获取响应体

其中ResponseBody代表响应体,用于操作网络请求返回的内容。常用方法如下:

    body.contentLength();                           //body的长度
    String content=body.string();                   //以字符串形式解码body
    byte[] byteContent=body.bytes();                //以字节数组形式解码body
    InputStreamReader reader=body.charStream();     //将body以字符流的形式解码
    InputStream inputStream=body.byteStream();      //将body以字节流的形式解码

需要注意的是:

上一篇下一篇

猜你喜欢

热点阅读