Android - 网络基础
Android網(wǎng)絡(luò)編程(一)HTTP協(xié)議原理
Android網(wǎng)絡(luò)請求心路歷程
?
HttpURLConnection和HttpClient對比:
http://blog.csdn.net/guolin_blog/article/details/12452307
?
HttpURL基本封裝
http://www.jianshu.com/p/3141d4e46240
?
HTTP緩存機(jī)制
緩存對于移動端是非常重要的存在。
- 減少請求次數(shù),減小服務(wù)器壓力.
- 本地?cái)?shù)據(jù)讀取速度更快,讓頁面不會空白幾百毫秒。
- 在無網(wǎng)絡(luò)的情況下提供數(shù)據(jù)。
緩存一般由服務(wù)器控制(通過某些方式可以本地控制緩存,比如向過濾器添加緩存控制信息)。
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 | 響應(yīng)被共有緩存,移動端無用 |
| Cache-Control: private | 響應(yīng)被私有緩存,移動端無用 |
| Cache-Control:no-cache | 不緩存 |
| Cache-Control:no-store | 不緩存 |
| Cache-Control: max-age=60 | 60秒之后緩存過期(相對時間) |
| Date: Sun, 03 Jan 2016 04:07:01 GMT | 當(dāng)前response發(fā)送的時間 |
| Expires: Sun, 03 Jan 2016 07:07:01 GMT | 緩存過期的時間(絕對時間) |
| Last-Modified: Sun, 03 Jan 2016 04:07:01 GMT | 服務(wù)器端文件的最后修改時間 |
| ETag: "3415g77s19tc3:0" | 服務(wù)器端文件的Etag[Hash]值 |
正式使用時按需求也許只包含其中部分字段。
客戶端要根據(jù)這些信息儲存這次請求信息。
然后在客戶端發(fā)起請求的時候要檢查緩存。遵循下面步驟:
?
Volley&OkHttp
Volley&OkHttp應(yīng)該是現(xiàn)在最常用的網(wǎng)絡(luò)請求庫。用法也非常相似。都是用構(gòu)造請求加入請求隊(duì)列的方式管理網(wǎng)絡(luò)請求。
先說Volley:
Volley可以通過這個庫進(jìn)行依賴.
Volley在Android 2.3及以上版本,使用的是HttpURLConnection,而在Android 2.2及以下版本,使用的是HttpClient。
Volley的基本用法,網(wǎng)上資料無數(shù),這里推薦郭霖大神的博客
Volley存在一個緩存線程,一個網(wǎng)絡(luò)請求線程池(默認(rèn)4個線程)。
Volley這樣直接用開發(fā)效率會比較低,我將我使用Volley時的各種技巧封裝成了一個庫RequestVolly.
我在這個庫中將構(gòu)造請求的方式封裝為了函數(shù)式調(diào)用。維持一個全局的請求隊(duì)列,拓展一些方便的API。
不過再怎么封裝Volley在功能拓展性上始終無法與OkHttp相比。
Volley停止了更新,而OkHttp得到了官方的認(rèn)可,并在不斷優(yōu)化。
因此我最終替換為了OkHttp
OkHttp用法見這里
很友好的API與詳盡的文檔。
這篇文章也寫的很詳細(xì)了。
OkHttp使用Okio進(jìn)行數(shù)據(jù)傳輸。都是Square家的。
但并不是直接用OkHttp。Square公司還出了一個Retrofit庫配合OkHttp戰(zhàn)斗力翻倍。
Retrofit&RestAPI
Retrofit極大的簡化了網(wǎng)絡(luò)請求的操作,它應(yīng)該說只是一個Rest API管理庫,它是直接使用OKHttp進(jìn)行網(wǎng)絡(luò)請求并不影響你對OkHttp進(jìn)行配置。畢竟都是Square公司出品。
RestAPI是一種軟件設(shè)計(jì)風(fēng)格。
服務(wù)器作為資源存放地。客戶端去請求GET,PUT, POST,DELETE資源。并且是無狀態(tài)的,沒有session的參與。
移動端與服務(wù)器交互最重要的就是API的設(shè)計(jì)。比如這是一個標(biāo)準(zhǔn)的登錄接口。
Paste_Image.png
你們應(yīng)該看的出這個接口對應(yīng)的請求包與響應(yīng)包大概是什么樣子吧。
請求方式,請求參數(shù),響應(yīng)數(shù)據(jù),都很清晰。
使用Retrofit這些API可以直觀的體現(xiàn)在代碼中。
Paste_Image.png
然后使用Retrofit提供給你的這個接口的實(shí)現(xiàn)類 就能直接進(jìn)行網(wǎng)絡(luò)請求獲得結(jié)構(gòu)數(shù)據(jù)。
注意Retrofit2.0相較1.9進(jìn)行了大量不兼容更新。google上大部分教程都是基于1.9的。這里有個2.0的教程。
教程里進(jìn)行異步請求是使用Call。Retrofit最強(qiáng)大的地方在于支持RxJava。就像我上圖中返回的是一個Observable。RxJava上手難度比較高,但用過就再也離不開了。Retrofit+OkHttp+RxJava配合框架打出成噸的輸出,這里不再多說。
網(wǎng)絡(luò)請求學(xué)習(xí)到這里我覺得已經(jīng)到頂了。。
網(wǎng)絡(luò)圖片加載優(yōu)化
對于圖片的傳輸,就像上面的登錄接口的avatar字段,并不會直接把圖片寫在返回內(nèi)容里,而是給一個圖片的地址。需要時再去加載。
如果你直接用HttpURLConnection去取一張圖片,你辦得到,不過沒優(yōu)化就只是個BUG不斷demo。絕對不能正式使用。
注意網(wǎng)絡(luò)圖片有些特點(diǎn):
一個鏈接對應(yīng)的圖片一般永遠(yuǎn)不會變,所以當(dāng)?shù)谝淮渭虞d了圖片時,就應(yīng)該予以永久緩存,以后就不再網(wǎng)絡(luò)請求。
一張圖片小的幾十k多的幾M高清無碼。尺寸也是64*64到2k圖。你不能就這樣直接顯示到UI,甚至不能直接放進(jìn)內(nèi)存。
加載一張圖片需要幾百ms到幾m。這期間的UI占位圖功能也是必須考慮的。
說說我在上面提到的RequestVolley里做的圖片請求處理(沒錯我做了,這部分的代碼可以去github里看源碼)。
三級緩存
網(wǎng)上常說三級緩存--服務(wù)器,文件,內(nèi)存。不過我覺得服務(wù)器不算是一級緩存,那就是數(shù)據(jù)源嘛。
-
內(nèi)存緩存
首先內(nèi)存緩存使用LruCache。LRU是Least Recently Used 近期最少使用算法,這里確定一個大小,當(dāng)Map里對象大小總和大于這個大小時將使用頻率最低的對象釋放。我將內(nèi)存大小限制為進(jìn)程可用內(nèi)存的1/8.
內(nèi)存緩存里讀得到的數(shù)據(jù)就直接返回,讀不到的向硬盤緩存要數(shù)據(jù)。 -
硬盤緩存
硬盤緩存使用DiskLruCache。這個類不在API中。得復(fù)制使用。
看見LRU就明白了吧。我將硬盤緩存大小設(shè)置為100M。
@Overridepublic void putBitmap(String url, Bitmap bitmap) {put(url, bitmap);//向內(nèi)存Lru緩存存放數(shù)據(jù)時,主動放進(jìn)硬盤緩存里try {Editor editor = mDiskLruCache.edit(hashKeyForDisk(url));bitmap.compress(Bitmap.CompressFormat.JPEG, 100, editor.newOutputStream(0));editor.commit();} catch (IOException e) {e.printStackTrace();}}//當(dāng)內(nèi)存Lru緩存中沒有所需數(shù)據(jù)時,調(diào)用創(chuàng)造。 @Overrideprotected Bitmap create(String url) {//獲取keyString key = hashKeyForDisk(url);//從硬盤讀取數(shù)據(jù)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中添加的數(shù)據(jù)增刪記錄時,最后一條沒有輸出,導(dǎo)致最后一條緩存一直失效。)
- 硬盤緩存也沒有數(shù)據(jù)就返回空,然后就向服務(wù)器請求數(shù)據(jù)。
這就是整個流程。
但我這樣的處理方案還是有很多局限。
- 圖片未經(jīng)壓縮處理直接存儲使用
- 文件操作在主線程
- 沒有完善的圖片處理API
以前也覺得這樣已經(jīng)足夠好直到我遇到下面?zhèn)z。
Fresco&Glide
不用想也知道它們都做了非常完善的優(yōu)化,重復(fù)造輪子的行為很蠢。
Fresco是Facebook公司的黑科技。光看功能介紹就看出非常強(qiáng)大。使用方法官方博客說的夠詳細(xì)了。
真三級緩存,變換后的BItmap(內(nèi)存),變換前的原始圖片(內(nèi)存),硬盤緩存。
在內(nèi)存管理上做到了極致。對于重度圖片使用的APP應(yīng)該是非常好的。
它一般是直接使用SimpleDraweeView來替換ImageView,呃~侵入性較強(qiáng),依賴上它apk包直接大1M。代碼量驚人。
所以我更喜歡Glide,作者是bumptech。這個庫被廣泛的運(yùn)用在google的開源項(xiàng)目中,包括2014年google I/O大會上發(fā)布的官方app。
這里有詳細(xì)介紹。直接使用ImageView即可,無需初始化,極簡的API,豐富的拓展,鏈?zhǔn)秸{(diào)用都是我喜歡的。
豐富的拓展指的就是這個。
另外我也用過Picasso。API與Glide簡直一模一樣,功能略少,且有半年未修復(fù)的BUG。
圖片管理方案
再說說圖片存儲。不要存在自己服務(wù)器上面,徒增流量壓力,還沒有圖片處理功能。
推薦七牛與阿里云存儲(沒用過其它 π__π )。它們都有很重要的一項(xiàng)圖片處理。在圖片Url上加上參數(shù)來對圖片進(jìn)行一些處理再傳輸。
于是(七牛的處理代碼)
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大的高清照片沒意義。
?
轉(zhuǎn)載于:https://www.cnblogs.com/qlky/p/7237385.html
總結(jié)
以上是生活随笔為你收集整理的Android - 网络基础的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: WinForm-SuspendLayou
- 下一篇: 风险纳税人是什么意思