안 드 로 이 드 포 토 월 애플 리 케 이 션 이 아무리 많은 사진 을 실현 해도 붕 괴 를 두려워 하지 않 는 다.

15054 단어 Android사진 벽
포 토 월 이라는 기능 은 이제 흔 한 것 으로 보인다.많은 애플 리 케 이 션 에서 포 토 월 의 모습 을 자주 볼 수 있다.그의 디자인 방향 도 매우 간단 하 다.GridView 컨트롤 을'벽'으로 한 다음 에 GridView 가 구 르 면서 사진 한 장 을'벽'에 붙 였 다.이 사진 들 은 핸드폰 로 컬 에 저장 할 수도 있 고 인터넷 에서 다운로드 할 수도 있다.이런 기능 과 유사 한 응용 을 만 드 는 데 매우 중요 한 문 제 는 바로 이미지 자원 이 언제 방출 되 어야 하 는 지 를 고려 해 야 한다.GridView 가 구 르 면서 불 러 오 는 그림 이 점점 많아 질 수 있 기 때문에 합 리 적 인 메커니즘 이 그림 을 방출 하지 않 으 면 그림 이 일정한 상한 선 에 이 르 면 프로그램 이 무 너 질 수 밖 에 없다.
오늘 우리 사진 벽 애플 리 케 이 션 의 실현 은 사진 이 너무 많아 프로그램 이 무 너 지 는 것 을 어떻게 방지 하 느 냐 에 중점 을 두 었 다.주요 핵심 알고리즘 은 Android 에서 제공 하 는 LRuCache 클래스 를 사 용 했 습 니 다.이 클래스 는 3.1 버 전에 서 제공 되 며,더 빠 른 Android 버 전에 서 개발 되 었 다 면 android-support-v4 의 jar 패 키 지 를 가 져 와 야 합 니 다.
루 캐 시 용법 에 대한 자세 한 설명 은 참고Android 고 효율 로드 큰 그림,다 중 그림 방안,프로그램 OOM 을 효과적으로 피 할 수 있 습 니 다.할 수 있다.
그럼 시작 합 시다.안 드 로 이 드 프로젝트 를 새로 만 듭 니 다.PhotoWallDemo 라 고 이름 을 지 었 습 니 다.여 기 는 안 드 로 이 드 4.0 API 를 사용 합 니 다.
첫 번 째 로 고려 해 야 할 문 제 는 우리 가 어디에서 이렇게 많은 그림 을 수집 하 느 냐 는 것 이다.여기 서 저 는 구 글 이 공식 적 으로 제공 한 데모 에서 사진 소스 를 꺼 냈 습 니 다.우 리 는 이 사이트 에서 사진 을 다운로드 하고 코드 는 다음 과 같 습 니 다.

public class Images { 
 
  public final static String[] imageThumbUrls = new String[] {  
       "https://lh4.googleusercontent.com/-vngKD5Z1U8w/URqvJUCEgPI/AAAAAAAAAbs/ulxCMVcU6EU/s160-c/Valley%252520Sunset.jpg", 
      "https://lh6.googleusercontent.com/-DOz5I2E2oMQ/URqvKMND1kI/AAAAAAAAAbs/Iqf0IsInleo/s160-c/Windmill%252520Sunrise.jpg", 
      "https://lh5.googleusercontent.com/-biyiyWcJ9MU/URqvKculiAI/AAAAAAAAAbs/jyPsCplJOpE/s160-c/Windmill.jpg", 
      "https://lh4.googleusercontent.com/-PDT167_xRdA/URqvK36mLcI/AAAAAAAAAbs/oi2ik9QseMI/s160-c/Windmills.jpg", 
      "https://lh5.googleusercontent.com/-kI_QdYx7VlU/URqvLXCB6gI/AAAAAAAAAbs/N31vlZ6u89o/s160-c/Yet%252520Another%252520Rockaway%252520Sunset.jpg", 
      "https://lh4.googleusercontent.com/-e9NHZ5k5MSs/URqvMIBZjtI/AAAAAAAAAbs/1fV810rDNfQ/s160-c/Yosemite%252520Tree.jpg", }; 
} 
그림 의 원본 이 이미 있 으 니,지금 우 리 는 이 그림 들 을 어디 에 놓 을 지 고려 해 야 한다.액 티 비 티 새로 만 들 거나 열기main.xml 는 프로그램의 주 레이아웃 으로 다음 코드 를 추가 합 니 다.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  xmlns:tools="http://schemas.android.com/tools" 
  android:layout_width="wrap_content" 
  android:layout_height="wrap_content" > 
   
  <GridView  
    android:id="@+id/photo_wall" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    android:columnWidth="90dip" 
    android:stretchMode="columnWidth" 
    android:numColumns="auto_fit" 
    android:verticalSpacing="10dip" 
    android:gravity="center" 
    ></GridView> 
   
</LinearLayout> 
이 레이아웃 파일 에 GridView 만 추가 되 었 습 니 다.이것 이 바로 우리 프로그램의'벽'입 니 다.모든 그림 이 이'벽'에 붙 어 있 습 니 다.
이어서 우 리 는 GridView 의 모든 하위 View 의 레이아웃 을 정의 하고 photo 를 새로 만 듭 니 다.layot.xml 레이아웃,다음 코드 추가:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  xmlns:tools="http://schemas.android.com/tools" 
  android:layout_width="wrap_content" 
  android:layout_height="wrap_content" > 
 
  <ImageView  
    android:id="@+id/photo" 
    android:layout_width="90dip" 
    android:layout_height="90dip" 
    android:src="@drawable/empty_photo" 
    android:layout_centerInParent="true" 
    /> 
 
</RelativeLayout> 
모든 키 View 에서 우 리 는 이미지 뷰 를 간단하게 사용 하여 그림 을 표시 합 니 다.이렇게 하면 모든 레이아웃 이 이미 정의 되 었 다.
다음 에 새로 만 든 PhotoWallAdapter 는 GridView 의 어댑터 로 코드 는 다음 과 같 습 니 다.

public class PhotoWallAdapter extends ArrayAdapter<String> implements OnScrollListener { 
 
  /** 
   *                 。 
   */ 
  private Set<BitmapWorkerTask> taskCollection; 
 
  /** 
   *           ,            ,                         。 
   */ 
  private LruCache<String, Bitmap> mMemoryCache; 
 
  /** 
   * GridView    
   */ 
  private GridView mPhotoWall; 
 
  /** 
   *            
   */ 
  private int mFirstVisibleItem; 
 
  /** 
   *            
   */ 
  private int mVisibleItemCount; 
 
  /** 
   *          ,             ,         。 
   */ 
  private boolean isFirstEnter = true; 
 
  public PhotoWallAdapter(Context context, int textViewResourceId, String[] objects, 
      GridView photoWall) { 
    super(context, textViewResourceId, objects); 
    mPhotoWall = photoWall; 
    taskCollection = new HashSet<BitmapWorkerTask>(); 
    //              
    int maxMemory = (int) Runtime.getRuntime().maxMemory(); 
    int cacheSize = maxMemory / 8; 
    //                   1/8 
    mMemoryCache = new LruCache<String, Bitmap>(cacheSize) { 
      @Override 
      protected int sizeOf(String key, Bitmap bitmap) { 
        return bitmap.getByteCount(); 
      } 
    }; 
    mPhotoWall.setOnScrollListener(this); 
  } 
 
  @Override 
  public View getView(int position, View convertView, ViewGroup parent) { 
    final String url = getItem(position); 
    View view; 
    if (convertView == null) { 
      view = LayoutInflater.from(getContext()).inflate(R.layout.photo_layout, null); 
    } else { 
      view = convertView; 
    } 
    final ImageView photo = (ImageView) view.findViewById(R.id.photo); 
    //  ImageView    Tag,              
    photo.setTag(url); 
    setImageView(url, photo); 
    return view; 
  } 
 
  /** 
   *  ImageView    。   LruCache        ,   ImageView 。  LruCache         , 
   *   ImageView        。 
   * 
   * @param imageUrl 
   *         URL  ,    LruCache  。 
   * @param imageView 
   *               。 
   */ 
  private void setImageView(String imageUrl, ImageView imageView) { 
    Bitmap bitmap = getBitmapFromMemoryCache(imageUrl); 
    if (bitmap != null) { 
      imageView.setImageBitmap(bitmap); 
    } else { 
      imageView.setImageResource(R.drawable.empty_photo); 
    } 
  } 
 
  /** 
   *         LruCache 。 
   * 
   * @param key 
   *      LruCache  ,       URL  。 
   * @param bitmap 
   *      LruCache  ,           Bitmap  。 
   */ 
  public void addBitmapToMemoryCache(String key, Bitmap bitmap) { 
    if (getBitmapFromMemoryCache(key) == null) { 
      mMemoryCache.put(key, bitmap); 
    } 
  } 
 
  /** 
   *  LruCache       ,        null。 
   * 
   * @param key 
   *      LruCache  ,       URL  。 
   * @return       Bitmap  ,  null。 
   */ 
  public Bitmap getBitmapFromMemoryCache(String key) { 
    return mMemoryCache.get(key); 
  } 
 
  @Override 
  public void onScrollStateChanged(AbsListView view, int scrollState) { 
    //   GridView         ,GridView               
    if (scrollState == SCROLL_STATE_IDLE) { 
      loadBitmaps(mFirstVisibleItem, mVisibleItemCount); 
    } else { 
      cancelAllTasks(); 
    } 
  } 
 
  @Override 
  public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, 
      int totalItemCount) { 
    mFirstVisibleItem = firstVisibleItem; 
    mVisibleItemCount = visibleItemCount; 
    //         onScrollStateChanged   ,        onScrollStateChanged     , 
    //                   。 
    if (isFirstEnter && visibleItemCount > 0) { 
      loadBitmaps(firstVisibleItem, visibleItemCount); 
      isFirstEnter = false; 
    } 
  } 
 
  /** 
   *   Bitmap  。     LruCache           ImageView Bitmap  , 
   *         ImageView Bitmap       ,             。 
   * 
   * @param firstVisibleItem 
   *            ImageView    
   * @param visibleItemCount 
   *                  
   */ 
  private void loadBitmaps(int firstVisibleItem, int visibleItemCount) { 
    try { 
      for (int i = firstVisibleItem; i < firstVisibleItem + visibleItemCount; i++) { 
        String imageUrl = Images.imageThumbUrls[i]; 
        Bitmap bitmap = getBitmapFromMemoryCache(imageUrl); 
        if (bitmap == null) { 
          BitmapWorkerTask task = new BitmapWorkerTask(); 
          taskCollection.add(task); 
          task.execute(imageUrl); 
        } else { 
          ImageView imageView = (ImageView) mPhotoWall.findViewWithTag(imageUrl); 
          if (imageView != null && bitmap != null) { 
            imageView.setImageBitmap(bitmap); 
          } 
        } 
      } 
    } catch (Exception e) { 
      e.printStackTrace(); 
    } 
  } 
 
  /** 
   *                 。 
   */ 
  public void cancelAllTasks() { 
    if (taskCollection != null) { 
      for (BitmapWorkerTask task : taskCollection) { 
        task.cancel(false); 
      } 
    } 
  } 
 
  /** 
   *          。 
   * 
   * @author guolin 
   */ 
  class BitmapWorkerTask extends AsyncTask<String, Void, Bitmap> { 
 
    /** 
     *    URL   
     */ 
    private String imageUrl; 
 
    @Override 
    protected Bitmap doInBackground(String... params) { 
      imageUrl = params[0]; 
      //           
      Bitmap bitmap = downloadBitmap(params[0]); 
      if (bitmap != null) { 
        //           LrcCache  
        addBitmapToMemoryCache(params[0], bitmap); 
      } 
      return bitmap; 
    } 
 
    @Override 
    protected void onPostExecute(Bitmap bitmap) { 
      super.onPostExecute(bitmap); 
      //   Tag     ImageView  ,           。 
      ImageView imageView = (ImageView) mPhotoWall.findViewWithTag(imageUrl); 
      if (imageView != null && bitmap != null) { 
        imageView.setImageBitmap(bitmap); 
      } 
      taskCollection.remove(this); 
    } 
 
    /** 
     *   HTTP  ,   Bitmap  。 
     * 
     * @param imageUrl 
     *         URL   
     * @return     Bitmap   
     */ 
    private Bitmap downloadBitmap(String imageUrl) { 
      Bitmap bitmap = null; 
      HttpURLConnection con = null; 
      try { 
        URL url = new URL(imageUrl); 
        con = (HttpURLConnection) url.openConnection(); 
        con.setConnectTimeout(5 * 1000); 
        con.setReadTimeout(10 * 1000); 
        bitmap = BitmapFactory.decodeStream(con.getInputStream()); 
      } catch (Exception e) { 
        e.printStackTrace(); 
      } finally { 
        if (con != null) { 
          con.disconnect(); 
        } 
      } 
      return bitmap; 
    } 
 
  } 
 
} 
PhotoWallAdapter 는 전체 사진 벽 프로그램 에서 가장 중요 한 유형 입 니 다.여기 서 제 가 중점적으로 설명해 드 리 겠 습 니 다.먼저 PhotoWallAdapter 의 구조 함수 에서 우 리 는 LruCache 류 를 초기 화 했 고 최대 캐 시 용량 을 프로그램 최대 사용 가능 한 메모리 의 1/8 로 설정 했다.그 다음 에 GridView 에 스크롤 모니터 를 등록 했다.그 다음 에 getView()방법 에서 우 리 는 모든 ImageView 에 유일한 태 그 를 설정 했다.이 태 그 는 뒤에서 이 ImageView 를 정확하게 찾 을 수 있 도록 하 는 역할 을 한다.그렇지 않 으 면 비동기 로 그림 을 불 러 오 면 무질서 한 상황 이 발생 할 수 있다.이후 setImageView()방법 을 사용 하여 ImageView 에 그림 을 설정 합 니 다.이 방법 은 먼저 LruCache 캐 시 에서 이 그림 을 캐 시 했 는 지 찾 습 니 다.성공 적 으로 찾 으 면 캐 시 에 있 는 그림 을 ImageView 에 표시 합 니 다.그렇지 않 으 면 기본 빈 그림 이 표 시 됩 니 다.
한참 을 봤 는데 도대체 어디서 사진 을 다운 받 았 을 까?이것 은 GridView 의 스크롤 모니터 에서 진 행 된 것 입 니 다.onScroll State Changed()방법 에서 저 희 는 GridView 의 스크롤 상 태 를 판단 하 였 습 니 다.현재 GridView 가 정지 되 어 있 으 면 loadBitmaps()방법 으로 그림 을 다운로드 하고 GridView 가 스크롤 하고 있 으 면 모든 다운로드 작업 을 취소 하면 GridView 스크롤 의 유창 성 을 확보 할 수 있 습 니 다.loadBitmaps()방법 에서 저 희 는 화면 에 보 이 는 GridView 하위 요 소 를 위해 다운로드 작업 을 수행 하 는 스 레 드 를 열 었 습 니 다.다운로드 에 성공 한 후에 그림 을 LruCache 에 저장 한 다음 에 Tag 를 통 해 해당 하 는 ImageView 컨트롤 을 찾 아 다운로드 한 그림 을 표시 합 니 다.
그림 을 캐 시 하기 위해 서 는 LruCache 를 사 용 했 기 때문에 메모리 가 넘 칠 염려 가 없습니다.LruCache 에 저 장 된 그림 의 총 크기 가 용량 상한 선 에 도달 하면 최근 에 가장 적 게 사용 한 그림 을 캐 시 에서 자동 으로 삭제 합 니 다.
마지막 으로 MainActivity 를 프로그램의 주 Activity 로 새로 만 들 거나 엽 니 다.코드 는 다음 과 같 습 니 다.

public class MainActivity extends Activity { 
 
  /** 
   *         GridView 
   */ 
  private GridView mPhotoWall; 
 
  /** 
   * GridView     
   */ 
  private PhotoWallAdapter adapter; 
 
  @Override 
  protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.activity_main); 
    mPhotoWall = (GridView) findViewById(R.id.photo_wall); 
    adapter = new PhotoWallAdapter(this, 0, Images.imageThumbUrls, mPhotoWall); 
    mPhotoWall.setAdapter(adapter); 
  } 
 
  @Override 
  protected void onDestroy() { 
    super.onDestroy(); 
    //                
    adapter.cancelAllTasks(); 
  } 
 
} 
MainActivity 의 코드 는 매우 간단 해서 설명 할 것 이 없습니다.Activity 가 소각 되 었 을 때 모든 다운로드 작업 을 취소 하여 프로그램 이 배경 에서 데 이 터 를 소모 하지 않도록 합 니 다.또한 네트워크 기능 을 사 용 했 기 때문에 AndroidManifest.xml 에 네트워크 권한 을 추가 하 는 성명 을 잊 지 마 세 요.
이제 프로그램 을 실행 할 수 있 습 니 다.효 과 는 다음 그림 과 같 습 니 다. 
                                         
사진 벽 을 굴 리 면 해당 이미지 뷰 에 그림 을 비동기 로 불 러 옵 니 다.그림 을 불 러 오 는 것 이 많아 지면 서 이전에 불 러 온 그림 을 풀 어 줍 니 다.몇 번 더 굴 리 면 알 수 있 습 니 다.또한 그림 의 방출 상황 을 뚜렷하게 볼 수 있 도록 저 는 이 프로그램 에서 로 컬 캐 시 를 사용 하지 않 았 습 니 다.풀 려 난 모든 그림 을 다시 표시 하려 면 인터넷 에서 다시 다운로드 해 야 합 니 다.실제 항목 에 적당 한 로 컬 캐 시 를 맞 추 면 효과 가 좋 습 니 다.
DDMS 를 열 면 LruCache 가 이미지 캐 시 를 관리 해 주기 때문에 아무리 사진 벽 을 굴 려 도 프로그램 메모리 가 합 리 적 인 범위 내 에 유지 되 는 것 을 알 수 있 습 니 다.

이 글 은 사진 을 어떻게 더 잘 회수 하 느 냐 에 중점 을 두 고 있 기 때문에 포 토 월 은 GridView 로 간단하게 보 여 주 었 을 뿐 더 멋 지고 멋 진 포 토 월 효 과 를 보고 싶 은 분 은 제 뒤의 글안 드 로 이 드 폭포 흐름 사진 벽 구현,불규칙 배열 의 아름다움 체험을 참고 하 세 요.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.

좋은 웹페이지 즐겨찾기