Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> [Android]OkHttp的簡單封裝-輔助框架

[Android]OkHttp的簡單封裝-輔助框架

編輯:關於Android編程

序言

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() {
            @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() {
    @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() {
                    @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() {
    @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() {
@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 strParamList = new ArrayList<>();
strParamList.add(new StrParam("id", 113321));
Http.postAsync("url", callback, strParamList);

// Map
Map 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
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線程中執行。

 
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved