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