[Android]OkHttp的简单封装-辅助框架

序言

OkHttp 的强大算是毋庸置疑了;OkHttp 基本在网络层能完成任何事情,适用任何情况;正因为如此 OkHttp 每次构建一个请求的时候不得不写大量的代码来完成相应的配置。在这里分享一个极限封装OkHttp的辅助框架,通过该框架能最大程度简化你的开发负担。好话不多说,往下看看就知道好不好。

原生

在这里举例几个原生情况下使用 okhttp 的情况。

GET

    public void get() {
        Request.Builder builder = new Request.Builder()
                .url("http://www.xx.com?id=dd&aa=sdd")
                .get();

        Request request = builder.build();
        Call call = new OkHttpClient().newCall(request);

        // 同步
        try {
            call.execute();
        } catch (IOException e) {
            e.printStackTrace();
        }

        // 异步
        call.enqueue(new Callback() {
            @Override
            public void onFailure(Request request, IOException e) {
            }

            @Override
            public void onResponse(Response response) throws IOException {
            }
        });
    }

Form

    public void form() {
        FormEncodingBuilder formEncodingBuilder = new FormEncodingBuilder();

        // Add values
        formEncodingBuilder.add("id", "dd");
        formEncodingBuilder.add("name", "sdd");
        RequestBody body = formEncodingBuilder.build();
        Request request = new Request.Builder().post(body).build();

        // do call...
    }

文件

    public void file() {
        MultipartBuilder builder = new MultipartBuilder();
        builder.type(MultipartBuilder.FORM);

        builder.addFormDataPart("id", "dd");
        builder.addFormDataPart("name", "sdd");

        RequestBody fileBody = RequestBody.create(MediaType.parse("image/png"), new File("aa.png"));
        builder.addFormDataPart("head", "aa.png", fileBody);

        RequestBody body = builder.build();
        Request request = new Request.Builder().post(body).build();

        // do call...
    }

不得不说,okhttp算是封装的非常Nice的框架,就算是文件发送也只是简单的几行代码就OK了。

不过假如我们需要在返回时进行UI切换,或者返回的数据进行对应的JSON解析呢?

也很简单就是得到数据后然后来一个线程切换,然后再使用GSON解析一下就好。

但是我们是否还可以简化呢?因为每次请求都需要构建build-request-发送-解析,这些操作很少,但是没必要没错重复。

初衷

之所以再次封装,就是为了让每次的build过程不再出现,当然功能肯定不能仅仅局限于此。

假如你现在登录后得到一个ID,要求后续操作都带上ID进行操作你会怎么办?

难道每次请求参数中都加上一次?这就是一个值得封装的地方。

封装只是为了能更加简单,仅此而已~

功能

  • UI 线程切换
  • 可选择的Callback(任意选择UI线程或者子线程)
  • 参数规范化,GET与POST都一样的传参方式
  • 上传/下载进度回调
  • 可以简单的设置Head部分
  • 可以每次请求时自动加上需要的参数
  • String/JSON/byte/File… 都能一样简单

用法

由于辅助代码较多,在这里就不一一贴出来了,在这里仅仅演示如何使用。

异步GET

        Http.getAsync("http://wthrcdn.etouch.cn/weather_mini", new UiCallback<String>() {
            @Override
            public void onFailure(Request request, Response response, Exception e) {
                log("getAsync:onFailed");
            }

            @Override
            public void onSuccess(String response, int code) {
                log("getAsync:onSuccess:" + response);
            }
        }, new StrParam("citykey", 101010100)
);

由于是 get 请求,在这里参数中的 citykey 会被自动解析到 url 中。

http://wthrcdn.etouch.cn/weather_mini?citykey=101010100

同步GET

final String url = "http://wthrcdn.etouch.cn/weather_mini?citykey=101010100";
String str = Http.getSync(String.class, url);
log("getSync1:" + str);

str = Http.getSync(url, new ThreadCallback<String>() {
    @Override
    public void onFailure(Request request, Response response, Exception e) {
        log("getSync2:onFailed");
    }

    @Override
    public void onSuccess(String response, int code) {
        log("getSync2:onSuccess:" + response);
    }
});
log("getSync2:" + str);

同步方式支持两种情况,一种有Callback,一种是没有。

当然就算加上了Callback也并不是异步,此时方法会等到执行完成后才会继续往下走。之所以这么干,是为了方便在callback中直接处理ui的事儿。

在这里有必要说明一下,返回类型需要进行指定,如果没有Callback哪么需要你传入返回类型class。

当然如果你传入了callback,哪么此时class就由callback

Account account = Http.getSync(Account.class, url);
User user = Http.getSync(User.class, url);
String str = Http.getSync(String.class, url, new StrParam("citykey", 101010100));

Callback 的情况也如上所示。

异步与同步的区别在于方法名称:

  • Http.getSync()
  • Http.getAsync()
  • Http.postSync()
  • Http.postAsync()
  • Http.uploadSync()
  • Http.uploadAsync()
  • Http.downloadSync()
  • Http.downloadAsync()

默认情况下,upload与download具有callProgress 回调进度功能。

POST

        String value1 = "xxx";
        String value2 = "xxx";
        String url = "http://www.baidu.com";

        Http.postAsync(url, new HttpCallback<String>() {
                    @Override
                    public void onFailure(Request request, Response response, Exception e) {
                        e.printStackTrace();
                    }

                    @Override
                    public void onSuccess(String response, int code) {
                        log(response);
                    }
                },
                new StrParam("value1", value1),
                new StrParam("value2", value2));

post 的请求方法与get基本如出一辙。

Upload

File file = getAssetsFile();
Http.uploadAsync("http://img.hoop8.com/upload.php", "uploadimg", file, new UiCallback<String>() {
    @Override
    public void onProgress(long current, long count) {
        super.onProgress(current, count);
        log("uploadAsync onProgress:" + current + "/" + count);
        mUpload.setProgress((int) ((current * 100.00 / count)));
    }

    @Override
    public void onFailure(Request request, Response response, Exception e) {
        e.printStackTrace();
        log("uploadAsync onFailed");
    }

    @Override
    public void onSuccess(String response, int code) {
        log("uploadAsync onSuccess:" + response);
    }
});

上传部分也很简单,如果需要带有参数哪么和Post的使用方式一样。当然此时传入参数就不是 StrParam 而是 IOParam.

上传的时候你可以仅仅传递文件+文件对应的name;或者 传递 IOParam; 也可以 StrParam+IOParam的方式;当然终极一点你可以传递:Param 类型。

Param 类型是 StrParam 与 IOParam 的结合体。

哪么上传你也可以这样:

Http.uploadAsync("url", callback, new IOParam("uploadimg", file));
Http.uploadAsync("url", callback,
        new StrParam[]{new StrParam("id", 123456), new StrParam("name", "qiujuer")},
        new IOParam("uploadimg", file));

Http.uploadAsync("url", callback,
        new Param("id", 123456),
        new Param("name", "qiujuer"),
        new Param("uploadimg", file));

Download

Http.downloadAsync("https://raw.githubusercontent.com/qiujuer/OkHttpPacker/master/release/sample.apk", getSDPath(), null, null, new UiCallback<File>() {
@Override
public void onProgress(long current, long count) {
    super.onProgress(current, count);
    log("downloadAsync onProgress:" + current + "/" + count);
    mDownload.setProgress((int) ((current * 100.00 / count)));
}

@Override
public void onFailure(Request request, Response response, Exception e) {
    e.printStackTrace();
    log("downloadAsync onFailed");
}

@Override
public void onSuccess(File response, int code) {
    log("downloadAsync onSuccess:" + response.getAbsolutePath());
}
});

下载这里为了方便所以强制返回File,哪么你拿到的时候就是下载好的文件了。

下载只有异步方式,也同样支持传入参数。

而在传入参数上,你可以仅仅传递一个存储目录,此时文件名会根据url进行指定。

当然你还可以传递目录+文件名。

也或者你直接传入一个文件(File)。

其中的Object是用于传入时设置Tag,方便OKHTTP进行cancel()取消。

参数

在所有方式中 Post 支持参数最多,所以这里就使用 Post 进行演示。

// 无参数情况
Http.postAsync("url", callback);

// StrParam
Http.postAsync("url", callback, new StrParam("id", 113321));

// List
List<StrParam> strParamList = new ArrayList<>();
strParamList.add(new StrParam("id", 113321));
Http.postAsync("url", callback, strParamList);

// Map
Map<String, String> strParamMap = new HashMap<>();
strParamMap.put("id", "113321");
Http.postAsync("url", callback, strParamMap);

// String
Http.postAsync("url", callback, "This is post body.");

// Byte
Http.postAsync("url", callback, new byte[]{1, 2});

// File
Http.postAsync("url", callback, new File("img.png"));

// JSON
JSONObject jsonObject = new JSONObject("json data");
Http.postAsync("url", callback, jsonObject);

// JSONArray
JSONArray jsonArray = new JSONArray();
Http.postAsync("url", callback, jsonArray);

请求构建

在本框架中,所有的请求都会把url与参数经过请求构建器进行请求体构建。所以如果你需要为你的每一个请求都带上特定的参数是非常简单的。

第一种方式:

RequestBuilder builder = Http.getInstance().getRequestBuilder();
((RequestCallBuilder) builder).setBuilderListener(new RequestCallBuilder.BuilderListener() {

    // 请求头构建,在这里你可以做一些请求头的初始化操作
    @Override
    public void onCreateBuilder(Request.Builder builder) {
        builder.addHeader("User-Agent", "User-Agent");
        builder.addHeader("Head-Content", "Head-Content");
    }

    // 构建Get时调用
    @Override
    public boolean onBuildGetParams(StringBuilder sb, boolean isFirst) {
        // isFirst 用于告知是否是第一个参数
        // 因为GET请求第一个参数是加上 "?" ,而其后参数则是加上 "&"
        // 返回时也用于告知当前参数中是否已经有参数了,
        // 如果已经有了哪么返回 false ,没有加上任何参数 返回 true
        // 或许把名称改成 haveParam 要恰当一点

        if (isFirst) {
            isFirst = false;
            sb.append("?");
        } else {
            sb.append("&");
        }
        sb.append("uid=");
        sb.append("qiujuer");

        return isFirst;
    }

    // 构建 Form body 时调用
    @Override
    public void onBuildFormBody(FormEncodingBuilder formEncodingBuilder) {
        formEncodingBuilder.add("uid", "qiujuer");
    }

    // 构建 Multipart body 时调用
    @Override
    public void onBuildMultipartBody(MultipartBuilder multipartBuilder) {
        multipartBuilder.addFormDataPart("uid", "qiujuer");
    }
});

第二种

import com.squareup.okhttp.FormEncodingBuilder;
import com.squareup.okhttp.MultipartBuilder;
import com.squareup.okhttp.Request;

import net.qiujuer.common.okhttp.impl.RequestCallBuilder;

/**
 * Created by qiujuer
 * on 16/1/13.
 */
public class MyRequestBuilder extends RequestCallBuilder {

    @Override
    protected boolean buildGetParams(StringBuilder sb, boolean isFirst) {
        if (isFirst) {
            isFirst = false;
            sb.append("?");
        } else {
            sb.append("&");
        }
        sb.append("uid=");
        sb.append("qiujuer");

        return isFirst && super.buildGetParams(sb, isFirst);
    }

    @Override
    protected FormEncodingBuilder buildFormBody(FormEncodingBuilder formEncodingBuilder) {
        formEncodingBuilder.add("uid", "qiujuer");
        return super.buildFormBody(formEncodingBuilder);
    }

    @Override
    protected MultipartBuilder buildMultipartBody(MultipartBuilder multipartBuilder) {
        multipartBuilder.addFormDataPart("uid", "qiujuer");
        return super.buildMultipartBody(multipartBuilder);
    }

    @Override
    protected Request.Builder createBuilder() {
        Request.Builder builder = super.createBuilder();
        builder.addHeader("User-Agent", "User-Agent");
        builder.addHeader("Head-Content", "Head-Content");
        return builder;
    }
}
Http.getInstance().setRequestBuilder(new MyRequestBuilder());

两种办法都是OK的,不过建议第一种,方便快捷。以后可以在第一种的方式上再封装一次,封装到 Param 层次那就简单了。

解析器

在本框架中,所有的返回都会经过解析器对返回数据进行解析;这也就达到了直接把 JSON 数据解析为 Class 的目的。

默认情况下采用GSON进行解析。你也可以重写解析器。

GSON配置

有时候返回的数据样式并不是 Gson 的默认样式(一般是时间字符串),此时会导致解析失败,这里提供一种简单的办法。

GsonBuilder gsonBuilder = new GsonBuilder();
gsonBuilder.setDateFormat("yyyy-MM-dd HH:mm:ss");
Gson gson = gsonBuilder.create();

Http.getInstance().setResolver(new GsonResolver(gson));

FastJson

如果你不想使用 Gson进行解析,或许你会采用FastJson,哪么你可以重写实现解析器。

import net.qiujuer.common.okhttp.core.Resolver;

import java.lang.reflect.Type;

/**
 * Created by qiujuer
 * on 16/1/13.
 */
public class MyResolver implements Resolver {
    @Override
    public Object analysis(String rsp, Type type) {
        return null;
    }

    @Override
    public Object analysis(String rsp, Class<?> subclass) {
        return null;
    }
}

解析方法有两种,两个方法你都需要自己去完善。

rsp 是网络返回的字符串。

Type 是等待返回的 ClassType

Cookie

关于 Cookie 支持,默认情况下 Cookie 存储是处于关闭状态,如果你想要存储网址Cookie到本地文件,并每次访问时都使用当前Cookie。

// 允许存储Cookie
Http.enableSaveCookie(getApplication());
// 清理Cookie
Http.removeCookie();
// 得到所有Cookie
Http.getCookie();

OkHttpClient

有时你需要拿到当前的 Client ,比如你可以把 Client 设置为 Glide 的网络驱动器。

OkHttpClient client = Http.getClient();
// Glide
Glide.get(application).register(GlideUrl.class, InputStream.class, new OkHttpUrlLoader.Factory(client));

调试

如果你需要知道每次请求Url与参数信息,你可以打开LOG开关。

Http.DEBUG = true;

关于 HTTPS

在当前框架中并没有直接集成 HTTPS 的支持,而是采用了一个 CertTool 证书 工具来进行 HTTPS 支持。

通过 CertTool 你可以方便的设置一个本地证书文件进行 HTTPS 请求。

CertTool.setCertificates(Http.getClient(),new FileInputStream(new File()));

Callback

HttpCallback

该Callback为默认需要,其中:

  • onStart UI 线程中执行
  • onFinish UI 线程中执行
  • onProgress, onFailure, onSuccess 子线程中执行

ThreadCallback

所有回调全部在子线程中执行。

UICallback

所有回调在UI线程中执行。

项目地址

https://github.com/qiujuer/OkHttpPacker

如果使用上有任何问题欢迎提交 issues 。

========================================================

作者:qiujuer

博客:blog.csdn.net/qiujuer

网站:www.qiujuer.net

开源库:github.com/qiujuer/Genius-Android

开源库:github.com/qiujuer/Blink

转载请注明出处:http://blog.csdn.net/qiujuer/article/details/50442600

—— 学之开源,用于开源;初学者的心态,与君共勉!

========================================================

时间: 2024-10-12 08:13:57

[Android]OkHttp的简单封装-辅助框架的相关文章

Android Toast(吐司) 简单封装

Android Toast(吐司)简单封装,且解决了Toast显示时间叠加问题. public class ToastUtil { private static Toast toast=null; public static void showToast(Context context,String content){ if(toast!=null) { toast.cancel(); } toast=Toast.makeText(context,content,Toast.LENGTH_LON

Android -- OkHttp的简单使用和封装

1,昨天把okHttp仔细的看了一下,以前都是调用同事封装好了的网络框架,直接使用很容易,但自己封装却不是那么简单,还好,今天就来自我救赎一把,就和大家写写从最基础的OKHttp的简单get.post的使用,再到它的封装. 2,OkHttp的简单使用 首先我们创建一个工程,并在布局文件中添加三个控件,TextView(用于展示获取到json后的信息).Button(点击开始请求网络).ProgressBar(网络加载提示框) ①简单的异步Get请求 第一步,创建OKHttpClient对象 第二

Android ToolBar 的简单封装

使用过 ToolBar 的朋友肯定对其使用方法不陌生,因为其用法很简单,如果对 ActionBar 使用比较熟练的人来说,ToolBar 就更容易了!不过,相信大家在使用的过程中都遇到过这样一个问题,需要在每一个我们要使用的 xml 中添加 ToolBar 这个控件,比如我需要在 MainActivity中使用 ToolBar,则他的 xml 文件需要这样写, <RelativeLayout xmlns:android="http://schemas.android.com/apk/res

Android中网络框架的简单封装

个人博客 http://www.milovetingting.cn Android中网络框架的简单封装 前言 Android作为一款主要应用在移动终端的操作系统,访问网络是必不可少的功能.访问网络,最基本的接口有:HttpUrlConnection,HttpClient,而在后续的发展中,出现了Volley,OkHttp,Retrofit等网络封装库.由于各种原因,在实际的项目开发中,我们可能会需要在项目的版本迭代中,切换网络框架.如果对于网络框架没有好的封装,那么当需要切换网络框架时,可能就会

Android使用Google推荐的联网框架Volley,让连接网络更加简单

大家好,随着技术的进步,科技的发达,很少有应用是单机的了,大部分都需要联网访问服务器,以前我们都用 httpclient和httpurlconnection,感觉是不是非常麻烦,而Google特别为开发者考虑,推出了Volley,从此妈妈再也不担心我的联网问题了,哪里联不上联哪里,Volley让联网更容易和更快,并且Volley请求会异步执行,不阻挡主线程联网请求无非就是Get或者Post,我们很少用到DELETE这个请求方式,说了这么多废话,下面让我们看看Volley到底能干啥.它真的有这么神

okhttp的简介(二)之简单封装

前一篇文章简单的介绍了okhttp的简单使用.okhttp的简介(一):http://blog.csdn.net/wuyinlei/article/details/50579564 相信使用还是非常好使用的. 可是,怎么说呢,我们应该不想,每次使用的时候都去又一次写一遍代码,或者是复制代码,这样不仅或降低效率,并且还会是代码冗余. 这个时候.採用封装就能够解决我们的问题了,把同样的代码,封装到一起,对外提供一个调用的接口.每次调用的时候.我们仅仅须要调用接口,传入数据.就能够了,我们全然不用去理

Android简单封装类似JQuery异步请求

在android开发中经常会使用异步请求数据,通常会使用handler或者AsyncTask去做,handler 配合message 使用起来比较麻烦,AsyncTask 线程池只允许128个线程工作,会有溢出的问题,(当然一般情况不会有那么多线程同时工作的)所以写了这个代码,还望高手指正! [Java]代码 01 package com.xbl.task; 02 03 import java.io.BufferedReader; 04 import java.io.InputStream; 0

bsd socket 简单封装。支持android、ios、mac osx

cocos2d-x官方没有封装原生socket,只提供了websocket,如果我们需要socket,不同团队有不同的造轮子的方案,其中使用Asio库的比较多,但是Asio库太过于庞大,我不太想用.其实只需要简单封装一下bsd socket就好了,几十行代码而已. 注意如果在android中测试,需要添加网络访问权限,而且不能在主线程中使用. 贴一发代码,只是简单测试了下,如果有问题再慢慢完善. 1 #ifndef __cpp_test__Socket__ 2 #define __cpp_tes

简单的struts2框架(四)---封装实体

接着以前的<简单的struts2框架(三)>,进一步优化 封装实体: 在action声明实体类:private Users user; 对实体类进行get,set方法 这样在方法里就不用对实体类进行一个个属性set值了,直接调用实体就可以了,免去了原来赋值的很多代码 代码: 1 private Users user; 2 private UserService userservice=new UserService(); 3 /** 4 * 用户注册 5 * @return 6 */ 7 pu