OkHttpClient使用和封装

OkHttpClient使用和封装

最近的项目用到了底部弹窗的效果,网上百度了很多类似写好的控件,其中也不乏好的实现。但是为了方便以后扩展,总结了一下前人的经验自己写了实现了一个类:



环境配置

目前安卓开发者普遍使用AS开发,所以这里只介绍引入依赖的配置方式,同时引入Gson作为后面数据解析的工具。

implementation 'com.squareup.okhttp3:okhttp:3.2.0'
implementation 'com.google.code.gson:gson:2.3.1'

引入库以后,需要在AndroidManifest文件中获取网络访问权限

 <uses-permission android:name="android.permission.INTERNET" />

同步GET请求

//同步GET方法,execute()方法会抛出IOException异常
    private void syncNetAccess() throws IOException {

        //创建OkHttpClient实例,主要用于请求网络
        OkHttpClient okHttpClient = new OkHttpClient();

        //创建Request实例,可以配置接口地址和请求头
        Request okRequest = new Request.Builder().url("http://toutiao-ali.juheapi.com/toutiao/index?type=caijing").build();

        //GET请求,用Response接受相应结果
        Response response = okHttpClient.newCall(okRequest).execute();

        //response.body()为请求返回数据 JSON格式
        Log.d("+++++++++++++++++++++",response.body().string();
    }

这里值得注意的一点,response.body()这个方法很奇怪只能获取一次,再调用只能得到null,所以有打印结果习惯的不要入坑。

另外一个坑就是线程的问题,现在的系统版本不支持在主线程,这样请求的话会报错:NetworkOnMainThreadException。

解决的办法有两种:一是添加StrictMode约束。

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

另外一种就是创建一个新的线程Thread,因为代码比较多,为了不干扰本文的主题在这里就不详说了。

那么,既然同步请求这么坑爹,为什么不直接使用异步请求呢?

异步GET请求

 //异步GET方法
    private void asyncNetAccess() throws IOException {

        //创建OkHttpClient实例,主要用于请求网络
        OkHttpClient okHttpClient = new OkHttpClient();

        //创建Request实例,这里配置了请求头 addHeader()
        Request okRequest = new Request.Builder().url("http://toutiao-ali.juheapi.com/toutiao/index?type=caijing").addHeader("name","value").build();

        //GET请求,回调函数中获取相应结果
       okHttpClient.newCall(okRequest).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.d("+++++++++++++++++++++",e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                Log.d("+++++++++++++++++++++",response.body().string());
            }
        });

    }

异步请求初始化的方式差不多,只是在最后请求网络的时候改为enqueue()方法,并且创建了一个Callback来异步处理返回的结果,不在需要Response接收。其中,onFailure和onResponse分别是访问失败和成功的回调。

值得注意的,这里创建Request实例的时候加入了响应头Header,应用场景嘛比如一些公共的接口会需要身份验证,就需要添加响应头。这里是通过addHeader()方法添加key-value值,有点类似Map。

具体使用:
addHeader(“name”,“value”) 。当然响应头可以add多次,并且后面也会讲到批量添加的方法。

异步POST请求

POST请求也有异步和同步之分,发送请求的时候与GET请求是一样的,在这里不再介绍赘述。参照异步POST请求代码就知道同步代码是什么样的了。

 //异步POST方法
    private void asyncPostAccess() throws IOException {

        //创建OkHttpClient实例,主要用于请求网络
        OkHttpClient okHttpClient = new OkHttpClient();

        //创建表单请求体
        FormBody.Builder formBody = new FormBody.Builder();
        //传递键值对参数
        formBody.add("name","shuaige");

        //创建Request实例,设置POST参数
        Request okRequest = new Request.Builder().url("http://toutiao-ali.juheapi.com/toutiao/index?type=caijing").post(formBody.build()).build();

        //POST异步请求,回调函数中获取相应结果
        okHttpClient.newCall(okRequest).enqueue(new Callback() {
            @Override
            public void onFailure(Call call, IOException e) {
                Log.d("+++++++++++++++++++++",e.getMessage());
            }
            @Override
            public void onResponse(Call call, Response response) throws IOException {
                Log.d("+++++++++++++++++++++",response.body().string());
            }
        });

    }

FormBody.Builder作为请求参数的创建,配置request时候调用post()方法传入请求参数的同时规定了请求方式,就是这么简单~

OkHttpUtil工具类封装 让网络请求更轻松

通过上面的例子我们不难发现,在每次请求网络之前都会创建一个实例:
OkHttpClient okHttpClient = new OkHttpClient();

并且每次网络访问都需要
okHttpClient.newCall() 来实现。

这显然不符合面向对象的的三要素的要求(更不符合懒蛋程序猿的要求)。作为当之无愧的程序猿,我义无反顾的对网络请求做了一个封装,方便以后其他项目上使用。

首先创建一个工具类:OkHttpUtil,这里为了节省一下内存我用了单例模式来封装,毕竟网络请求是APP的核心嘛,用的次数不要太多。

至于单例怎么写本着能省则省态度,以后找一章专门来记录。不多说,下面上代码。

package com.dzh.goldmarket.util;

import okhttp3.Callback;
import okhttp3.Headers;
import okhttp3.OkHttpClient;
import okhttp3.Request;

public class OkHttpUtil {

    private volatile static OkHttpUtil okHttpUtil = null;
    private static OkHttpClient okHttpClient = null;

    public static OkHttpUtil getInstance(){
        if(okHttpUtil == null){
            synchronized (OkHttpUtil.class){
                if(okHttpUtil == null){
                    okHttpUtil=new OkHttpUtil();
                    if(okHttpClient==null)
                        okHttpClient = new OkHttpClient();
                }
            }
        }
        return okHttpUtil;
    }

    public void doGet(String url, Headers headers, Callback callback){

        Request.Builder builder = new Request.Builder().url(url);
        //添加响应头集合
        if(headers!=null)
            builder.headers(headers);

        Request okRequest = builder.build();
        okHttpClient.newCall(okRequest).enqueue(callback);
    }

    public void doGet(String url, Callback callback){
        this.doGet(url,null,callback);
    }

}


这里doGet()实现了一个异步GET请求,其中Headers参数是响应头集合,Callback作为回调函数用法跟之前差不多,下面是具体的调用方法:

private void getNewsList() throws IOException, JSONException {
        String url="http://toutiao-ali.juheapi.com/toutiao/index?type=caijing";
        //name-value格式,可以多个header, 如("name1","value1","name2","value2")
        Headers headers =Headers.of("Authorization","APPCODE vjpawenapasj23sfln3");
        Request okRequest = new Request.Builder().url("http://toutiao-ali.juheapi.com/toutiao/index?type=caijing").addHeader("Authorization","APPCODE 545beb7b4c744411988486b946bca3cd").build();
        OkHttpUtil.getInstance().doGet(url,headers,new Callback(){

            @Override
            public void onFailure(Call call, IOException e) {
                Log.d("+++++++++++++++++++++",e.getMessage());
            }

            @Override
            public void onResponse(Call call, Response response) throws IOException {
                String bodyStr = response.body().string();
				//Gson解析返回结果
                newsEntities = new Gson().fromJson(bodyStr, NewsResultEntity.class);

                //多线程,需要在UI线程中更新APP界面
                getActivity().runOnUiThread(new Runnable() {
                    @Override
                    public void run() {
                        newListView.setAdapter(new NewsAdapter(newsEntities.getResult().getData(),getActivity()));
                    }
                });
            }
        });

    }

需要注意一点:异步网络请求是多线程调用的,一般网络请求伴随的就是更新UI界面,所以需要调用runOnUiThread()方法在主线程中更新APP界面。

OK,使用方法和封装方法到此结束,开发中遇到的坑也一一列举。另外网络请求的一些配置,如超时、缓存等,以后有需要再慢慢补充。

(督促自己养成编写项目笔记的习惯,留作日后复习使用)

  • 3
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值