안 드 로 이 드 포 토 월 애플 리 케 이 션 이 아무리 많은 사진 을 실현 해도 붕 괴 를 두려워 하지 않 는 다.
오늘 우리 사진 벽 애플 리 케 이 션 의 실현 은 사진 이 너무 많아 프로그램 이 무 너 지 는 것 을 어떻게 방지 하 느 냐 에 중점 을 두 었 다.주요 핵심 알고리즘 은 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 로 간단하게 보 여 주 었 을 뿐 더 멋 지고 멋 진 포 토 월 효 과 를 보고 싶 은 분 은 제 뒤의 글안 드 로 이 드 폭포 흐름 사진 벽 구현,불규칙 배열 의 아름다움 체험을 참고 하 세 요.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
Bitrise에서 배포 어플리케이션 설정 테스트하기이 글은 Bitrise 광고 달력의 23일째 글입니다. 자체 또는 당사 등에서 Bitrise 구축 서비스를 사용합니다. 그나저나 며칠 전 Bitrise User Group Meetup #3에서 아래 슬라이드를 발표했...
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.