android分享图片功能实现原理,Android:简单实现并理解图片三级缓存
學(xué)習(xí)Android網(wǎng)絡(luò)開發(fā)的過程中,勢必會經(jīng)歷很多痛苦的過程,其中一個大坑就是圖片緩存,當(dāng)然現(xiàn)在有很多現(xiàn)成的庫非常方便,常常幾行代碼就可以實現(xiàn)想要的功能,但不懂其中的原理是不行的,所以對于剛開始學(xué)習(xí)網(wǎng)絡(luò)編程的小猿們,最好的方法就是手動實現(xiàn)一下。沒有經(jīng)歷過HttpClient或HttpUrlConnection連接網(wǎng)絡(luò)的繁瑣過程,怎么能感受到OkHttp,Volley,Retrofit的方便,下面,我們就一起開始學(xué)習(xí)圖片三級緩存。
使用圖片緩存的原因
提高用戶體驗:如果每次啟動都從網(wǎng)絡(luò)下載圖片,勢必會加載很慢,圖片無法顯示,或需要很久才能完全顯示,用戶體驗及其不好
節(jié)約流量:如果每次加載頁面,甚至只是滑動控件瀏覽就會下載的話,會消耗很多流量,占用網(wǎng)絡(luò)資源的同時,也會因為應(yīng)用耗流量而用戶數(shù)量級受到影響
什么是三級緩存
內(nèi)存緩存:優(yōu)先加載,速度最快
本地緩存:次優(yōu)先加載,速度較快
網(wǎng)絡(luò)緩存:最后加載,速度較慢
緩存策略
為什么使用緩存策略
上面從用戶角度考慮了為什么要使用圖片緩存,此外,從開發(fā)人員角度看,Bitmap的創(chuàng)建非常消耗時間和內(nèi)存,可能導(dǎo)致頻繁GC,使用緩存策略能夠高效加載Bitmap,減少卡頓,從而減少讀取耗時和電量消耗。
緩存策略是什么
具體通過三級級緩存策略,內(nèi)存作為一級緩存,本地作為二級緩存,網(wǎng)絡(luò)直接下載為最后,其實嚴格來說不算緩存。其中內(nèi)存采用LruCache,其內(nèi)部通過LinkedhashMap來持有外界緩存對象的強引用;對于本地緩存,我這里為了簡單快速理解原理,直接使用的是文件IO操作,而網(wǎng)上也有人采用DiskLruCache (不是Android官網(wǎng)提供,但被官網(wǎng)推薦)。加載圖片時,首先采用LRU方式進行尋找,若找不到指定內(nèi)容,則進行本地搜索,若本地也找不到,向網(wǎng)絡(luò)發(fā)起請求來獲取圖片。
圖片請求緩存框架
調(diào)用bindBitmap,傳遞url和ImageView,首先是loadBitmapFromMemCache從內(nèi)存緩沖區(qū)中根據(jù)url去找,如果找不到的話,則調(diào)用loadBitmap,通過一個runnable,提交到線程池,得到結(jié)果后,通過主線程handler來進行ui的更新。這里要注意,當(dāng)我們加載圖片的時候,如果圖片從內(nèi)存中找不到,調(diào)用了loadBitmap,這個時候,已經(jīng)將loadbitmap封裝在Runnable中,然后提交到線程池中了,也就是后續(xù)的都是和主線程處于異步的狀態(tài)同時展開的了,可以很好的解決因為Bitmap的申請創(chuàng)建耗時導(dǎo)致的掉幀現(xiàn)象的出現(xiàn)。
下面是loadBitmap的工作流程:
上圖中,對于loadBitmapFromHttp,在調(diào)用的時候,通過urlConnection,將網(wǎng)絡(luò)的數(shù)據(jù)流寫入到本地后,然后又調(diào)用的laodBitmapFromDiskCache,也就是在圖片被下載下來之后,首先會將其添加到我們的本地磁盤緩存中,然后當(dāng)這個圖片被使用的時候,我們又會將其添加到我們的內(nèi)存緩存中。
以上就是整個圖片請求緩存框架的流程介紹,基本都是按照函數(shù)方法的設(shè)計進行介紹的,下面就來看看在代碼中,應(yīng)該如何實現(xiàn)。
圖片緩存代碼實現(xiàn)
首先是整個緩存的函數(shù),相當(dāng)于前面圖中的 bindBitmap,根據(jù)Url來獲取圖片Bitmap。
1、從內(nèi)存中獲取,函數(shù):loadBitmapFromMemCache,這里用到LruCache,是Android提供的一個緩存工具類,其算法是最近最少使用算法。它把最近使用的對象用“強引用”存儲在LinkedHashMap中,并且把最近最少使用的對象在緩存值達到預(yù)設(shè)定值之前就從內(nèi)存中移除。
注意,這里是將url作為key值進行哈希,因為url中可能有特殊字符影響使用,一般采用其MD5值來作為key,我這里沒有實現(xiàn),只是簡單的將特殊符號進行了替換。
2、從磁盤中加載,函數(shù):loadBitmapFromDiskCache
這里我用了自己寫的工具類FileUtils來進行文件的讀寫,主要包括sd卡的檢查,讀取圖片,存取圖片等操作。注意,若從文件中獲取成功,則將其按照鍵值對的形式存至內(nèi)存中。
3、從網(wǎng)絡(luò)中獲取圖片,函數(shù):loadBitmapFromHttp
同理,這里用了工具類HttpUtils來進行網(wǎng)絡(luò)的連接,獲取輸入流InputStream,同時將流直接BitmapFactory.decodeStream轉(zhuǎn)為Bitmap。若從網(wǎng)絡(luò)獲取圖片成功,要將圖片存入磁盤緩存,同時寫入內(nèi)存。
至此,一個簡易的圖片緩存框架就結(jié)束了,但還要注意一下幾點:
Bitmap縮放:從網(wǎng)絡(luò)加載過來的圖片我們不可能將其全部加載到內(nèi)存,需要根據(jù)其大小做一個顯示的處理,獲取圖片的寬高,根據(jù)控件的寬高進行一個縮放,用BitmapFactory.Options修改其屬性后,設(shè)置為該Bitmap的屬性,具體代碼比較容易實現(xiàn),網(wǎng)上教程較多,這里不再贅述。
AsyncTask線程池問題:這里在實現(xiàn)加載圖片時大多是在多線程中進行的,而android中比較常用比較方便的就是AsyncTask,我按照上述代碼完成后,發(fā)現(xiàn)程序加載圖片速度沒有明顯改進,依然會有一個肉眼可見的緩慢過程,經(jīng)過閱讀源碼發(fā)現(xiàn),雖然利用AsyncTask表面開啟了多個線程,但實際其底層只開了一個單線程順序執(zhí)行,因而想要同時開啟多個線程下載需要用線程池的方式開啟AsyncTask,具體原因見我上一篇博客
創(chuàng)建類ImageLoader,將imageview,bitmap和url綁定在一起,同時給imageview設(shè)置tag進行標(biāo)記,防止因為異步下載導(dǎo)致的圖片錯位
附上代碼用到的工具類代碼
1、Http工具類
2、File工具類
參考資料
總結(jié)
以上是生活随笔為你收集整理的android分享图片功能实现原理,Android:简单实现并理解图片三级缓存的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: java的reentrantlock_J
- 下一篇: JAVA获得天气json数据的方法,获取