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

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

对于使用OkHttp进行封装,以下是一个基本的示例: 1. 首先,确保已经在项目中添加了OkHttp的依赖。在build.gradle文件中添加以下代码: ```groovy implementation 'com.squareup.okhttp3:okhttp:4.9.0' ``` 2. 创建一个HttpHelper类来封装OkHttp使用。示例代码如下: ```java import okhttp3.*; import java.io.IOException; public class HttpHelper { private final OkHttpClient client; public HttpHelper() { client = new OkHttpClient(); } public void get(String url, Callback callback) { Request request = new Request.Builder() .url(url) .build(); client.newCall(request).enqueue(callback); } public void post(String url, RequestBody requestBody, Callback callback) { Request request = new Request.Builder() .url(url) .post(requestBody) .build(); client.newCall(request).enqueue(callback); } } ``` 3. 现在可以在其他类中使用HttpHelper进行网络请求。以下是一个使用GET请求的示例: ```java import okhttp3.Call; import okhttp3.Callback; import okhttp3.Response; import java.io.IOException; public class Main { public static void main(String[] args) { HttpHelper httpHelper = new HttpHelper(); String url = "https://api.example.com/data"; httpHelper.get(url, new Callback() { @Override public void onFailure(Call call, IOException e) { // 处理请求失败的情况 } @Override public void onResponse(Call call, Response response) throws IOException { // 处理请求成功的情况 String responseData = response.body().string(); System.out.println(responseData); } }); } } ``` 以上示例中,我们首先创建了一个HttpHelper实例,然后使用get方法发送GET请求。在回调函数中,可以处理请求成功或失败的情况,并处理返回的响应数据。 对于POST请求,可以使用post方法,并传递一个RequestBody对象作为请求体。具体的请求参数和请求头信息可以根据实际需求进行设置。 这只是一个基本的封装示例,你可以根据自己的项目需求进行更多的定制和扩展。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值