OkHttpPlus介紹
項(xiàng)目地址:https://github.com/ZhaoKaiQiang/OkHttpPlus
主要功能:OkHttp封裝,支持GET、POST、UI線程回調(diào)、JSON格式解析、鏈?zhǔn)秸{(diào)用、小文件上傳下載及進(jìn)度監(jiān)聽等功能
為什么要寫這么一個(gè)庫(kù)呢?
首先,是因?yàn)镺kHttp在4.4之后已經(jīng)作為底層的Http實(shí)現(xiàn)了,所以O(shè)kHttp這個(gè)庫(kù)很強(qiáng)大,值得我們學(xué)習(xí)。
其次,在我看來(lái),OkHttp使用起來(lái)不如Volley方便,OkHttp的回調(diào)都是在工作線程,所以如果在回調(diào)里面操作View的話,需要自己轉(zhuǎn)換到UI線程,非常繁瑣,所以需要封裝。也有將OkHttp作為Volley底層Http實(shí)現(xiàn)的用法,發(fā)送請(qǐng)求、維護(hù)請(qǐng)求隊(duì)列用的是Volley,實(shí)際的Http請(qǐng)求用的是OkHttp。
關(guān)于Volley和oOkHttp結(jié)合的Demo請(qǐng)戳煎蛋項(xiàng)目
如何使用
初始化
你可以在Application里面完成初始化,因?yàn)閷?duì)OkHttp的封裝主要使用的是代理設(shè)計(jì)模式,使用OkHttpProxy.getInstance()
可以獲取到單例客戶端,你可以像沒(méi)封裝之前一樣,設(shè)置任意的參數(shù),比如下面就設(shè)置超時(shí)時(shí)間和忽略HTTPS認(rèn)證。
public class OkApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
OkHttpClient okHttpClient = OkHttpProxy.getInstance();
okHttpClient.setConnectTimeout(10, TimeUnit.SECONDS);
okHttpClient.setReadTimeout(15, TimeUnit.SECONDS);
okHttpClient.setWriteTimeout(15, TimeUnit.SECONDS);
//ignore HTTPS Authentication
okHttpClient.setHostnameVerifier(new MyHostnameVerifier());
try {
SSLContext sc = SSLContext.getInstance("TLS");
sc.init(null, new TrustManager[]{new MyTrustManager()}, new SecureRandom());
okHttpClient.setSslSocketFactory(sc.getSocketFactory());
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
}
}
Get方法
你大多數(shù)情況下是和OkHttpProxy這個(gè)代理類打交道,而且OkHttpPlus支持鏈?zhǔn)秸{(diào)用,內(nèi)部采用Builder設(shè)計(jì)模式,所以你可以像下面這樣使用
OkHttpProxy.get()
.url(URL_USER)
.tag(this)
.execute(new OkCallback<User>(new OkJsonParser<User>() {
}) {
@Override
public void onSuccess(int code, User user) {
tv_response.setText(user.toString());
}
@Override
public void onFailure(Throwable e) {
tv_response.setText(e.getMessage());
}
});
為了支持返回值解析,這里我采用了泛型,在OkCallback的構(gòu)造函數(shù)中,你需要傳入一個(gè)解析器,OkHttpPlus內(nèi)部支持5種解析器,這可以解決你大部分的需求
- OkBaseParser,所有解析器的基類,不可直接使用
- OkBaseJsonParser,所有JSON解析器的基類,你可以繼承它來(lái)定義自己的JSON解析
- OkJsonParser,JSON解析器,支持JSONObject和JSONArray的解析,默認(rèn)使用GSON作為解析器
- OkTextParser,String解析器,支持將結(jié)果以String方式輸出
- OkFileParser,文件解析器,支持將結(jié)果保存為文件,你可以用來(lái)下載文件,但是不支持較大文件下載
所以如果你想獲取一個(gè)JSONArray,你可以像下面這樣
OkHttpProxy.get()
.url(URL_USER)
.tag(this)
.execute(new OkCallback<List<User>>(new OkJsonParser<List<User>>() {
}) {
@Override
public void onSuccess(int code, List<User> users) {
tv_response.setText(users.toString());
}
@Override
public void onFailure(Throwable e) {
tv_response.setText(e.getMessage());
}
});
你如果想獲取String數(shù)據(jù),你可以這樣
OkHttpProxy.get()
.url(URL_BAIDU)
.tag(this)
.execute(new OkCallback<String>(new OkTextParser()) {
@Override
public void onSuccess(int code, String s) {
tv_response.setText(s);
}
@Override
public void onFailure(Throwable e) {
tv_response.setText(e.getMessage());
}
});
當(dāng)然,如果你想自定義一個(gè)解析器,也是完全可以的。
OkHttpPlus的解析器部分使用的是策略設(shè)計(jì)模式,所以你可以像下面這樣自定義一個(gè)解析策略,完成結(jié)果的解析
public class JokeParser<T> extends OkJsonParser<T> {
@Nullable
@Override
public T parse(Response response) throws IOException {
String jsonStr = response.body().string();
try {
jsonStr = new JSONObject(jsonStr).getJSONArray("comments").toString();
return mGson.fromJson(jsonStr, new TypeToken<ArrayList<Joke>>() {
}.getType());
} catch (JSONException e) {
e.printStackTrace();
return null;
}
}
}
然后就可以將返回結(jié)果解析為ArrayList<Joke>了
OkHttpProxy.get()
.url(Joke.getRequestUrl(1))
.tag(this).execute(new OkCallback<List<Joke>>(new JokeParser()) {
@Override
public void onSuccess(int code, List<Joke> jokes) {
tv_response.setText(jokes.toString());
}
@Override
public void onFailure(Throwable e) {
tv_response.setText(e.getMessage());
}
});
Post方法
Post的方法與Get方法使用類似,你可以像下面這樣發(fā)送POST請(qǐng)求,并添加Header和Params。
OkHttpProxy
.post()
.url(URL_USERS)
.tag(this)
.addParams("name", "zhaokaiqiang")
.addHeader("header", "okhttp")
.execute(new OkCallback<ArrayList<User>>(new OkJsonParser<ArrayList<User>>() {
}) {
@Override
public void onSuccess(int code, ArrayList<User> users) {
tv_response.setText(users.toString());
}
@Override
public void onFailure(Throwable e) {
tv_response.setText(e.getMessage());
}
});
你可能注意到了,在發(fā)送每個(gè)請(qǐng)求的時(shí)候,我都調(diào)用了tag()方法,所以你可以在不需要的時(shí)候,將請(qǐng)求取消掉。
@Override
protected void onDestroy() {
super.onDestroy();
OkHttpProxy.cancel(this);
}
下載
你可以像下面這樣下載一個(gè)文件,但是由于下載的內(nèi)容都在內(nèi)存中,所以不支持大文件下載,否則會(huì)OOM
String desFileDir = Environment.getExternalStorageDirectory().getAbsolutePath();
OkHttpProxy.download(URL_DOWMLOAD, new DownloadListener(desFileDir, "json.jar") {
@Override
public void onUIProgress(Progress progress) {
//當(dāng)下載資源長(zhǎng)度不可知時(shí),progress.getTotalBytes()為-1,此時(shí)不能顯示下載進(jìn)度
int pro = (int) (progress.getCurrentBytes() / progress.getTotalBytes() * 100);
if (pro > 0) {
pb.setProgress(pro);
}
KLog.d("pro = " + pro + " getCurrentBytes = " + progress.getCurrentBytes() + " getTotalBytes = " + progress.getTotalBytes());
}
@Override
public void onSuccess(File file) {
tv_response.setText(file.getAbsolutePath());
}
@Override
public void onFailure(Exception e) {
tv_response.setText(e.getMessage());
}
});
}
上傳
OkHttpPlus也支持小文件上傳,我這里測(cè)試使用的是七牛的上傳API,Token是有期限的,所以你需要在下面網(wǎng)址自己生成測(cè)試
/**
* 采用七牛上傳接口,Token有效期為12小時(shí),若Token無(wú)效,請(qǐng)?jiān)谙旅孀孕蝎@取
* Token生成網(wǎng)址 http://jsfiddle.net/gh/get/extjs/4.2/icattlecoder/jsfiddle/tree/master/uptoken
* <p/>
* AK = IUy4JnOZHP6o-rx9QsGLf9jMTAKfRkL07gNssIDA
* CK = DkfA7gPTNy1k4HWnQynra3qAZhrzp-wmSs15vub6
* BUCKE_NAME = zhaokaiqiang
*/
public void uploadFile(View view) {
File file = new File(Environment.getExternalStorageDirectory(), "jiandan02.jpg");
if (!file.exists()) {
Toast.makeText(MainActivity.this, "文件不存在,請(qǐng)修改文件路徑", Toast.LENGTH_SHORT).show();
return;
}
Map<String, String> param = new HashMap<>();
param.put("token", TOKEN);
Pair<String, File> pair = new Pair("file", file);
OkHttpProxy
.upload()
.url(URL_UPLOAD)
.file(pair)
.setParams(param)
.setWriteTimeOut(20)
.start(new UploadListener() {
@Override
public void onSuccess(Response response) {
tv_response.setText("isSuccessful = " + response.isSuccessful() + "\n" + "code = " + response.code());
}
@Override
public void onFailure(Exception e) {
tv_response.setText(e.getMessage());
}
@Override
public void onUIProgress(Progress progress) {
int pro = (int) ((progress.getCurrentBytes() + 0.0) / progress.getTotalBytes() * 100);
if (pro > 0) {
pb.setProgress(pro);
}
KLog.d("pro = " + pro + " getCurrentBytes = " + progress.getCurrentBytes() + " getTotalBytes = " + progress.getTotalBytes());
}
});
}
靈感來(lái)源
本項(xiàng)目的靈感和部分代碼來(lái)自于下面兩個(gè)開源項(xiàng)目,謝謝他們的分享精神
尊重原創(chuàng),轉(zhuǎn)載請(qǐng)注明:From 凱子哥 侵權(quán)必究!