本文為菜鳥窩作者蔣志碧的連載×眩“從 0 開始開發(fā)一款直播 APP ”系列來聊聊時下最火的直播 APP唯卖,如何完整的實現(xiàn)一個類"騰訊直播"的商業(yè)化項目
視頻地址:http://www.cniao5.com/course/10121
【從 0 開始開發(fā)一款直播 APP】4.1 網(wǎng)絡(luò)封裝之 Okhttp -- 基礎(chǔ)回顧
【從 0 開始開發(fā)一款直播 APP】4.2 網(wǎng)絡(luò)封裝之 OkHttp -- GET粱玲,POST,前后端交互
【從 0 開始開發(fā)一款直播 APP】4.3 網(wǎng)絡(luò)封裝之 OkHttp -- 封裝 GET拜轨,POST FORM抽减,POST JSON
【從 0 開始開發(fā)一款直播 APP】4.4 網(wǎng)絡(luò)封裝之 OkHttp -- 網(wǎng)絡(luò)請求實現(xiàn)直播登錄
封裝 OkHttp 框架,主要功能有:
GET 請求
POST FORM
POST JSON
封裝之前橄碾,再次熟悉一下 OkHttp 請求網(wǎng)絡(luò)的大致步驟卵沉,讓封裝的時候思路清晰一點(diǎn)。
//1法牲、初始化 OkHttpClient 對象
private OkHttpClient mHttpClient = new OkHttpClient();
//2史汗、構(gòu)造Request
//2.1 構(gòu)造RequestBody
FormEncodingBuilder builder = new FormEncodingBuilder();
RequestBody requestBody = builder.add("key", "value").build();
final Request request = new Request
.Builder()
.post(requestBody)
.url(url)
.build();
//3、將 Request 封裝成 call
final Call call = mHttpClient.newCall(request);
//4拒垃、執(zhí)行 call
call.enqueue(new Callback() {
//請求失敗調(diào)用
@Override
public void onFailure(Request request, IOException e) {
}
//請求成功調(diào)用
@Override
public void onResponse(Response response) throws IOException {
}
});
OkHttp 請求基本步驟就是這幾步停撞,看起來很簡單,要封裝自然也要考慮到這里面的方方面面恶复,根據(jù)自己的業(yè)務(wù)需求進(jìn)行相應(yīng)的封裝怜森。封裝是基于鴻洋大神的 OkHttpUtils,站在巨人的肩膀上谤牡,我們封裝起來會更加簡單副硅。
1、OkHttpClient 實例化
聲明一個私有的 OkHttpClient 對象翅萤,對其進(jìn)行構(gòu)建并設(shè)置超時信息恐疲,而 AsyncHttp 類則是我們要進(jìn)行網(wǎng)絡(luò)訪問對外公開的類,OkHttpClient 官方建議我們設(shè)置成單例模式套么。
public class AsyncHttp {
private static AsyncHttp mInstance;
//初始化操作培己,設(shè)置超時時間
private OkHttpClient okHttpClient = new OkHttpClient.Builder()
.connectTimeout(20 * 1000, TimeUnit.MILLISECONDS)
.readTimeout(20 * 1000, TimeUnit.MILLISECONDS)
.build();
//私有構(gòu)造函數(shù),初始化 OkHttpClient 對象
private AsyncHttp() {
OkHttpUtils.initClient(okHttpClient);
}
//單例模式
public static AsyncHttp instance() {
if (mInstance == null) {
synchronized (OkHttpUtils.class) {
if (mInstance == null) {
mInstance = new AsyncHttp();
}
}
}
return mInstance;
}
}
2胚泌、構(gòu)造 GET 請求
get 請求官方給我們的是沒有參數(shù)的省咨,不滿足我們需求,根據(jù)我們的需求將其進(jìn)行封裝玷室。GET 請求需要 Request 對象傳參零蓉,還需要回調(diào) CallBack,因此需要添加 Request 基類和 CallBack 基類穷缤。
public void get(IRequest request, IHttpListener listener) {}
IRequest 是 Request 的封裝類敌蜂,IHttpListener 是回調(diào) CallBack 的監(jiān)聽。
2.1津肛、封裝 IRequest
我們知道官方提供的 Request 類是對請求信息進(jìn)行封裝章喉,包括請求地址 url,請求方法 method,請求頭 head秸脱,請求體 RequestBody落包,取消 http 請求的標(biāo)志 tag。IRequest 是一個抽象類撞反,請求信息封裝在 RequestParams 類里面妥色,IRequest 對外提供了一些方法,獲取請求參數(shù)遏片,獲取/設(shè)置唯一標(biāo)識,獲取 Url撮竿,獲取解析的數(shù)據(jù)類型吮便。
//IDontObfuscate 實現(xiàn) Serializable 的一個抽象類
public abstract class IRequest extends IDontObfuscate {
//測試登錄的 API
public static final String HOST_PUBLIC = "http://live.demo.cniao5.com/Api/";
public static final String HOST_DEBUG = "http://192.168.31.92:8094/Api/";
//判斷上面兩個 API 使用哪一個。表示猜不透直播老師的心啊幢踏,不知道為什么要這樣
private boolean DEBUG = false;
//Request 請求信息封裝類
protected RequestParams mParams = new RequestParams();
//請求網(wǎng)絡(luò)直播登錄的唯一標(biāo)識
public int mRequestId = 0;
protected int mDraw = 0;
public IRequest() {
}
/**
* 接口請求參數(shù)
*/
public RequestParams getParams() {
return mParams;
}
/**
* 設(shè)置接口請求唯一標(biāo)識
*/
public void setRequestId(int requestId) {
mRequestId = requestId;
}
/**
* 返回請求接口唯一標(biāo)識
*/
public int getRequestId() {
return mRequestId;
}
/**
* 當(dāng)前接口的url地址
*/
public abstract String getUrl();
/**
* 獲取解析類型
*/
public abstract Type getParserType();
/**
* 返回服務(wù)器接口地址
*/
protected String getHost() {
return DEBUG ? HOST_DEBUG : HOST_PUBLIC;
}
@Override
public String toString() {
return "IRequest [DEBUG=" + DEBUG
+ ", mParams=" + mParams + ", mRequestId=" + mRequestId
+ ", mDraw=" + mDraw + "]";
}
//是否緩存
public boolean isCache() {
return false;
}
}
RequestParams 請求參數(shù)封裝
參數(shù)封裝類髓需,顧名思義就是對參數(shù)的保存和移除,該類適用于 GET 和 POST 參數(shù)房蝉,包括 url 參數(shù)封裝僚匆,stream 參數(shù)封裝,file 參數(shù)封裝搭幻,file 數(shù)組參數(shù)封裝咧擂,url 對象參數(shù)封裝。全部都是存儲在 ConcurrentHashMap 對象中檀蹋,通過鍵值對進(jìn)行存儲松申,put 方法有很多重載,對不同形式的參數(shù)采取不同的添加方式俯逾。
public class RequestParams implements Serializable{
//二進(jìn)制流數(shù)據(jù)
public final static String APPLICATION_OCTET_STREAM = "application/octet-stream";
//JSON數(shù)據(jù)格式
public final static String APPLICATION_JSON = "application/json";
protected final static String LOG_TAG = "RequestParams";
//存儲 url 參數(shù)
protected final ConcurrentHashMap<String, String> urlParams = new ConcurrentHashMap<String, String>();
//存儲 stream 參數(shù)
protected final ConcurrentHashMap<String, StreamWrapper> streamParams = new ConcurrentHashMap<String, StreamWrapper>();
//存儲 file 參數(shù)
protected final ConcurrentHashMap<String, FileWrapper> fileParams = new ConcurrentHashMap<String, FileWrapper>();
//存儲 fileArray 參數(shù)
protected final ConcurrentHashMap<String, List<FileWrapper>> fileArrayParams = new ConcurrentHashMap<String, List<FileWrapper>>();
//存儲 url 對象參數(shù)
protected final ConcurrentHashMap<String, Object> urlParamsWithObjects = new ConcurrentHashMap<String, Object>();
//是否重復(fù)
protected boolean isRepeatable;
//標(biāo)志 multipart/form-data:需要在表單中進(jìn)行文件上傳時贸桶,就需要使用該格式
protected boolean forceMultipartEntity = false;
//用戶 json 數(shù)據(jù)流
protected boolean useJsonStreamer;
//自動關(guān)閉輸入流標(biāo)志
protected boolean autoCloseInputStreams;
//保存上傳有效載荷所需的時間
protected String elapsedFieldInJsonStreamer = "_elapsed";
//指定編碼格式
protected String contentEncoding = "utf-8";
private Gson mGson = new Gson();
/**
* 構(gòu)造一個空的 RequestParams 實例
*/
public RequestParams() {
this((Map<String, String>) null);
}
//獲取 urlParams
public String getUrlParams(String key){
if(!TextUtils.isEmpty(key)&&urlParams.containsKey(key)){
return urlParams.get(key);
}
return "";
}
/**
* 構(gòu)造一個新的RequestParams實例,該實例包含指定map中的鍵/值字符串參數(shù)桌肴。
*/
public RequestParams(Map<String, String> source) {
if (source != null) {
for (Map.Entry<String, String> entry : source.entrySet()) {
put(entry.getKey(), entry.getValue());
}
}
}
/**
* 構(gòu)造一個新的RequestParams實例皇筛,并使用單個初始鍵/值填充
*/
public RequestParams(final String key, final String value) {
this(new HashMap<String, String>() {{
put(key, value);
}});
}
/**
* 構(gòu)造一個新的RequestParams實例,并用多個初始鍵/值填充
*/
public RequestParams(Object... keysAndValues) {
int len = keysAndValues.length;
if (len % 2 != 0)
throw new IllegalArgumentException("Supplied arguments must be even");
for (int i = 0; i < len; i += 2) {
String key = String.valueOf(keysAndValues[i]);
String val = String.valueOf(keysAndValues[i + 1]);
put(key, val);
}
}
public void setContentEncoding(final String encoding) {
if (encoding != null) {
this.contentEncoding = encoding;
} else {
Log.d(LOG_TAG, "setContentEncoding called with null attribute");
}
}
/**
* 如果設(shè)置為true坠七,即使沒有文件或流被發(fā)送水醋,也會將Content-Type頭部強(qiáng)制為“multipart/form-data”
* multipart/form-data:需要在表單中進(jìn)行文件上傳時,就需要使用該格式
*/
public void setForceMultipartEntityContentType(boolean force) {
this.forceMultipartEntity = force;
}
/**
* 添加 string 類型字符串到 urlParams
*/
public void put(String key, String value) {
if (key != null && value != null) {
urlParams.put(key, value);
}
}
/**
* 將自定義提供的文件內(nèi)容類型和文件名稱添加到 fileArrayParams
*/
public void put(String key, File files[]) throws FileNotFoundException {
put(key, files, null, null);
}
/**
* 將自定義提供的文件內(nèi)容類型和文件名稱添加到 fileArrayParams
*/
public void put(String key, File files[], String contentType, String customFileName) throws FileNotFoundException {
if (key != null) {
List<FileWrapper> fileWrappers = new ArrayList<FileWrapper>();
for (File file : files) {
if (file == null || !file.exists()) {
throw new FileNotFoundException();
}
fileWrappers.add(new FileWrapper(file, contentType, customFileName));
}
fileArrayParams.put(key, fileWrappers);
}
}
/**
* 將自定義提供的文件內(nèi)容類型和文件名添加到 fileParams
*/
public void put(String key, File file) throws FileNotFoundException {
put(key, file, null, null);
}
/**
* 將自定義提供的文件內(nèi)容類型和文件名添加到 fileParams
*/
public void put(String key, String customFileName, File file) throws FileNotFoundException {
put(key, file, null, customFileName);
}
/**
* 將自定義提供的文件內(nèi)容類型和文件名添加到 fileParams
*/
public void put(String key, File file, String contentType) throws FileNotFoundException {
put(key, file, contentType, null);
}
/**
* 將自定義提供的文件內(nèi)容類型和文件名添加到 fileParams
*/
public void put(String key, File file, String contentType, String customFileName) throws FileNotFoundException {
if (file == null || !file.exists()) {
throw new FileNotFoundException();
}
if (key != null) {
fileParams.put(key, new FileWrapper(file, contentType, customFileName));
}
}
/**
* 添加 InputStream 流到 streamParams
*/
public void put(String key, InputStream stream) {
put(key, stream, null);
}
/**
* 添加 InputStream 流到 streamParams
*/
public void put(String key, InputStream stream, String name) {
put(key, stream, name, null);
}
/**
* 添加 InputStream 流到 streamParams
*/
public void put(String key, InputStream stream, String name, String contentType) {
put(key, stream, name, contentType, autoCloseInputStreams);
}
/**
* 添加 InputStream 流到 streamParams
*/
public void put(String key, InputStream stream, String name, String contentType, boolean autoClose) {
if (key != null && stream != null) {
streamParams.put(key, StreamWrapper.newInstance(stream, name, contentType, autoClose));
}
}
/**
* 添加 Object 對象到 urlParamsWithObjects
*/
public void put(String key, Object value) {
if (key != null && value != null) {
urlParamsWithObjects.put(key, value);
}
}
/**
* 添加 int 類型字符串到 urlParams
*/
public void put(String key, int value) {
if (key != null) {
urlParams.put(key, String.valueOf(value));
}
}
/**
* 添加 long 類型字符串到 urlParams
*/
public void put(String key, long value) {
if (key != null) {
urlParams.put(key, String.valueOf(value));
}
}
/**
* 添加 String 類型字符串到 urlParamsWithObjects
*/
public void add(String key, String value) {
if (key != null && value != null) {
Object params = urlParamsWithObjects.get(key);
if (params == null) {
// 向后兼容灼捂,這將導(dǎo)致“k = v1&k = v2&k = v3”
params = new HashSet<String>();
this.put(key, params);
}
if (params instanceof List) {
((List<Object>) params).add(value);
} else if (params instanceof Set) {
((Set<Object>) params).add(value);
}
}
}
/**
* 從 request 中移除某個字段
*/
public void remove(String key) {
urlParams.remove(key);
streamParams.remove(key);
fileParams.remove(key);
urlParamsWithObjects.remove(key);
fileArrayParams.remove(key);
}
/**
* 監(jiān)測字段是否被定義
*/
public boolean has(String key) {
return urlParams.get(key) != null ||
streamParams.get(key) != null ||
fileParams.get(key) != null ||
urlParamsWithObjects.get(key) != null ||
fileArrayParams.get(key) != null;
}
public void setHttpEntityIsRepeatable(boolean flag) {
this.isRepeatable = flag;
}
public void setUseJsonStreamer(boolean flag) {
this.useJsonStreamer = flag;
}
/**
* 通過流上傳 JSON 對象時設(shè)置一個附加字段离例,以保存上載有效載荷所需的時間(以毫秒為單位)。 默認(rèn)情況下悉稠,此字段設(shè)置為“_elapsed”宫蛆。
* 要禁用此功能,請將此方法調(diào)用為null作為字段值。
*/
public void setElapsedFieldInJsonStreamer(String value) {
this.elapsedFieldInJsonStreamer = value;
}
/**
* 設(shè)置全局標(biāo)志耀盗,用于確定在成功上傳時是否自動關(guān)閉輸入流想虎。
*/
public void setAutoCloseInputStreams(boolean flag) {
autoCloseInputStreams = flag;
}
/**
* http get builder 參數(shù)封裝構(gòu)造類
*/
public GetBuilder getGetBuilder() {
GetBuilder getBuilder = new GetBuilder();
//添加參數(shù) url 后面
for (ConcurrentHashMap.Entry<String, String> entry : urlParams.entrySet()) {
Log.i("log", "getBuilder value:" + entry.getValue());
getBuilder.addParams(entry.getKey(), entry.getValue());
}
return getBuilder;
}
/**
* post form 表單
*/
public PostFormBuilder getPostFormBuilder() {
PostFormBuilder postFormBuilder = new PostFormBuilder();
// post 請求添加參數(shù) url后面添加
for (ConcurrentHashMap.Entry<String, String> entry : urlParams.entrySet()) {
Log.i("log", "getBuilder value:" + entry.getValue());
postFormBuilder.addParams(entry.getKey(), entry.getValue());
}
//post 請求添加參數(shù) file 文件參數(shù)
for (ConcurrentHashMap.Entry<String, FileWrapper> entry : fileParams.entrySet()) {
postFormBuilder.addFile(entry.getKey(), entry.getValue().file.getAbsolutePath(), entry.getValue().file);
}
//文件對象列表存儲相關(guān)信息
//public PostFormBuilder addFile(String name, String filename, File file)
//{
// files.add(new FileInput(name, filename, file));
// return this;
//}
return postFormBuilder;
}
// post String 字符串
public PostStringBuilder getPostJsonBuilder() {
PostStringBuilder postFormBuilder = new PostStringBuilder();
//將對象轉(zhuǎn)成 json 字符串傳遞給 PostStringBuilder
postFormBuilder.content(mGson.toJson(urlParams));
return postFormBuilder;
}
//文件包裝類
public static class FileWrapper implements Serializable {
public final File file;
public final String contentType;
public final String customFileName;
public FileWrapper(File file, String contentType, String customFileName) {
this.file = file;
this.contentType = contentType;
this.customFileName = customFileName;
}
}
//輸入流包裝類
public static class StreamWrapper {
public final InputStream inputStream;//輸入流
public final String name;//文件名
public final String contentType;//contentType 媒體類型
public final boolean autoClose;//是否自動關(guān)閉
public StreamWrapper(InputStream inputStream, String name, String contentType, boolean autoClose) {
this.inputStream = inputStream;
this.name = name;
this.contentType = contentType;
this.autoClose = autoClose;
}
//輸入流包裝類 APPLICATION_OCTET_STREAM:二進(jìn)制流數(shù)據(jù)標(biāo)志
static StreamWrapper newInstance(InputStream inputStream, String name, String contentType, boolean autoClose) {
return new StreamWrapper(
inputStream,
name,
contentType == null ? APPLICATION_OCTET_STREAM : contentType,
autoClose);
}
}
}
2.2、IHttpListener 接口
在 OkHttp 的 CallBack 類中叛拷,封裝了 onSuccess() 和 onFailure() 方法舌厨,我們按照類似需求進(jìn)行添加相應(yīng)的方法。
onStart() 方法用于網(wǎng)絡(luò)請求之前的一些操作忿薇,onSuccess() 網(wǎng)絡(luò)請求成功的回調(diào)裙椭,onFailure() 網(wǎng)絡(luò)請求成功的回調(diào)。
public interface IHttpListener {
//請求網(wǎng)絡(luò)之前回調(diào)(對話框提示信息等) requestId:網(wǎng)絡(luò)請求唯一標(biāo)識
void onStart(int requestId);
//請求網(wǎng)絡(luò)成功回調(diào) requestId:網(wǎng)絡(luò)請求唯一標(biāo)識署浩,response:Response 對象
void onSuccess(int requestId, Response response);
//請求網(wǎng)絡(luò)失敗回調(diào) requestId:網(wǎng)絡(luò)請求唯一標(biāo)識揉燃,httpStatus:狀態(tài)碼,error:錯誤信息
void onFailure(int requestId, int httpStatus, Throwable error);
}
兩個重要的參數(shù)算是封裝完了筋栋,下面開始 GET 請求方法實現(xiàn)炊汤。
public void get(IRequest request, IHttpListener listener) {
LogDebugUtil.e(TAG, "post: url=" + request.getUrl());
if (request != null) {
//請求參數(shù)構(gòu)造,其實就是構(gòu)造 Request 對象,Request 采用 build 模式弊攘,這里也一樣
//RequestParams params = request.getParams();
//GetBuilder 來自 OkHttpUtils
//GetBuilder getBuilder = params.getGetBuilder();
//RequestCall 和 Call 對象類似抢腐,就是用來執(zhí)行網(wǎng)絡(luò)請求的
//RequestCall call = getBuilder.url(request.getUrl())
// .id(request.getRequestId()).build();
//執(zhí)行 call,ResponseCallback是自定義 CallBack襟交,listener:回調(diào)監(jiān)聽迈倍,request.getParserType():請求類型解析 ResponseCallback(IHttpListener httpListener, Type parserType)
//call.execute(new ResponseCallback(listener,request.getParserType()));
//鏈?zhǔn)秸{(diào)用,上面是分析調(diào)用過程
request.getParams()
.getGetBuilder()
.url(request.getUrl())
.id(request.getRequestId())
.build()
.execute(new ResponseCallback(listener, request.getParserType()));
} else {
throw new RuntimeException("Request param is null");
}
}
3婿着、CallBack 封裝
看到 鴻洋大神的 github 上對于自定義 CallBack 寫了示例授瘦,根據(jù)這個示例,我們來封裝一個自己的 CallBack竟宋。
先定義一個 Bean提完,針對下面這個 json 串進(jìn)行封裝,這個是登錄的請求信息丘侠。
{ "status": 0,
"msg": "請求成功",
"data": {
"id": "1", "nickname": "pzf“
}
}
創(chuàng)建一個 Response 對象徒欣,聲明需要解析的數(shù)據(jù)
//IDontObfuscate 是一個實現(xiàn)了 Serializable 接口的序列化抽象類,上面已經(jīng)講過了
public class Response<T> extends IDontObfuscate {
public int status;//狀態(tài)碼
public String msg;//狀態(tài)信息
public T data;//對象
@Override
public String toString() {
return "Response [code=" + status + ", msg=" + msg + ", data=" + data
+ "]";
}
}
ResponseCallback — 自定義 Callback
//ResponseCallback 繼承自 OkHttpUtils 框架中的 Callback蜗字,Response 是一個 bean 對象打肝,上面講過
class ResponseCallback extends Callback<Response> {
private IHttpListener mHttpListener;//callback 回調(diào)監(jiān)聽
private Type mParserType;//數(shù)據(jù)轉(zhuǎn)換類型
public ResponseCallback(IHttpListener httpListener, Type parserType) {
mHttpListener = httpListener;
mParserType = parserType;
}
//請求網(wǎng)絡(luò)之前回調(diào)
@Override
public void onBefore(Request request, int id) {
if (mHttpListener != null) {
mHttpListener.onStart(id);
}
}
@Override
public Response parseNetworkResponse(okhttp3.Response response, int id) throws Exception {
LogDebugUtil.e(TAG, "parseNetworkResponse: ");
Response responseData = null;
if (mHttpListener != null && response != null) {
if (response.isSuccessful()) {
String content = response.body().string();
if (content != null) {
try {
LogDebugUtil.e(TAG, "onSuccess: " + content);
//解析數(shù)據(jù),返回解析之后的數(shù)據(jù)
responseData = mGson.fromJson(content,mParserType);
} catch (JsonSyntaxException e) {
onError(null,e,id);
}
}
} else {
onError(null, new Exception("net error"),id);
}
}
return responseData;
}
//請求錯誤回調(diào)
@Override
public void onError(Call call, Exception e, int id) {
if (mHttpListener != null) {
if (!call.isCanceled()) {
mHttpListener.onFailure(id, 0, e);
}
}
}
//請求成功回調(diào)
@Override
public void onResponse(Response response, int id) {
if (mHttpListener != null) {
mHttpListener.onSuccess(id, response);
}
}
}
OkHttpUtils 中 Callback 源碼
public abstract class Callback<T>{
/**
* UI Thread 請求網(wǎng)絡(luò)之前調(diào)用
*/
public void onBefore(Request request, int id){
}
/**
* UI Thread 請求網(wǎng)絡(luò)之后調(diào)用
*/
public void onAfter(int id){
}
/**
* UI Thread 更新進(jìn)度條
*/
public void inProgress(float progress, long total , int id){
}
/**
* 如果在 parseNetworkResponse 中解析響應(yīng)代碼挪捕,則應(yīng)該使此方法返回 true粗梭。
*/
public boolean validateReponse(Response response, int id)
{
return response.isSuccessful();
}
/**
* Thread Pool Thread 根據(jù)示例可以看出,該方法是解析數(shù)據(jù)的级零,T 是數(shù)據(jù)源
*/
public abstract T parseNetworkResponse(Response response, int id) throws Exception;
public abstract void onError(Call call, Exception e, int id);
public abstract void onResponse(T response, int id);
public static Callback CALLBACK_DEFAULT = new Callback(){
@Override
public Object parseNetworkResponse(Response response, int id) throws Exception{
return null;
}
@Override
public void onError(Call call, Exception e, int id){
}
@Override
public void onResponse(Object response, int id){
}
};
}
到此断医,GET 請求封裝完成。
4、構(gòu)造 POST 請求
post 請求這里封裝兩個鉴嗤,F(xiàn)orm 表單和 Json 字符串的 Post 提交封裝斩启。
4.1、Post Form
post 和 get 類似醉锅,之前 RequestParams 請求參數(shù)封裝類已經(jīng)構(gòu)造完成兔簇,這里可以直接使用。
public void postForm(IRequest request, IHttpListener listener) {
LogDebugUtil.e(TAG, "postForm: url=" + request.getUrl());
if (request != null) {
//請求參數(shù)構(gòu)造,其實就是構(gòu)造 Request 對象硬耍,Request 采用 build 模式垄琐,這里也一樣
//RequestParams params = request.getParams();
//PostFormBuilder 來自 OkhttpUtils
//PostFormBuilder postFormBuilder = params.getPostFormBuilder();
//RequestCall 和 Call 對象類似,就是用來執(zhí)行網(wǎng)絡(luò)請求的
//RequestCall call = postFormBuilder.url(request.getUrl())
// .id(request.getRequestId()).build();
//執(zhí)行 call默垄,ResponseCallback 是自定義 CallBack此虑,listener:回調(diào)監(jiān)聽,request.getParserType():請求類型解析 ResponseCallback(IHttpListener httpListener, Type parserType)
//call.execute(new ResponseCallback(listener,request.getParserType()));
//這里采用鏈?zhǔn)秸{(diào)用口锭,上面的是解析
request.getParams()
.getPostFormBuilder()
.url(request.getUrl())
.id(request.getRequestId())
.build()
.execute(new ResponseCallback(listener, request.getParserType()));
} else {
throw new RuntimeException("Request param is null");
}
}
4.2、Post Json
public void postJson(IRequest request, IHttpListener listener) {
LogDebugUtil.e(TAG, "postForm: url=" + request.getUrl());
if (request != null) {
//請求參數(shù)構(gòu)造,其實就是構(gòu)造 Request 對象介杆,Request 采用 build 模式鹃操,這里也一樣
//RequestParams params = request.getParams();
//PostStringBuilder 來自 OkhttpUtils
//PostStringBuilder postJsonBuilder = params.getPostJsonBuilder();
//RequestCall 和 Call 對象類似,就是用來執(zhí)行網(wǎng)絡(luò)請求的
//RequestCall call = postJsonBuilder.url(request.getUrl())
// .id(request.getRequestId()).build();
//執(zhí)行 call春哨,ResponseCallback 是自定義 CallBack荆隘,listener:回調(diào)監(jiān)聽,request.getParserType():請求類型解析 ResponseCallback(IHttpListener httpListener, Type parserType)
//call.execute(new ResponseCallback(listener,request.getParserType()));
//這里采用鏈?zhǔn)秸{(diào)用赴背,上面的是解析
request.getParams()
.getPostJsonBuilder()
.url(request.getUrl())
.id(request.getRequestId())
.build().execute(new ResponseCallback(listener, request.getParserType()));
} else {
throw new RuntimeException("Request param is null");
}
}
5椰拒、其它方法和類的封裝
使用 Call.cancel() 可以立即停止掉一個正在執(zhí)行的 call。如果一個線程正在寫請求或者讀響應(yīng)凰荚,將會引發(fā) IOException燃观。當(dāng) call 沒有必要的時候,使用這個 api 可以節(jié)約網(wǎng)絡(luò)資源便瑟。例如當(dāng)用戶離開一個應(yīng)用時缆毁。不管同步還是異步的 call 都可以取消。
你可以通過 tags 來同時取消多個請求到涂。當(dāng)你構(gòu)建一請求時脊框,使用 RequestBuilder.tag(tag) 來分配一個標(biāo)簽。之后你就可以用 OkHttpClient.cancel(tag) 來取消所有帶有這個 tag 的 call践啄。
cancelRequest 根據(jù) tag 取消 call浇雹,StringCallback 為 String 類 Callback。
//取消 call
public void cancelRequest(String tag) {
if (tag != null) {
OkHttpUtils.getInstance().cancelTag(tag);
}
}
//StringCallback 封裝屿讽,解析 String 類型數(shù)據(jù)
abstract class StringCallback extends Callback<String> {
@Override
public String parseNetworkResponse(okhttp3.Response response, int id) throws IOException {
return response.body().string();
}
}
6昭灵、總結(jié)
OkHttp 封裝步驟整理
1、OkHttpClient 實例化,所有請求都是在此基礎(chǔ)上進(jìn)行的虎锚。
2硫痰、封裝 Request,包括參數(shù)的傳遞和 url 的構(gòu)造
3窜护、封裝 Callback效斑,將數(shù)據(jù)源作為范型傳遞進(jìn)去,根據(jù)具體需求進(jìn)行解析柱徙,重寫抽象方法缓屠,onSuccess()、onFailure()护侮、onStart() 等敌完。
140套Android優(yōu)秀開源項目源碼,領(lǐng)取地址:http://mp.weixin.qq.com/s/afPGHqfdiApALZqHsXbw-A