摘要:需要注意的是回調(diào)并不是在線程。也可以通過(guò)來(lái)同時(shí)取消多個(gè)請(qǐng)求。在開(kāi)始創(chuàng)建的時(shí)候配置好,在請(qǐng)求網(wǎng)絡(luò)的時(shí)候用將請(qǐng)求的結(jié)果回調(diào)給線程。最后調(diào)用這個(gè)的方法請(qǐng)求成功使用起來(lái)簡(jiǎn)單多了,而且請(qǐng)求結(jié)果回調(diào)是在線程的。
前言
講完了Volley,我們接下來(lái)看看目前比較火的網(wǎng)絡(luò)框架OkHttp, 它處理了很多網(wǎng)絡(luò)疑難雜癥:會(huì)從很多常用的連接問(wèn)題中自動(dòng)恢復(fù)。如果您的服務(wù)器配置了多個(gè)IP地址,當(dāng)?shù)谝粋€(gè)IP連接失敗的時(shí)候,OkHttp會(huì)自動(dòng)嘗試下一個(gè)IP,此外OkHttp還處理了代理服務(wù)器問(wèn)題和SSL握手失敗問(wèn)題。
1.使用前準(zhǔn)備eclipse引入jar包地址:
okhttp-2.7.5.jar
okio-1.7.0.jar
Android Studio 配置gradle:
compile "com.squareup.okhttp:okhttp:2.7.5" compile "com.squareup.okio:okio:1.7.0"2.異步GET請(qǐng)求
最簡(jiǎn)單的get請(qǐng)求,老規(guī)矩請(qǐng)求百度:
private void getAsynHttp() { //創(chuàng)建okHttpClient對(duì)象 OkHttpClient mOkHttpClient = new OkHttpClient(); final Request request = new Request.Builder() .url("http://www.baidu.com") .build(); Call call = mOkHttpClient.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(Request request, IOException e) { } @Override public void onResponse(final Response response) throws IOException { String str = response.body().string(); Log.i("wangshu", str); runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(getApplication(), "請(qǐng)求成功", Toast.LENGTH_SHORT).show(); } }); } }); }
運(yùn)行程序log打印出來(lái)的是百度首頁(yè)的html文件,基本的步驟很簡(jiǎn)單,就是創(chuàng)建OkHttpClient、Request和Call,最后調(diào)用Call的enqueue()方法。但是每次這么寫(xiě)肯定是很麻煩,肯定是要進(jìn)行封裝的。需要注意的是onResponse回調(diào)并不是在UI線程。
3.同步GET請(qǐng)求private String getSyncHttp() throws IOException{ OkHttpClient mOkHttpClient = new OkHttpClient(); //創(chuàng)建請(qǐng)求Request final Request request = new Request.Builder() .url("http://www.baidu.com") .build(); Call call = mOkHttpClient.newCall(request); Response mResponse=call.execute(); if (mResponse.isSuccessful()) { return mResponse.body().string(); } else { throw new IOException("Unexpected code " + mResponse); } }
同步Get請(qǐng)求和異步調(diào)用區(qū)別就是調(diào)用了call的execute()方法。
4.異步POST請(qǐng)求private void postAsynHttp() { OkHttpClient mOkHttpClient = new OkHttpClient(); RequestBody formBody = new FormEncodingBuilder() .add("size", "10") .build(); Request request = new Request.Builder() .url("http://api.1-blog.com/biz/bizserver/article/list.do") .post(formBody) .build(); Call call = mOkHttpClient.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(Request request, IOException e) { } @Override public void onResponse(Response response) throws IOException { String str = response.body().string(); Log.i("wangshu", str); runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext(), "請(qǐng)求成功", Toast.LENGTH_SHORT).show(); } }); } }); }
post與get不同的就是要要?jiǎng)?chuàng)建RequestBody并傳進(jìn)Request中,同樣onResponse回調(diào)不是在UI線程。
5.請(qǐng)求緩存設(shè)置首先我們?cè)O(shè)置緩存路徑和大小并設(shè)置給OkHttpClient:
mOkHttpClient = new OkHttpClient(); File sdcache = getExternalCacheDir(); int cacheSize = 10 * 1024 * 1024; mOkHttpClient.setCache(new Cache(sdcache.getAbsoluteFile(), cacheSize));
接下來(lái)異步GET請(qǐng)求baidu:
private void getAsynHttp() { //創(chuàng)建請(qǐng)求Request final Request request = new Request.Builder() .url("http://www.baidu.com") .build(); Call call = mOkHttpClient.newCall(request); call.enqueue(new Callback() { @Override public void onFailure(Request request, IOException e) { } @Override public void onResponse(final Response response) throws IOException { if (null != response.cacheResponse()) { String str = response.cacheResponse().toString(); Log.i("wangshu", "cache---" + str); } else { response.body().string(); String str=response.networkResponse().toString(); Log.i("wangshu", "network---" + str); } runOnUiThread(new Runnable() { @Override public void run() { Toast.makeText(getApplicationContext(), "請(qǐng)求成功", Toast.LENGTH_SHORT).show(); } }); } }); }
第一次請(qǐng)求會(huì)請(qǐng)求網(wǎng)絡(luò)得到數(shù)據(jù),第二次以及后面的請(qǐng)求則會(huì)從緩存中取出數(shù)據(jù):
當(dāng)然也有種情況是有的請(qǐng)求每次都需要最新的數(shù)據(jù),則在創(chuàng)建Request,來(lái)設(shè)置cacheControl為“CacheControl.FORCE_NETWORK”,用來(lái)表示請(qǐng)求會(huì)一直請(qǐng)求網(wǎng)絡(luò)得到數(shù)據(jù):
final Request request = new Request.Builder() .url("http://www.baidu.com") .cacheControl(CacheControl.FORCE_NETWORK) .build();
運(yùn)行程序結(jié)果為:
6.設(shè)置超時(shí)時(shí)間另外我們也需要設(shè)置超時(shí)的時(shí)間用來(lái)處理各種網(wǎng)絡(luò)超時(shí)的情況,超時(shí)的原因可能是網(wǎng)絡(luò)問(wèn)題也可能是服務(wù)器響應(yīng)慢等問(wèn)題,OkHttp當(dāng)然不會(huì)忽略這一點(diǎn),它支持連接、讀取和寫(xiě)入超時(shí)的時(shí)間設(shè)置:
mOkHttpClient = new OkHttpClient(); mOkHttpClient.setConnectTimeout(15, TimeUnit.SECONDS); mOkHttpClient.setWriteTimeout(20, TimeUnit.SECONDS); mOkHttpClient.setReadTimeout(20, TimeUnit.SECONDS);7.取消請(qǐng)求
使用call.cancel()可以立即停止掉一個(gè)正在執(zhí)行的call。如果一個(gè)線程正在寫(xiě)請(qǐng)求或者讀響應(yīng),將會(huì)引發(fā)IOException。當(dāng)用戶離開(kāi)一個(gè)應(yīng)用時(shí)或者跳到其他界面時(shí),使用Call.cancel()可以節(jié)約網(wǎng)絡(luò)資源,另外不管同步還是異步的call都可以取消。
也可以通過(guò)tags來(lái)同時(shí)取消多個(gè)請(qǐng)求。當(dāng)你構(gòu)建一請(qǐng)求時(shí),使用RequestBuilder.tag(tag)來(lái)分配一個(gè)標(biāo)簽。之后你就可以用OkHttpClient.cancel(tag)來(lái)取消所有帶有這個(gè)tag的call。
為了模擬這個(gè)場(chǎng)景我們首先創(chuàng)建一個(gè)定時(shí)的線程池:
private ScheduledExecutorService executor = Executors.newScheduledThreadPool(1);
接下來(lái)的代碼為:
private void cancel(){ final Request request = new Request.Builder() .url("http://www.baidu.com") .cacheControl(CacheControl.FORCE_NETWORK) .build(); Call call=null; call = mOkHttpClient.newCall(request); final Call finalCall = call; //100毫秒后取消call executor.schedule(new Runnable() { @Override public void run() { finalCall.cancel(); } }, 100, TimeUnit.MILLISECONDS); call.enqueue(new Callback() { @Override public void onFailure(Request request, IOException e) { } @Override public void onResponse(final Response response) { if (null != response.cacheResponse()) { String str = response.cacheResponse().toString(); Log.i("wangshu", "cache---" + str); } else { try { response.body().string(); } catch (IOException e) { Log.i("wangshu", "IOException"); e.printStackTrace(); } String str = response.networkResponse().toString(); Log.i("wangshu", "network---" + str); } } }); Log.i("wangshu", "是否取消成功"+call.isCanceled()); }
100毫秒后調(diào)用call.cancel(),為了能讓請(qǐng)求耗時(shí),我們?cè)O(shè)置每次請(qǐng)求都要請(qǐng)求網(wǎng)絡(luò),運(yùn)行程序并且不斷的快速點(diǎn)擊發(fā)送請(qǐng)求按鈕:
很明顯每次cancel()都失敗了,仍舊成功的訪問(wèn)了網(wǎng)絡(luò),在cancel()時(shí)已經(jīng)有讀寫(xiě)操作了所以會(huì)報(bào)IOException。每隔100毫秒來(lái)調(diào)用call.cancel()顯然時(shí)間間隔太長(zhǎng),我們?cè)O(shè)置為1毫秒并不斷的快速的點(diǎn)擊發(fā)送請(qǐng)求按鈕:
沒(méi)有請(qǐng)求網(wǎng)絡(luò)的log,幾乎每次都取消成功了。
8.關(guān)于封裝如果每次請(qǐng)求網(wǎng)絡(luò)都需要寫(xiě)重復(fù)的代碼絕對(duì)是令人頭疼的,網(wǎng)上也有很多對(duì)OkHttp封裝的優(yōu)秀開(kāi)源項(xiàng)目,功能也非常強(qiáng)大,封裝的意義就在于更加方便的使用,具有拓展性,但是對(duì)OkHttp封裝最需要解決的是以下的兩點(diǎn):
避免重復(fù)代碼調(diào)用
將請(qǐng)求結(jié)果回調(diào)改為UI線程
根據(jù)以上兩點(diǎn),我們也簡(jiǎn)單封裝一下,在此只是舉個(gè)例子,如果想要使用OkHttp封裝的開(kāi)源庫(kù),推薦使用OkHttpFinal。
首先呢我們寫(xiě)一個(gè)抽象類(lèi)用于請(qǐng)求回調(diào):
public abstract class ResultCallback{ public abstract void onError(Request request, Exception e); public abstract void onResponse(Response response); }
接下來(lái)封裝OkHttp,并實(shí)現(xiàn)了異步GET請(qǐng)求:
public class OkHttpEngine { private static OkHttpEngine mInstance; private OkHttpClient mOkHttpClient; private Handler mHandler; public static OkHttpEngine getInstance() { if (mInstance == null) { synchronized (OkHttpEngine.class) { if (mInstance == null) { mInstance = new OkHttpEngine(); } } } return mInstance; } private OkHttpEngine() { mOkHttpClient = new OkHttpClient(); mOkHttpClient.setConnectTimeout(15, TimeUnit.SECONDS); mOkHttpClient.setWriteTimeout(20, TimeUnit.SECONDS); mOkHttpClient.setReadTimeout(20, TimeUnit.SECONDS); mHandler = new Handler(); } public OkHttpEngine setCache(Context mContext) { File sdcache = mContext.getExternalCacheDir(); int cacheSize = 10 * 1024 * 1024; mOkHttpClient.setCache(new Cache(sdcache.getAbsoluteFile(), cacheSize)); return mInstance; } /** * 異步get請(qǐng)求 * @param url * @param callback */ public void getAsynHttp(String url, ResultCallback callback) { final Request request = new Request.Builder() .url(url) .build(); Call call = mOkHttpClient.newCall(request); dealResult(call, callback); } private void dealResult(Call call, final ResultCallback callback) { call.enqueue(new Callback() { @Override public void onFailure(Request request, IOException e) { sendFailedCallback(request, e, callback); } @Override public void onResponse(final Response response) throws IOException { sendSuccessCallback(response, callback); } private void sendSuccessCallback(final Response object, final ResultCallback callback) { mHandler.post(new Runnable() { @Override public void run() { if (callback != null) { callback.onResponse(object); } } }); } private void sendFailedCallback(final Request request, final Exception e, final ResultCallback callback) { mHandler.post(new Runnable() { @Override public void run() { if (callback != null) callback.onError(request, e); } }); } }); } }
原理很簡(jiǎn)單就是,寫(xiě)一個(gè)雙重檢查模式的單例,不了解雙重檢查模式的請(qǐng)查看設(shè)計(jì)模式之單例模式的七種寫(xiě)法這篇文章。在開(kāi)始創(chuàng)建的時(shí)候配置好OkHttpClient,在請(qǐng)求網(wǎng)絡(luò)的時(shí)候用Handler將請(qǐng)求的結(jié)果回調(diào)給UI線程。
最后調(diào)用這個(gè)OkHttpEngine的getAsynHttp()方法:
OkHttpEngine.getInstance().getAsynHttp("http://www.baidu.com", new ResultCallback() { @Override public void onError(Request request, Exception e) { } @Override public void onResponse(Response response) { String str = response.networkResponse().toString(); Log.i("wangshu", str); Toast.makeText(getApplicationContext(), "請(qǐng)求成功", Toast.LENGTH_SHORT).show(); } });
使用起來(lái)簡(jiǎn)單多了,而且請(qǐng)求結(jié)果回調(diào)是在UI線程的。下一篇我們會(huì)講到OkHttp3,來(lái)看看它與OkHttp2.x之間的使用方式上有什么區(qū)別。
github源碼下載
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/70589.html
摘要:使用前準(zhǔn)備配置添加網(wǎng)絡(luò)權(quán)限異步請(qǐng)求慣例,請(qǐng)求百度可以省略,默認(rèn)是請(qǐng)求請(qǐng)求成功與版本并沒(méi)有什么不同,比較郁悶的是回調(diào)仍然不在線程。 前言 上一篇介紹了OkHttp2.x的用法,這一篇文章我們來(lái)對(duì)照OkHttp2.x版本來(lái)看看,OkHttp3使用起來(lái)有那些變化。當(dāng)然,看這篇文章前建議看一下前一篇文章Android網(wǎng)絡(luò)編程(五)OkHttp2.x用法全解析。 1.使用前準(zhǔn)備 Android ...
摘要:異步請(qǐng)求當(dāng)正在運(yùn)行的異步請(qǐng)求隊(duì)列中的數(shù)量小于并且正在運(yùn)行的請(qǐng)求主機(jī)數(shù)小于時(shí)則把請(qǐng)求加載到中并在線程池中執(zhí)行,否則就再入到中進(jìn)行緩存等待。通常情況下攔截器用來(lái)添加,移除或者轉(zhuǎn)換請(qǐng)求或者響應(yīng)的頭部信息。 前言 學(xué)會(huì)了OkHttp3的用法后,我們當(dāng)然有必要來(lái)了解下OkHttp3的源碼,當(dāng)然現(xiàn)在網(wǎng)上的文章很多,我仍舊希望我這一系列文章篇是最簡(jiǎn)潔易懂的。 1.從請(qǐng)求處理開(kāi)始分析 首先OKHttp...
摘要:前言想必很多人都用過(guò),為了建立網(wǎng)絡(luò)編程的知識(shí)體系,是必須要講的知識(shí)點(diǎn),所以我這里有必要再次介紹一下的使用。簡(jiǎn)介在年大會(huì)上推出了一個(gè)新的網(wǎng)絡(luò)通信框架。在使用前請(qǐng)下載庫(kù)并放在目錄下并到工程中。 前言 Volley想必很多人都用過(guò),為了建立網(wǎng)絡(luò)編程的知識(shí)體系,Volley是必須要講的知識(shí)點(diǎn),所以我這里有必要再次介紹一下Volley的使用。 1.Volley簡(jiǎn)介 在2013年Google I/...
閱讀 913·2023-04-25 22:57
閱讀 3139·2021-11-23 10:03
閱讀 685·2021-11-22 15:24
閱讀 3248·2021-11-02 14:47
閱讀 2990·2021-09-10 11:23
閱讀 3196·2021-09-06 15:00
閱讀 4042·2019-08-30 15:56
閱讀 3405·2019-08-30 15:52