안 드 로 이 드 는 위 챗 과 QQ 다 중 그림 을 합 친 프레임 워 크(그룹 이미지 유사)의 실현 방법 을 모방 합 니 다.

머리말
현재 대부분의 app 에 채 팅 을 넣 는 것 은 이미 매우 보편적 인 현상 이 고,위 챗 과 qq 는 통신 분야 의 원조 이다.제품 매니저 가 채 팅 디자인 을 고려 할 때 대부분 참고 한다.
자주 들 을 수 있 습 니 다.위 챗 과 qq 가 모두 이렇게 하 는 것 을 보 세 요.그렇게 하 세 요.마음 이 만 가지 불쾌 하지만 누가 우 리 를 추구 하 는 프로그래머 라 고 부 릅 니까?
그래서 제품 의 요 구 는 위 챗 과 유사 한 군 두상 을 실현 하 는 것 이다.
유사 하 다

프로그래머 로 서 우선 업 무량 을 평가 해 보 겠 습 니 다.제품 눈 에는 그림 을 합성 하 는 거 잖 아 요.뭐 가 어려워 요?그래서 근무 시간 에 어떻게 할 수 있 을 지 결 정 했 죠.
프로젝트 분석:
방안 1.레이아웃 으로 직접 작성 한 다음 에 서로 다른 레이아웃 에 따라 서로 다른 장의 그림 을 불 러 옵 니 다.모두 가 사용 하 는 그림 로드 방안 은 비동기 로 불 러 옵 니 다.그러면 불 러 올 때 반 짝 거 리 며 그림 으로 합 쳐 집 니 다.현재 그림 프레임 워 크 에 캐 시 가 있 기 때문에 두 번 째 는 많이 좋아 질 것 입 니 다.
장점:실현 이 빠르다
단점:low 입 니 다.프로그래머 를 강요 하 는 방법 이 아니 라 효과 도 좋 지 않 습 니 다.
프로젝트 2.컨트롤 을 사용자 정의 하거나 다른 방식 으로 모든 그림 을 다운로드 합 니 다.컨트롤 에 계수 기 를 추가 하여 모든 그림 다운로드 가 완 료 된 후에 함께 표시 하도록 합 니 다.
장점:난이도 적당
단점:확장 성 이 떨 어 지 는데 언제 제품 을 합성 방안 으로 바 꾸 고 싶 어 요?
프로젝트 3.네 이 티 브 컨트롤 을 사용 하여 그룹 이미 지 를 합 친 후에 새로운 이미 지 를 만 들 고 원래 의 캐 시 를 합 니 다.병합 알고리즘 을 인터페이스 로 추상 화하 다.
장점:확장 이 쉽 고 체험 이 좋다.
단점:시간 이 좀 더 걸린다
물론 꿈 이 있 는 프로그래머 로 서 우 리 는 실현 방안 3 을 고려 하고 제품 에 시 달 리 는 프로그램 원숭이 동 포 를 행복 하 게 해 야 한다.
다음은 주요 아이디어 와 핵심 코드 를 말씀 드 리 겠 습 니 다.
사고의 방향 을 실현 하 다.
사실 전체적인 사고방식 은 말하자면 비교적 간단 하기 때문에 한 폭 의 흐름 도로 요약 할 수 있다.

실현 방법
우선,프로그램의 입력 매개 변 수 는 ImageView 컨트롤,url 목록 이 어야 한 다 는 것 을 알 고 있 습 니 다.
ImageView 이미지 보 기 는 View 클래스 에서 직접 계승 합 니 다.주요 기능 은 그림 을 표시 하 는 데 사 용 됩 니 다.실제로 그림 을 표시 할 수 있 을 뿐만 아니 라 모든 Drawable 대상 은 ImageView 로 표시 할 수 있 습 니 다.ImageView 는 모든 레이아웃 에 적용 할 수 있 으 며,Android 는 크기 조정 과 착색 작업 을 제공 합 니 다.
물론 통합 반전 함수 도 있 습 니 다.통합 방법 을 사용자 정의 하 는 데 사 용 됩 니 다.

public void displayImages(
 final List<String> urls,
 final ImageView imageView, 
 final MergeCallBack mergeCallBack
)
사고방식 에 따라,우 리 는 urls 에 따라 새 키 를 생 성하 여 캐 시가 합 쳐 진 그림 에 사용 해 야 하 며,다음 에는 캐 시 에서 직접 불 러 올 수 있 습 니 다.통합 프로필 은 시간 이 걸 리 니까.

 public String getNewUrlByList(List<String> urls, String mark) {
 StringBuilder sb = new StringBuilder();
 for (String url : urls) {
  sb.append(url + mark);
 }
 return sb.toString();
 }
여 기 는 모든 url 을 간단하게 연결 한 다음 에 md5.
캐 시 처리 가 가장 중요 한 절차 입 니 다.단일 링크 그림 의 캐 시 와 병합 그림 의 캐 시 와 관련 됩 니 다.캐 시 시스템 에 있어 서 한 장의 그림 과 여러 장의 그림 은 똑 같이 취급 되 고 모두 key 가 하나의 캐 시 대상 에 대응 합 니 다.다만 키 의 규칙 은 조금 다르다.
캐 시 방안 도 일반적인 DiskLruCache 와 Memory LruCache 가 구현 하 는 2 급 캐 시 로 캐 시의 효율 성 을 유지 할 수 있 습 니 다.(LRu 알고리즘 에 대해 서 는 간단 한 Least Recently Used,즉 최근 사용 원칙,구체 적 으로 바 이 두 를 바 랍 니 다)입 니 다.
디 스 플레이 이미지 의 핵심 코드 를 살 펴 보 겠 습 니 다.메모리 캐 시 를 찾 은 다음 디스크 캐 시 를 찾 는 것 입 니 다.없 으 면 모든 그림 을 동기 화 하 는 것 입 니 다.

 public void displayImages(final List<String> urls, final ImageView imageView, final MergeCallBack mergeCallBack, final int dstWidth, final int dstHeight) {
 if (urls == null || urls.size() <= 0) {
  throw new IllegalArgumentException("url    ");
 }
 if (mergeCallBack == null) {
  throw new IllegalArgumentException("mergeCallBack     ");
 }
 final String url = getNewUrlByList(urls, mergeCallBack.getMark());
 imageView.setTag(IMG_URL, url);
 //     
 Bitmap bitmap = loadFromMemory(url);
 if (bitmap != null) {
  LogUtil.e(Tag, "displayImages this is from Memory");
  imageView.setImageBitmap(bitmap);
  return;
 }
 try {
  //     
  bitmap = loadFromDiskCache(url, dstWidth, dstHeight);
  if (bitmap != null) {
  LogUtil.e(Tag, "displayImages this is from Disk");
  imageView.setImageBitmap(bitmap);
  return;
  }
 } catch (Exception e) {
  e.printStackTrace();
 }
 //       
 bitmap = BitmapFactory.decodeResource(mContext.getResources(), R.drawable.ic_launcher_round);
 imageView.setImageBitmap(bitmap);
 LogUtil.e(Tag, "displayImages this is from default");
 //        ,         。      ,   。
 Runnable loadBitmapTask = new Runnable() {
  @Override
  public void run() {
  ArrayList<Bitmap> bitmaps = loadBitMaps(urls, dstWidth, dstHeight);
  if (bitmaps != null && bitmaps.size() > 0) {
   Result result;
   if (mergeCallBack != null) {
   Bitmap mergeBitmap = mergeCallBack.merge(bitmaps, mContext, imageView);
   if (urls.size() == bitmaps.size()) {
    //    
    try {
    saveDru(url, mergeBitmap);
    } catch (IOException e) {
    e.printStackTrace();
    }
   } else {
    LogUtil.e(Tag, "size change. so can not save");
   }
   LogUtil.e(Tag, "displayImages this is from Merge");
   result = new Result(mergeBitmap, url, imageView);
   } else {
   result = new Result(bitmaps.get(0), url, imageView);
   }
   Message msg = mMainHandler.obtainMessage(MESSAGE_SEND_RESULT, result);
   msg.sendToTarget();
  }
  }
 };
 threadPoolExecutor.execute(loadBitmapTask);
 }
캐 시 에서 불 러 오 는 데 실패 하면 스 레 드 를 열 어 이미지 통합 작업 을 수행 합 니 다.그 이미지 통합 은 동기 화 작업 입 니 다.이미지 통합 이 필요 한 대상 을 얻어 야 합 니 다.어떻게 얻 을 수 있 습 니까?우 리 는 코드 를 계속 봅 니 다.

 private ArrayList<Bitmap> loadBitMaps(List<String> urls, int dstWidth, int dstHeight) {
 ArrayList<Bitmap> bitmaps = new ArrayList<>();
 for (String url : urls) {
  //        
  Bitmap bitmap = loadBitMap(url, dstWidth, dstHeight);
  if (bitmap != null) {
  bitmaps.add(bitmap);
  }
 }
 return bitmaps;
 }
그림 은 loadBitMap()함 수 를 통 해 되 돌아 오 는 것 이 고 이 함수 의 핵심 방법 은?

 private Bitmap loadBitMap(String url, int dstWidth, int dstHeight) {
 //  
 Bitmap bitmap = loadFromMemory(url);
 if (bitmap != null) {
  LogUtil.e(Tag, "this is from Memory");
  return bitmap;
 }
 try {
  //  
  bitmap = loadFromDiskCache(url, dstWidth, dstHeight);
  if (bitmap != null) {
  LogUtil.e(Tag, "this is from Disk");
  return bitmap;
  }
  //  
  bitmap = loadFromNet(url, dstWidth, dstHeight);
  LogUtil.e(Tag, "this is from Net");
  if (bitmap == null) {
  LogUtil.e(Tag, "bitmap null network error");
  }
 } catch (Exception e) {
  e.printStackTrace();
 }
 return bitmap;
 }
디 스 플레이 이미지()방법의 논리 에 똑 같은 캐 시 방향 을 사용 한 것 을 똑똑히 볼 수 있 습 니 다.우 리 는 다시 loadBitmapTask 라 는 스 레 드 의 실행 방법 으로 돌아 갑 니 다.그 중에서 중요 한 논 리 는?

Bitmap mergeBitmap = mergeCallBack.merge(bitmaps, mContext, imageView);
if (urls.size() == bitmaps.size()) {
 //    
 try {
  saveDru(url, mergeBitmap);
 } catch (IOException e) {
  e.printStackTrace();
 }
} 
이 mergeCallBack 방법 은 사용자 가 스스로 실현 해 야 할 이미지 통합 방법 입 니 다.목록 의 bitmap 에 들 어간 다음 병합 그림 대상 을 되 돌려 줍 니 다.마지막 으로 이 통합 을 캐 시 에 추가 합 니 다.다음 부 터 는 캐 시 에서 바로 찾 을 수 있 습 니 다.
다음 의 중점 은 이미지 통합 기술 이다.저 는 코드 에 위 챗 과 qq 를 실현 하 는 그룹 프로필 사진 을 넣 었 습 니 다.다음은 위 챗 합병 방안,QQ 의 합병 방안 을 간단하게 말씀 드 리 겠 습 니 다.여러분 은 스스로 코드 를 보 러 갈 수 있 습 니 다.
우선 MergeCallBack 의 실현 방법 을 살 펴 보 겠 습 니 다.

@Override
public Bitmap merge(List<Bitmap> bitmapArray, Context context, ImageView imageView) {
 this.context = context;
 //     
 ViewGroup.LayoutParams lp = imageView.getLayoutParams();
 int tempWidth;
 int tempHeight;
 if (lp != null) {
 tempWidth = dip2px(context, lp.width);
 tempHeight = dip2px(context, lp.height);
 } else {
 //          
 tempWidth = dip2px(context, 70);
 tempHeight = dip2px(context, 70);
 }
 return CombineBitmapTools.combimeBitmap(context, tempWidth, tempHeight,
  bitmapArray);
}
combineBitmap 의 실현 을 살 펴 보 겠 습 니 다.

 public static Bitmap combimeBitmap(Context context, int combineWidth,
     int combineHeight, List<Bitmap> bitmaps) {
 if (bitmaps == null || bitmaps.size() == 0)
  return null;

 if (bitmaps.size() >= 9) {
  bitmaps = bitmaps.subList(0, 9);
 }
 Bitmap resultBitmap = null;
 int len = bitmaps.size();
 //     ,           。
 List<CombineBitmapEntity> combineBitmapEntities = CombineNineRect
  .generateCombineBitmapEntity(combineWidth, combineHeight, len);
 //    
 List<Bitmap> thumbnailBitmaps = new ArrayList<Bitmap>();
 for (int i = 0; i < len; i++) {
  thumbnailBitmaps.add(ThumbnailUtils.extractThumbnail(bitmaps.get(i),
   (int) combineBitmapEntities.get(i).width,
   (int) combineBitmapEntities.get(i).height));
 }
 //   
 resultBitmap = getCombineBitmaps(combineBitmapEntities,
  thumbnailBitmaps, combineWidth, combineHeight);

 return resultBitmap;
 }
 private static Bitmap getCombineBitmaps(
  List<CombineBitmapEntity> mEntityList, List<Bitmap> bitmaps,
  int width, int height) {
 Bitmap newBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
 for (int i = 0; i < mEntityList.size(); i++) {
  //    
  newBitmap = mixtureBitmap(newBitmap, bitmaps.get(i), new PointF(
   mEntityList.get(i).x, mEntityList.get(i).y));
 }
 return newBitmap;
 }
마지막 으로 getCombineBitmaps 를 호출 하여 이미 지 를 합성 하 는 관건 은 Bitmap.createBitmap 를 통 해 이 루어 지 는 것 입 니 다.

 private static Bitmap mixtureBitmap(Bitmap first, Bitmap second,
     PointF fromPoint) {
 if (first == null || second == null || fromPoint == null) {
  return null;
 }
 Bitmap newBitmap = Bitmap.createBitmap(first.getWidth(),
  first.getHeight(), Bitmap.Config.ARGB_8888);
 Canvas cv = new Canvas(newBitmap);
 cv.drawBitmap(first, 0, 0, null);
 cv.drawBitmap(second, fromPoint.x, fromPoint.y, null);
 cv.save(Canvas.ALL_SAVE_FLAG);
 cv.restore();
 if (first != null) {
  first.recycle();
  first = null;
 }
 if (second != null) {
  second.recycle();
  second = null;
 }
 return newBitmap;
 }
모든 관건 적 인 논 리 는 코드 에 이미 비고 되 어 있다.
전체 효과 와 전체 코드 를 보고 싶다 면 여 기 를 클릭 하 십시오.MutiImgLoader물론로 컬 다운로드을 통 해서 도 됩 니 다.
총결산
이상 은 이 글 의 전체 내용 입 니 다.본 논문 의 내용 이 여러분 의 학습 이나 업무 에 어느 정도 참고 학습 가치 가 있 기 를 바 랍 니 다.궁금 한 점 이 있 으 시 면 댓 글 을 남 겨 주 셔 서 저희 에 대한 지지 에 감 사 드 립 니 다.

좋은 웹페이지 즐겨찾기