HttpURLConnection和HttpClient對比:android
http://blog.csdn.net/guolin_blog/article/details/12452307git
HttpURL基本封裝github
http://www.jianshu.com/p/3141d4e46240算法
緩存對於移動端是很是重要的存在。編程
緩存通常由服務器控制(經過某些方式能夠本地控制緩存,好比向過濾器添加緩存控制信息)。緩存
Request服務器
請求頭字段 | 意義 |
---|---|
If-Modified-Since: Sun, 03 Jan 2016 03:47:16 GMT | 緩存文件的最後修改時間。 |
If-None-Match: "3415g77s19tc3:0" | 緩存文件的Etag(Hash)值 |
Cache-Control: no-cache | 不使用緩存 |
Pragma: no-cache | 不使用緩存 |
Response網絡
響應頭字段 | 意義 |
---|---|
Cache-Control: public | 響應被共有緩存,移動端無用 |
Cache-Control: private | 響應被私有緩存,移動端無用 |
Cache-Control:no-cache | 不緩存 |
Cache-Control:no-store | 不緩存 |
Cache-Control: max-age=60 | 60秒以後緩存過時(相對時間) |
Date: Sun, 03 Jan 2016 04:07:01 GMT | 當前response發送的時間 |
Expires: Sun, 03 Jan 2016 07:07:01 GMT | 緩存過時的時間(絕對時間) |
Last-Modified: Sun, 03 Jan 2016 04:07:01 GMT | 服務器端文件的最後修改時間 |
ETag: "3415g77s19tc3:0" | 服務器端文件的Etag[Hash]值 |
正式使用時按需求也許只包含其中部分字段。
客戶端要根據這些信息儲存此次請求信息。
而後在客戶端發起請求的時候要檢查緩存。遵循下面步驟:session
Volley&OkHttp應該是如今最經常使用的網絡請求庫。用法也很是類似。都是用構造請求加入請求隊列的方式管理網絡請求。
先說Volley:
Volley能夠經過這個庫進行依賴.
Volley在Android 2.3及以上版本,使用的是HttpURLConnection,而在Android 2.2及如下版本,使用的是HttpClient。
Volley的基本用法,網上資料無數,這裏推薦郭霖大神的博客
Volley存在一個緩存線程,一個網絡請求線程池(默認4個線程)。
Volley這樣直接用開發效率會比較低,我將我使用Volley時的各類技巧封裝成了一個庫RequestVolly.
我在這個庫中將構造請求的方式封裝爲了函數式調用。維持一個全局的請求隊列,拓展一些方便的API。
不過再怎麼封裝Volley在功能拓展性上始終沒法與OkHttp相比。
Volley中止了更新,而OkHttp獲得了官方的承認,並在不斷優化。
所以我最終替換爲了OkHttp
OkHttp用法見這裏
很友好的API與詳盡的文檔。
這篇文章也寫的很詳細了。
OkHttp使用Okio進行數據傳輸。都是Square家的。
但並非直接用OkHttp。Square公司還出了一個Retrofit庫配合OkHttp戰鬥力翻倍。
Retrofit極大的簡化了網絡請求的操做,它應該說只是一個Rest API管理庫,它是直接使用OKHttp進行網絡請求並不影響你對OkHttp進行配置。畢竟都是Square公司出品。
RestAPI是一種軟件設計風格。
服務器做爲資源存放地。客戶端去請求GET,PUT, POST,DELETE資源。而且是無狀態的,沒有session的參與。
移動端與服務器交互最重要的就是API的設計。好比這是一個標準的登陸接口。
大家應該看的出這個接口對應的請求包與響應包大概是什麼樣子吧。
請求方式,請求參數,響應數據,都很清晰。
使用Retrofit這些API能夠直觀的體如今代碼中。
而後使用Retrofit提供給你的這個接口的實現類 就能直接進行網絡請求得到結構數據。
注意Retrofit2.0相較1.9進行了大量不兼容更新。google上大部分教程都是基於1.9的。這裏有個2.0的教程。
教程裏進行異步請求是使用Call。Retrofit最強大的地方在於支持RxJava。就像我上圖中返回的是一個Observable。RxJava上手難度比較高,但用過就再也離不開了。Retrofit+OkHttp+RxJava配合框架打出成噸的輸出,這裏再也不多說。
網絡請求學習到這裏我以爲已經到頂了。。
對於圖片的傳輸,就像上面的登陸接口的avatar字段,並不會直接把圖片寫在返回內容裏,而是給一個圖片的地址。須要時再去加載。
若是你直接用HttpURLConnection去取一張圖片,你辦獲得,不過沒優化就只是個BUG不斷demo。絕對不能正式使用。
注意網絡圖片有些特色:
說說我在上面提到的RequestVolley裏作的圖片請求處理(沒錯我作了,這部分的代碼能夠去github裏看源碼)。
網上常說三級緩存--服務器,文件,內存。不過我以爲服務器不算是一級緩存,那就是數據源嘛。
內存緩存
首先內存緩存使用LruCache。LRU是Least Recently Used 近期最少使用算法,這裏肯定一個大小,當Map裏對象大小總和大於這個大小時將使用頻率最低的對象釋放。我將內存大小限制爲進程可用內存的1/8.
內存緩存裏讀獲得的數據就直接返回,讀不到的向硬盤緩存要數據。
硬盤緩存
硬盤緩存使用DiskLruCache。這個類不在API中。得複製使用。
看見LRU就明白了吧。我將硬盤緩存大小設置爲100M。
@Override public void putBitmap(String url, Bitmap bitmap) { put(url, bitmap); //向內存Lru緩存存放數據時,主動放進硬盤緩存裏 try { Editor editor = mDiskLruCache.edit(hashKeyForDisk(url)); bitmap.compress(Bitmap.CompressFormat.JPEG, 100, editor.newOutputStream(0)); editor.commit(); } catch (IOException e) { e.printStackTrace(); } } //當內存Lru緩存中沒有所需數據時,調用創造。 @Override protected Bitmap create(String url) { //獲取key String key = hashKeyForDisk(url); //從硬盤讀取數據 Bitmap bitmap = null; try { DiskLruCache.Snapshot snapShot = mDiskLruCache.get(key); if(snapShot!=null){ bitmap = BitmapFactory.decodeStream(snapShot.getInputStream(0)); } } catch (IOException e) { e.printStackTrace(); } return bitmap; }
DiskLruCache的原理再也不解釋了(我還解決了它存在的一個BUG,向Log中添加的數據增刪記錄時,最後一條沒有輸出,致使最後一條緩存一直失效。)
這就是整個流程。
但我這樣的處理方案仍是有不少侷限。
之前也以爲這樣已經足夠好直到我遇到下面倆。
不用想也知道它們都作了很是完善的優化,重複造輪子的行爲很蠢。
Fresco是Facebook公司的黑科技。光看功能介紹就看出很是強大。使用方法官方博客說的夠詳細了。
真三級緩存,變換後的BItmap(內存),變換前的原始圖片(內存),硬盤緩存。
在內存管理上作到了極致。對於重度圖片使用的APP應該是很是好的。
它通常是直接使用SimpleDraweeView
來替換ImageView
,呃~侵入性較強,依賴上它apk包直接大1M。代碼量驚人。
因此我更喜歡Glide,做者是bumptech。這個庫被普遍的運用在google的開源項目中,包括2014年google I/O大會上發佈的官方app。
這裏有詳細介紹。直接使用ImageView便可,無需初始化,極簡的API,豐富的拓展,鏈式調用都是我喜歡的。
豐富的拓展指的就是這個。
另外我也用過Picasso。API與Glide簡直如出一轍,功能略少,且有半年未修復的BUG。
再說說圖片存儲。不要存在本身服務器上面,徒增流量壓力,尚未圖片處理功能。
推薦七牛與阿里雲存儲(沒用過其它 π__π )。它們都有很重要的一項圖片處理。在圖片Url上加上參數來對圖片進行一些處理再傳輸。
因而(七牛的處理代碼)
public static String getSmallImage(String image){ if (image==null)return null; if (isQiniuAddress(image)) image+="?imageView2/0/w/"+IMAGE_SIZE_SMALL; return image; } public static String getLargeImage(String image){ if (image==null)return null; if (isQiniuAddress(image)) image+="?imageView2/0/w/"+IMAGE_SIZE_LARGE; return image; } public static String getSizeImage(String image,int width){ if (image==null)return null; if (isQiniuAddress(image)) image+="?imageView2/0/w/"+width; return image; }
既能夠加快請求速度,又能減小流量。再配合Fresco或Glide。完美的圖片加載方案。
不過這就須要你把全部圖片都存放在七牛或阿里雲,這樣也不錯。
圖片/文件上傳也都是使用它們第三方存儲,它們都有SDK與官方文檔教你。不過圖片必定要壓縮事後上傳。上傳1-2M大的高清照片沒意義。