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