編輯:關於Android編程
仿微信相冊選擇圖片,查看大圖,寫的不太好,希望評論指出不足,諒解,先介紹一下我的基本思路
第一步獲取手機上的所有圖片路徑:
Uri uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI; ContentResolver contentResolver = getContentResolver(); //獲取jpeg和png格式的文件,並且按照時間進行倒序 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); }
我的存儲格式
/** 按時間排序的所有圖片list */ private ArrayListallImages; /** 按目錄排序的所有圖片list */ private ArrayList imageDirectories; /** * 一個文件夾中的圖片數據實體 */ private class SingleImageDirectories{ /** 父目錄的路徑 */ public String directoryPath; /** 目錄下的所有圖片實體 */ public ImageDirectoryModel images; }
一個是全部圖片的存儲順序,第二個是按照目錄的圖片存儲順序
第二步,獲取到圖片之後,放入到gridview中進行顯示,但是BitmapFactory.decodeFile()函數會非常耗時,所以為了使得非常流暢的顯示圖片,創建一個類AlbumBitmapCacheHelper.class,用來異步加載圖片,
該類使用LruCache
然後使用ThreadPoolExecutor線程池來處理圖片的顯示,線程池大小應該設置適中
做完這兩件事情之後就可以用來加載圖片了,方法getBitmap用來講
Bitmap bitmap = getBitmapFromCache(path, width, height); //如果能夠從緩存中獲取符合要求的圖片,則直接回調 if (bitmap != null) { } else { //新建線程放入線程池去處理該圖片的顯示 } return bitmap;
如果cache中找不到該圖片,則調用BitmapFactory.decodeFile()去加載圖片,加載圖片不能夠直接加載原圖,會造成OOM,所以要去處理壓縮比
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); //獲取之後,放入緩存,以便下次繼續使用 if (bitmap != null && cache!=null) { cache.put(path, bitmap); }
這樣在gridview中的getview方法中去調用AlbumBitmapCacheHelper.class的getBitmap方法即可, 但是這樣會有很多的問題:
一個問題就是圖片顯示會閃,這主要是由於getview的view的復用,解決方法就是使用settag方法 holder.iv_content.setTag(path); 將要顯示的Imageview的tag設置為需要顯示的圖片路徑,這樣在回調的時候使用方法gridView.findViewWithTag(path),找到這個imageview進行顯示,閃的問題就解決了
第二個問題就是加載速度很慢,拉的速度很快的情況下,圖片要很久才會加載出來,特別是很大的圖片,比如拍照和截圖的照片,
解決方法第一方案就是在AlbumBitmapCacheHelper類中維護一個ArrayListcurrentShowString,在getview方法中,如果該圖片要顯示,則直接將path加入到該list中,同時如果這個view的tag不為空,說明該view的原來的path是不需要顯示的,所以需要將這個path從list中刪除:
//優化顯示效果 if(holder.iv_content.getTag() != null) { String remove = (String) holder.iv_content.getTag(); AlbumBitmapCacheHelper.getInstance().removePathFromShowlist(remove); } AlbumBitmapCacheHelper.getInstance().addPathToShowlist(path);這樣在線程池中的處理方式就是先查看需要顯示的path是否在list中,如果沒有在list中,則該線程直接關閉,如果在list中,則顯示該圖片
if (!currentShowString.contains(path)||cache==null) { return; }
第二個方案就是如果顯示的圖片很大,特別是拍照,截圖和解圖的圖片,decode有時會耗時幾秒中,微信顯示效果非常好,我自己想出來的處理的方式就是
***第一步,從應用的緩存temp目錄下取,如果取不到, ***第二步,計算圖片的壓縮比例samplesize,如果samplesize < 4,圖片的BitmapFactory.decodeFile()時間短,直接返回圖片,但是如果 samplesize > 4,執行第三步 ***第三步則將壓縮後的圖片存入temp目錄下,以便下次快速取出這樣顯示圖片的效果就出來了,顯示的速度除了和微信一樣第一次大圖加載慢之外,之後的顯示就能很快了,
if (!new File(CommonUtil.getDataPath()).exists()) new File(CommonUtil.getDataPath()).mkdirs(); //臨時文件的文件名 String tempPath = CommonUtil.getDataPath() + hash + ".temp"; //如果該文件存在 if (new File(tempPath).exists()) bitmap = BitmapFactory.decodeFile(tempPath); ...... //第三步,如果縮放比例大於4,該圖的加載會非常慢,所以將該圖保存到臨時目錄下以便下次的快速加載 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(); } }
問題就差不多解決了
第三步大圖的查看,大圖只要是使用的網上找的ZoomImageView+viewpagger的組合,但是使用這個出現的問題就是很容易OOM,沒辦法,我的處理方式就是在點進去大圖的時候
public void releaseHalfSizeCache() { cache.resize((int) (Runtime.getRuntime().maxMemory() / 1024 / 8)); }
直接將cache的大小變成原來的一半,因為查看大圖頁,加載一張大圖占用的內存就很大,這樣顯示效果頁還湊合,有別的方法,一定要留言告訴我
注意:大圖的查看由於需要通過intent傳遞數據,但是intent傳遞的數據大小不能太大,如果手機上有幾千張圖片,則數據量大小可能會超過intent所能傳遞的最大量,所以可以寫入一個公共的地方,內存,數據庫,文件都可以,
//TODO 這裡由於涉及到intent傳遞的數據不能太大的問題,所以如果需要,這裡要進行另外的處理,寫入到內存或者寫入到文件中 intent.putExtra(PickBigImagesActivity.EXTRA_DATA, getAllImagesFromCurrentDirectory());
我暫時沒有處理~~
第四步就是圖片選擇完成之後,完成善後工作,將AlbumBitmapCacheHelper類中cache清空,差不多就這樣了,還有很多的小問題,比如圖片時間的顯示,具體大家看源碼
源碼下載點我
由於源碼是android studio的工程,所以不能直接導入eclipse,必須要手動拷貝文件,在這裡放出所有的文件,方便eclipse
命令模式(command pattern) 詳解本文地址: http://blog.csdn.net/caroline_wendy命令模式(command pattern
你登陸論壇的時候,我們先看看浏覽器干了什麼事兒: 用Firefox打開HiPda 的登陸頁面,輸入用戶名和密碼,點登陸。 下面是通過firebug插件獲取的數據: 可
從本篇博客開始,我們開始分析PKMS的構造函數,看看PKMS到底是如何解析和管理手機中APK的信息的。由於PKMS的構造函數較長,我們會分段進行研究。public Pac
在工作中,有一個這樣的需求,需要用到WebView與javascript進行交互,下面我們就通過一個簡單的需求來介紹.先看一下效果圖: 需求:1.點