android仿最新版本微信相冊--附源碼

仿微信相冊選擇圖片懒叛,查看大圖勇蝙,寫的不太好,希望評論指出不足综液,諒解款慨,先介紹一下我的基本思路。
  轉(zhuǎn)載請注明出處:http://blog.csdn.net/self_study/article/details/69397859
  對技術(shù)感興趣的同鞋加群 544645972 一起交流谬莹。

思路

第一步檩奠,獲取所有圖片路徑

第一步獲取手機(jī)上的所有圖片路徑:

Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
ContentResolver contentResolver = getContentResolver();
//獲取jpeg和png格式的文件,并且按照時(shí)間進(jìn)行倒序
Cursor cursor = contentResolver.query(uri, null, MediaStore.Images.Media.MIME_TYPE + "=\"image/jpeg\" or " +
        MediaStore.Images.Media.MIME_TYPE + "=\"image/png\"", null, MediaStore.Images.Media.DATE_MODIFIED+" desc");
if (cursor != null){
    while (cursor.moveToNext()){
        //do something
    }
    handler.sendEmptyMessage(0);
}

然后定義一個(gè)存儲圖片的數(shù)據(jù)格式:

/** 按時(shí)間排序的所有圖片list */  
private ArrayList<SingleImageModel> allImages;  
/** 按目錄排序的所有圖片list */  
private ArrayList<SingleImageDirectories> imageDirectories;  
 /** 
 * 一個(gè)文件夾中的圖片數(shù)據(jù)實(shí)體 
 */  
private class SingleImageDirectories{  
    /** 父目錄的路徑 */  
    public String directoryPath;  
    /** 目錄下的所有圖片實(shí)體 */  
    public ImageDirectoryModel images;  
}  

一個(gè)是全部圖片的存儲順序附帽,第二個(gè)是按照目錄的圖片存儲順序埠戳。

第二步,壓縮加載圖片

獲取到圖片之后蕉扮,放入到 Gridview 中進(jìn)行顯示整胃,但是 BitmapFactory.decodeFile() 函數(shù)會非常耗時(shí),所以為了使得非常流暢的顯示圖片喳钟,創(chuàng)建一個(gè)類 AlbumBitmapCacheHelper屁使,用來異步加載圖片,該類使用 LruCache<String,Bitmap> 來緩存 Bitmap奔则,使得存儲圖片不會造成 OOM蛮寂,我這里設(shè)置 LruCache 的初始大小為 1/4 的運(yùn)行時(shí)內(nèi)存然后使用 ThreadPoolExecutor 線程池來處理圖片的顯示,線程池大小應(yīng)該設(shè)置適中(可以根據(jù)系統(tǒng)的處理器線程數(shù)來設(shè)置易茬,系統(tǒng)也提供一個(gè)相關(guān)的線程池酬蹋,感興趣的也可以去了解),做完這兩件事情之后就可以用來加載圖片了疾呻,方法 getBitmap 用來返回圖片:

Bitmap bitmap = getBitmapFromCache(path, width, height);
//如果能夠從緩存中獲取符合要求的圖片除嘹,則直接回調(diào)
if (bitmap != null) {
} else {
    //新建線程放入線程池去處理該圖片的顯示
}
return bitmap;

如果 cache 中找不到該圖片,則調(diào)用 BitmapFactory.decodeFile() 去加載圖片岸蜗,加載圖片不能夠直接加載原圖尉咕,會造成 OOM,所以要去計(jì)算壓縮比:

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
options.inSampleSize = computeScale(options, width, height);
options.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeFile(path, options);
//獲取之后璃岳,放入緩存年缎,以便下次繼續(xù)使用
if (bitmap != null && cache!=null) {
    cache.put(path, bitmap);
}

方法 computeScale() 主要是計(jì)算圖片最小的壓縮比悔捶,這樣在 Gridview 中的 getview 方法中去調(diào)用 AlbumBitmapCacheHelper 的 getBitmap() 方法即可。

第三步单芜,處理顯示問題

經(jīng)過上面的處理之后蜕该,在實(shí)際顯示的時(shí)候會出現(xiàn)一些問題,這里也匯總和分析一下:

顯示圖片閃爍

第一個(gè)問題就是圖片顯示會閃爍洲鸠,這主要是由于 getview 方法的 convertView 的復(fù)用導(dǎo)致一個(gè) Imageview 被設(shè)置多次 background堂淡,解決方法就是使用 setTag 方法:

holder.iv_content.setTag(path);

將要顯示的 Imageview 的 tag 設(shè)置為需要顯示的圖片路徑,這樣在回調(diào)的時(shí)候使用方法 gridView.findViewWithTag(path)扒腕,找到這個(gè) Imageview 進(jìn)行顯示绢淀,閃爍的問題就解決了。

大圖片加載速度緩慢

第二個(gè)問題就是加載速度很慢瘾腰,拉的速度很快的情況下皆的,圖片要很久才會加載出來,特別是很大的圖片蹋盆,比如拍照和截圖的照片费薄,這個(gè)問題可以有兩個(gè)步驟去優(yōu)化:第一個(gè)優(yōu)化方案就是在 AlbumBitmapCacheHelper 類中維護(hù)一個(gè) ArrayList<String> currentShowString,在 getView 方法中栖雾,如果該圖片要顯示楞抡,則直接將 path 加入到該 list 中,同時(shí)如果這個(gè) view 的 tag 不為空析藕,說明該 view 的原來的 path 是不需要顯示的拌倍,所以需要將這個(gè) path 從 ArrayList 中刪除:

//優(yōu)化顯示效果
if(holder.iv_content.getTag() != null) {
    String remove = (String) holder.iv_content.getTag();
    AlbumBitmapCacheHelper.getInstance().removePathFromShowlist(remove);
}
AlbumBitmapCacheHelper.getInstance().addPathToShowlist(path);

這樣在線程池中的處理方式就是先查看需要顯示的 path 是否在 ArrayList 中,如果沒有在 ArrayList 中噪径,則該線程直接關(guān)閉,如果在 ArrayList 中数初,則顯示該圖片:

if (!currentShowString.contains(path)||cache==null) {
         return;
}

第二個(gè)優(yōu)化方案是如果顯示的圖片很大找爱,特別是拍照和截圖的圖片,decode 有時(shí)會耗時(shí)幾秒鐘泡孩,微信顯示效果非常好车摄,我自己參考微信的表現(xiàn)想出來的處理的方式是:<ol><li>第一步,從應(yīng)用的緩存 temp 目錄下取仑鸥,如果取不到吮播,則進(jìn)行下一步;</li><li>第二步眼俊,計(jì)算圖片的壓縮比例 samplesize意狠,如果 samplesize < 4(根據(jù)表現(xiàn)一般的相機(jī)拍攝照片為 4000*3000,需要縮放 4 倍才能加速 decode 步驟)疮胖,圖片的 BitmapFactory.decodeFile() 時(shí)間短环戈,直接返回圖片闷板,但是如果 samplesize > 4,執(zhí)行第三步院塞;</li><li>第三步則將壓縮后的圖片存入 temp 目錄下遮晚,以便下次快速取出,這樣微信圖片展示的效果就出來了拦止,顯示的速度和微信一樣县遣,第一次大圖加載慢之外,之后的顯示就能很快:

if (!new File(CommonUtil.getDataPath()).exists())
    new File(CommonUtil.getDataPath()).mkdirs();
//臨時(shí)文件的文件名
String tempPath = CommonUtil.getDataPath() + hash + ".temp";
//如果該文件存在
if (new File(tempPath).exists())
    bitmap = BitmapFactory.decodeFile(tempPath);
......
//第三步,如果縮放比例大于4汹族,該圖的加載會非常慢萧求,所以將該圖保存到臨時(shí)目錄下以便下次的快速加載
if (options.inSampleSize >= 4) {
    try {
        File file = new File(tempPath);
        if (!file.exists())
            file.createNewFile();
        FileOutputStream fos = new FileOutputStream(file);
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        bitmap.compress(Bitmap.CompressFormat.PNG, 100, baos);
        fos.write(baos.toByteArray());
        fos.flush();
        fos.close();
    } catch (FileNotFoundException e) {
        e.printStackTrace();
    } catch (IOException e) {
        e.printStackTrace();
    }
}

</li></ol>
問題到這里就差不多解決了;

第四步鞠抑,詳情頁面大圖的展示

第四步大圖的查看饭聚,大圖主要是使用網(wǎng)上開源的 ZoomImageView+Viewpagger 的組合,但是使用這個(gè)出現(xiàn)的問題就是很容易 OOM搁拙,沒辦法秒梳,我的處理方式就是在點(diǎn)進(jìn)去大圖的時(shí)候:

public void releaseHalfSizeCache() {  
    cache.resize((int) (Runtime.getRuntime().maxMemory() / 1024 / 8));  
}  

直接將 LruCache 的大小變成原來的一半,因?yàn)椴榭创髨D頁加載一張大圖占用的內(nèi)存本身就很大箕速,所以這樣去特殊處理酪碘,顯示效果頁還湊合,有別的方法盐茎,一定要留言告訴我兴垦。
  <font color='red'>還有一點(diǎn)需要注意的是大圖的查看由于需要通過 intent 傳遞數(shù)據(jù),但是 intent 傳遞的數(shù)據(jù)大小不能太大字柠,如果手機(jī)上有幾千張圖片探越,則數(shù)據(jù)量大小可能會超過 intent 所能傳遞的最大量,所以可以寫入一個(gè)公共的地方窑业,共享內(nèi)存钦幔、數(shù)據(jù)庫或者文件都可以,具體的原因可以參考我的另一篇博客:Android TransactionTooLargeException 解析常柄,思考與監(jiān)控方案鲤氢。</font>

第五步,退出相冊頁面清空 LruCache

圖片選擇完成之后西潘,完成善后工作卷玉,將 AlbumBitmapCacheHelper 類中 LruCache 清空,差不多就這樣了喷市,還有很多的功能小點(diǎn)相种,比如圖片時(shí)間的顯示,這里就不詳細(xì)一一去介紹了东抹,具體大家看源碼蚂子。

問題討論

最新發(fā)現(xiàn)的問題:3.0 以前 GC 操作需要很長時(shí)間沃测,經(jīng)常大于 100ms,在執(zhí)行 GC 時(shí)(關(guān)于 JVM 和 ART 的 GC 可以看看我的這篇博客 Android 性能優(yōu)化之內(nèi)存泄漏檢測以及內(nèi)存優(yōu)化(上))食茎,程序就會出現(xiàn)卡的現(xiàn)象蒂破,3.0 以后 GC 修改為同步,執(zhí)行的時(shí)間通常在 5ms 以內(nèi)别渔,在 3.0 以前的版本中附迷,加載圖片時(shí),系統(tǒng)把 Bitmap 加載到 Native 緩存中哎媚,并不受 GC 管理喇伯,需要手機(jī)自己釋放,不然會遇到莫名奇妙的內(nèi)存問題拨与。3.0 以后 Bitmap 直接放到內(nèi)存中在執(zhí)行 GC 時(shí)稻据,會及時(shí)清理無用的 Bitmap 所占的內(nèi)存,在初始化圖片時(shí)把圖片放到內(nèi)存中买喧,當(dāng)加載完后捻悯,系統(tǒng)會把圖片從內(nèi)存轉(zhuǎn)移到顯存中,當(dāng)你用內(nèi)存測試工具時(shí)淤毛,會發(fā)現(xiàn)在加載圖片時(shí)今缚,內(nèi)存占用率很高,當(dāng)加載完成后低淡,內(nèi)存使用量突然下來姓言,加載大量圖片時(shí)會發(fā)現(xiàn)這種情況。
  總而言之就是 2.x 版本的時(shí)候蔗蹋,就算你使用的是 LruCache何荚,Bitmap 還是不會被 GC 主動回收,必須要手動釋放猪杭,所以如果需要適配 2.x 版本兽泣,該 demo 需要加入手動釋放 Bitmap 的操作。

顯示效果

這里寫圖片描述

    
這里寫圖片描述

源碼

源碼下載地址https://github.com/zhaozepeng/AlbumImageSelect胁孙。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市称鳞,隨后出現(xiàn)的幾起案子涮较,更是在濱河造成了極大的恐慌,老刑警劉巖冈止,帶你破解...
    沈念sama閱讀 206,126評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件狂票,死亡現(xiàn)場離奇詭異,居然都是意外死亡熙暴,警方通過查閱死者的電腦和手機(jī)闺属,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評論 2 382
  • 文/潘曉璐 我一進(jìn)店門慌盯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人掂器,你說我怎么就攤上這事亚皂。” “怎么了国瓮?”我有些...
    開封第一講書人閱讀 152,445評論 0 341
  • 文/不壞的土叔 我叫張陵灭必,是天一觀的道長。 經(jīng)常有香客問我乃摹,道長禁漓,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 55,185評論 1 278
  • 正文 為了忘掉前任孵睬,我火速辦了婚禮播歼,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘掰读。我一直安慰自己秘狞,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評論 5 371
  • 文/花漫 我一把揭開白布磷支。 她就那樣靜靜地躺著谒撼,像睡著了一般。 火紅的嫁衣襯著肌膚如雪雾狈。 梳的紋絲不亂的頭發(fā)上廓潜,一...
    開封第一講書人閱讀 48,970評論 1 284
  • 那天,我揣著相機(jī)與錄音善榛,去河邊找鬼辩蛋。 笑死,一個(gè)胖子當(dāng)著我的面吹牛移盆,可吹牛的內(nèi)容都是我干的悼院。 我是一名探鬼主播,決...
    沈念sama閱讀 38,276評論 3 399
  • 文/蒼蘭香墨 我猛地睜開眼咒循,長吁一口氣:“原來是場噩夢啊……” “哼据途!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起叙甸,我...
    開封第一講書人閱讀 36,927評論 0 259
  • 序言:老撾萬榮一對情侶失蹤颖医,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后裆蒸,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體熔萧,經(jīng)...
    沈念sama閱讀 43,400評論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了佛致。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片贮缕。...
    茶點(diǎn)故事閱讀 37,997評論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖俺榆,靈堂內(nèi)的尸體忽然破棺而出感昼,到底是詐尸還是另有隱情,我是刑警寧澤肋演,帶...
    沈念sama閱讀 33,646評論 4 322
  • 正文 年R本政府宣布抑诸,位于F島的核電站,受9級特大地震影響爹殊,放射性物質(zhì)發(fā)生泄漏蜕乡。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評論 3 307
  • 文/蒙蒙 一梗夸、第九天 我趴在偏房一處隱蔽的房頂上張望层玲。 院中可真熱鬧,春花似錦反症、人聲如沸辛块。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,204評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽润绵。三九已至,卻和暖如春胞谈,著一層夾襖步出監(jiān)牢的瞬間尘盼,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,423評論 1 260
  • 我被黑心中介騙來泰國打工烦绳, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留卿捎,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,423評論 2 352
  • 正文 我出身青樓径密,卻偏偏與公主長得像午阵,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子享扔,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評論 2 345

推薦閱讀更多精彩內(nèi)容