Android最佳化查詢載入大數量的本地相簿圖片_Android

來源:互聯網
上載者:User

一、概述

講解最佳化查詢相簿圖片之前,我們先來看下PM提出的需求,PM的需求很簡單,就是要做一個類似微信的本地相簿圖片查詢控制項,主要包含兩個兩部分:

  • 進入圖片選擇頁面就要顯示出手機中所有的照片,包括系統相簿圖片和其他目錄下的所有圖片,並按照時間倒敘排列
  • 切換相簿功能,切換相簿頁面列出手機中所有的圖片目錄列表,並且顯示出每個目錄下所有的圖片個數以及封面圖片

這兩個需求看似簡單,實則隱藏著一系列的效能最佳化問題。在做最佳化之前,我們調研了一些其他比較出名的app在載入大數量圖片的效能表現(gif錄製的不夠清晰,但展示問題已經夠了):

下面測試了幾個常用軟體

微信:
微信的圖片查詢速度還是非常快的,基本上進入圖片選擇頁面,相簿資料就已經查出來了,包括各個圖片目錄下圖片的個數和封面圖片的url,這個體驗還是比較好的。

新浪微博:
相比較微信來說,新浪微博做的體驗就比較差了,進入圖片選擇頁面後,先是黑屏然後是白屏,連個進度條都沒有,讓使用者以為app死掉了,等過一段時間才顯示出來,這個體驗較差

QQ:
QQ一上來是載入的最近100張照片,這個速度非常快,但是進入Camera相簿(有5000多張)後,有一個進度條等待,我體驗了下,等待的時間還是比較長的,這個體驗比新浪微博稍微好點,比微信差

閑魚:
閑魚是做的最爛的一個,一上來是卡死四五秒,然後是黑屏兩三秒,最後才顯示出來

二、綜合對比

經過綜合對比後,就微信做的還比較好,基本上進入相簿頁面就能展示出所有照片,相簿目錄也非常快的展示出來!!!

經過我們的調研,發現微信是採用迴圈分頁載入策略,我們最佳化的思路也是採用這種策略,先看最佳化後的效果圖:

進入圖片選擇頁面,圖片能夠非常快的顯示出來,進入更換相簿頁面,圖片目錄也能非常快的顯示出來,這裡沒有像微信一樣做圖片目錄的緩衝:一是因為查詢速度非常快,基本上不到2秒就載入出來了,二是能夠即時重新整理出相簿的最新資料

頻繁的切換各個相簿目錄,圖片都能非常快速的查詢出來,體驗還是不錯的!!!

三、最佳化實現

最佳化查詢相簿目錄

因為要列舉出所有的相簿目錄列表,這裡沒有其他好的辦法,直接請求ContentResolver的query方法來查詢,這裡為了加速查詢,去掉了while迴圈中一些耗時的判斷,將一些檢測圖片是否判斷的邏輯移到外面去,具體用的時候再去判斷

查詢圖片的URI

MediaStore.Images.Media.EXTERNAL_CONTENT_URI

因為我們只查詢圖片url和圖片所在的目錄

String[] projection = {MediaStore.Images.ImageColumns.DATA, MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME};

PM要求相簿按照圖片的時間倒敘排列,圖片的建立、修改會影響其所在目錄的排序,排序按時間倒敘排列

String sortOrder = MediaStore.Images.Media.DATE_TAKEN + " DESC ";

根據這些查詢條件,經過query之後得到一個Cursor,這個cursor裡面就包含我們所需要的所有圖片的資訊,然後我們while迴圈遍曆這個cursor,在while迴圈中一定不能有耗時操作

//一個輔助集合,防止同一目錄被掃描多次HashSet<String> dirPaths = new HashSet<String>();while (cursor.moveToNext()) {  // 擷取圖片的路徑  String path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.ImageColumns.DATA));  String bucketName = cursor.getString(cursor.getColumnIndex(MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME));  if (TextUtils.isEmpty(allFolderItem.coverImagePath)) {    allFolderItem.coverImagePath = path;  }  File parentFile = new File(path).getParentFile();  if (parentFile == null) continue;  String dirPath = parentFile.getAbsolutePath();  PicFolderItem folderItem = null;  // 利用一個HashSet防止多次掃描同一個檔案夾(不加這個判斷,圖片多起來還是相當恐怖的~~)  if (dirPaths.contains(dirPath)) {    continue;  } else {    dirPaths.add(dirPath);    boolean isNew = true;    //判斷一下是否dirPath不同,但是bucketName相同    for (PicFolderItem item : picList) {      if (item.name.equals(bucketName)) {        folderItem = item;        item.addParentPath(dirPath);        isNew = false;        break;      }    }    if (isNew) {      folderItem = new PicFolderItem();      folderItem.coverImagePath = path;      folderItem.name = bucketName;      folderItem.addParentPath(dirPath);    }  }  String[] array = parentFile.list(new FilenameFilter() {    @Override    public boolean accept(File dir, String filename) {      if (filename.endsWith(".jpg")          || filename.endsWith(".png")          || filename.endsWith(".jpeg"))        return true;      return false;    }  });  int arrayCount = array == null ? 0 : array.length;  folderItem.count += arrayCount;  if (!picList.contains(folderItem) && arrayCount > 0) {    picList.add(folderItem);  }}

這樣就能非常快速的查詢出手機中所有的圖片目錄、目錄的圖片張數以及封面圖url。這裡主要最佳化了三點:

while迴圈中去除耗時判斷

之前的代碼中存在判斷檔案圖片是否存在的代碼:

 public static boolean isFileExist(String path) {  File file = new File(path);  if (file == null || !file.exists()) {    return false;  }  return true;  }

這段代碼放到while迴圈中是很恐怖的,我測試了下,5000多張圖片都要檢測的話總時間會增加三四秒。這個判斷可以放到外面去,具體操作哪一個圖片的時候再做具體的業務判斷!

防止一個圖片檔案夾被掃描多次

這裡添加了一個變數來儲存已經掃描過的圖片目錄,已經掃描的就不在處理了:

//一個輔助集合,防止統一目錄查詢多次HashSet<String> dirPaths = new HashSet<String>();

這塊最佳化了之後效果還是很明顯的,相同的目錄不會掃描多次!

擷取圖片目錄下圖片個數

String[] array = parentFile.list(new FilenameFilter() {            @Override            public boolean accept(File dir, String filename) {              if (filename.endsWith(".jpg")                  || filename.endsWith(".png")                  || filename.endsWith(".jpeg"))                return true;              return false;            }          });

這個file.list()方法內部是一個native方法,查詢效率非常快!!!

當然擷取某個目錄下的圖片有多少張也可以通過cursor查詢的方式來擷取!!!

查詢某個相簿目錄下的所有照片

在介紹查詢目錄下的照片之前,我們先介紹下我們查詢圖片的兩種策略,一種是針對目錄下圖片比較多的,動不動就上千上萬張的那種;另一種是那種目錄下圖片比較少的,就幾百張圖片

一次載入策略

當目錄下圖片數量小於1000張時採用file.list這個native方法來一次載入所有圖片,這個native查詢效率非常快,上千張圖片都是秒級查詢出來

迴圈分頁載入策略

當圖片數量大於等於1000張時採用迴圈分頁載入策略,這種策略專門針對圖片數量特別多的情況,通過分頁的方式先把第一頁的圖片載入出來,讓使用者能第一眼看到最新的圖片,然後後台非同步迴圈的查詢下一頁圖片,直到所有圖片都查詢完成,這也是微信的查詢相簿策略。

一次載入策略實現

我們這裡看下一次載入完策略實現代碼,首先通過File的list方法將尾碼為圖片格式的檔案過濾出來,返回一個圖片路徑數組

File dirFile = new File(dir);String[] list = dirFile.list(new FilenameFilter() {  @Override  public boolean accept(File dir, String filename) {    if (filename.endsWith(".jpg") || filename.endsWith(".png")        || filename.endsWith(".jpeg"))      return true;    return false;  }});

因為我們要的是按時間倒敘進行排列的數組,所以要對上面查詢出來的數組進行排序,這裡用到了File檔案lastModified方法

Collections.sort(strings, new Comparator<String>() {        @Override        public int compare(String lhs, String rhs) {          Long time1 = new File(lhs).lastModified();          Long time2 = new File(rhs).lastModified();          return time2.compareTo(time1);        }        });

迴圈分頁載入策略實現

這個策略借鑒了微信,通過分頁的方式來一頁一頁的載入圖片,直到所有的圖片都載入完成。

這裡的核心就是查詢條件,將你要查詢的某個目錄添加到查詢參數中

String selection = MediaStore.Images.ImageColumns.BUCKET_DISPLAY_NAME + " = '" + 目錄名稱 + "' ";

這個selection一定不能寫錯,不然查詢不出來

因為要分頁,sortOrder不是簡單的按照時間倒敘來排了

String sortOrder = MediaStore.Images.Media.DATE_TAKEN + " DESC limit " + PAGE_SIZE + " offset " + pageIndex * PAGE_SIZE;

最後對Cursor進行迴圈遍曆拿到我們要的圖片路徑

PAGE_SIZE是個常量,表示我們要一次查詢多少條,我們這裡定的是200,一次查詢200條資料,pageIndex是查詢第幾頁,從0開始

一開始的時候查詢第一頁的資料,當查詢的資料列表大小大於等於我們要查詢的PageSize大小時,我們就認為有下一頁,pageIndex加1迴圈查詢下一頁,直到查詢的列表大小小於PageSize。

經過上面幾步最佳化後,載入本地相簿圖片基本上就沒有什麼問題了。我們經過真機測試,圖片5549張,都能夠非常快速的查詢出來,堪比微信和圖庫。

以上就是本文的全部內容,希望對大家的學習有所協助,也希望大家多多支援雲棲社區。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.