Android 는 로 컬 앨범 사진 을 많이 불 러 오 는 것 을 최적화 합 니 다.

9209 단어 Android로드그림.
개술
최적화 조회 앨범 사진 을 설명 하기 전에 우 리 는 먼저 PM 이 제기 한 수 요 를 살 펴 보 자.PM 의 수 요 는 매우 간단 하 다.바로 위 챗 과 유사 한 로 컬 앨범 사진 조회 컨트롤 을 하 는 것 이다.주로 두 부분 을 포함한다.
4.567917.사진 선택 페이지 에 들 어가 면 핸드폰 에 있 는 모든 사진 을 표시 해 야 한다.시스템 앨범 사진 과 다른 디 렉 터 리 에 있 는 모든 사진 을 포함 하고 시간 에 따라 거꾸로 배열 해 야 한다4.567917.앨범 기능 을 전환 하고 앨범 페이지 를 전환 하여 핸드폰 에 있 는 모든 그림 디 렉 터 리 목록 을 표시 하 며 각 디 렉 터 리 에 있 는 모든 그림 갯 수 와 표지 그림 을 표시 합 니 다이 두 가지 수 요 는 간단 해 보이 지만 사실은 일련의 성능 최적화 문 제 를 숨 기 고 있다.최적화 하기 전에 우 리 는 다른 유명한 app 이 대량의 그림 을 불 러 오 는 성능 표현(gif 녹화 가 뚜렷 하지 않 지만 전시 문 제 는 충분 하 다)을 조사 연 구 했 습 니 다.
다음은 몇 가지 상용 소프트웨어 를 테스트 하 였 다.
위 챗:
위 챗 의 이미지 조회 속 도 는 매우 빠르다.기본적으로 이미지 선택 페이지 에 들 어가 면 앨범 데 이 터 는 이미 찾 아 냈 다.각 이미지 디 렉 터 리 아래 그림 의 개수 와 표지 그림 의 url 을 포함 하여 이 체험 은 비교적 좋다.
시 나 웨 이 보:
위 챗 과 비교 해 보면 시 나 웨 이 보가 하 는 체험 은 비교적 좋 지 않다.사진 선택 페이지 에 들 어간 후에 먼저 검은색 화면 이 고 그 다음 에 흰색 화면 이다.진도 가 하나 도 없어 서 사용 자 는 app 이 죽 었 다 고 생각 하고 시간 이 지나 서 야 나타 나 는데 이 체험 은 비교적 나쁘다.
QQ:
QQ 가 올 라 오 자마자 최근 100 장의 사진 을 불 러 왔 습 니 다.이 속 도 는 매우 빠 릅 니 다.하지만 Camera 앨범(5000 여 장)에 들 어간 후에 진도 표 가 기다 리 고 있 습 니 다.저 는 체험 해 보 았 습 니 다.기다 리 는 시간 이 비교적 길 었 습 니 다.이 체험 은 시 나 웨 이 보 보다 조금 좋 고 위 챗 보다 못 합 니 다.
한어:
한 어 는 가장 못 만 든 것 이다.올 라 오 면 4,5 초 걸 리 고 그 다음 에 검 은 화면 이 2,3 초 걸 려 서 야 나 타 났 다.
2.종합 대비
종합 적 인 대 비 를 거 친 후에 위 챗 은 잘 만 들 었 습 니 다.기본적으로 앨범 페이지 에 들 어가 면 모든 사진 을 보 여줄 수 있 고 앨범 목록 도 매우 빨리 보 여 줍 니 다!!!
우리 의 조사 연 구 를 통 해 위 챗 은 순환 페이지 로 딩 전략 을 사용 하 는 것 을 발견 했다.우리 의 최적화 사고 도 이런 전략 을 사용 하고 최적화 후의 효과 도 를 먼저 본다.

그림 선택 페이지 에 들 어가 면 그림 이 매우 빨리 표 시 됩 니 다.앨범 교체 페이지 에 들 어가 면 그림 디 렉 터 리 도 매우 빨리 표 시 됩 니 다.여 기 는 위 챗 처럼 그림 디 렉 터 리 를 만 드 는 캐 시 가 없습니다.하 나 는 조회 속도 가 매우 빠 르 기 때문에 기본적으로 2 초 도 안 되 어 추가 되 었 습 니 다.다른 하 나 는 실시 간 으로 앨범 의 최신 데 이 터 를 새로 고 칠 수 있 습 니 다.
각 앨범 목록 을 자주 전환 하면 사진 이 매우 빠르게 조회 되 고 체험 도 좋 습 니 다!!
3.최적화 실현
앨범 디 렉 터 리 최적화 조회
모든 앨범 디 렉 터 리 목록 을 열거 해 야 하기 때문에 여 기 는 다른 좋 은 방법 이 없습니다.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 여 장의 그림 을 모두 검사 하려 면 총 시간 이 3,4 초 증가 할 것 이다.이 판단 은 밖으로 내 보 내 고 어떤 그림 을 구체 적 으로 조작 할 때 구체 적 인 업무 판단 을 할 수 있 습 니 다!
그림 폴 더 가 여러 번 검색 되 는 것 을 방지 합 니 다.
스 캔 한 그림 디 렉 터 리 를 저장 하기 위해 변 수 를 추가 하 였 습 니 다.스 캔 한 것 은 처리 되 지 않 습 니 다.

//      ,          
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 파일 last Modified 방법 을 사 용 했 습 니 다.

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 장 을 모두 신속하게 조회 할 수 있 는데 마치 위 챗 과 갤러리 와 같다.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기