상세 안 드 로 이 드성능 최적화 ViewPager 에 수백 수천 개의 고 화질 큰 그림 oom 솔 루 션 을 불 러 옵 니 다.
최근 에 프로젝트 를 할 때 선택 한 그림 을 업로드 해 야 합 니 다.위 챗,웨 이 보 와 같은 그림 선택 기 입 니 다.ContentResolver 는 로 컬 그림 자원 을 읽 고 RecyclerView+Glide 로 그림 을 불 러 오 면 목록 의 표 시 를 해결 합 니 다.이것 은 큰 문제 가 없습니다.중요 한 것 은 그림 을 클릭 하여 큰 그림 탐색 에 들 어 가 는 것 입 니 다.예 를 들 어 앨범 에 수백 장의 그림 이 있 습 니 다.즉,ViewPager 에 수백 개의 view 를 불 러 와 야 한 다 는 뜻 이다.게다가 핸드폰 으로 찍 은 사진 은 모두 1-2 천만 화소 의 고 화질 큰 그림(필자 핸드폰 2 천만 화소 즉 사진 을 찍 은 사진 3888*5152)이 고 크기 도 5-7 메 가 이다.ViewPager 는 10 여 장 이 미 끄 러 지지 않 으 면 oom 이다.즉,사진 을 압축 처리 하여 사진 해상 도 를 1366*960 으로 낮 춘 것 이다.크기 를 150 k 이하 로 압축 하고 ViewPager 의 destroy Item 방법 으로 bitmap 자원 을 회수 했다.효과 가 좋 지만 oom 의 강림 을 막 을 수 없다.50-70 장 을 훑 어 보 았 을 때 oom 은 메모리 가 계속 폭등 하여 회수 할 수 없 었 습 니 다.믿 지 않 으 면 압축 과 회수 가 문 제 를 근본적으로 해결 할 수 없 었 습 니 다.그러면 어떻게 해결 합 니까?위 챗 과 위 보 를 연 구 했 는데 그들 은 아무리 해도 oom 을 할 줄 모 르 고 마지막 에 나 는 해결 방안 을 생각 했다.
2.방안 실시
1.예전 의 일반적인 방법
부분 코드:
List<SubsamplingScaleImageView> mViews = new ArrayList<>();
int size = mDatas.size();
for (int i = 0; i < size; i++) {
SubsamplingScaleImageView view = new SubsamplingScaleImageView(this);
mViews.add(view);
}
mBinding.viewpager.setAdapter(new MyAdapter());
class MyAdapter extends PagerAdapter {
@Override
public int getCount() {
return mDatas.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, final int position) {
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
ViewPager.LayoutParams.MATCH_PARENT,ViewPager.LayoutParams.MATCH_PARENT);
final SubsamplingScaleImageView imageView = mViews.get(position);
imageView.setLayoutParams(params);
final String url = mDatas.get(position);
String cacheExists = cacheExists(url);
if(TextUtils.isEmpty(cacheExists)) {// ( )
new AsyncTask<Void, Void, String>() {
@Override
protected String doInBackground(Void... voids) {
String cacheNoExistsPath = getCacheNoExistsPath(url);
BitmapCompressUtils.compressBitmap(url, cacheNoExistsPath);
File file = new File(cacheNoExistsPath);
if (file.exists()) {//
return cacheNoExistsPath;
} else {
return url;
}
}
@Override
protected void onPostExecute(String s) {
imageView.setImage(ImageSource.uri(s));
}
}.execute();
} else {//
imageView.setImage(ImageSource.uri(cacheExists));
}
container.addView(imageView);
return imageView;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
SubsamplingScaleImageView imageView = mViews.get(position);
if(imageView != null) {
imageView.recycle();
}
container.removeView(imageView);
}
}
/**
* url ""
*
* @param url
* @return
*/
private String cacheExists(String url) {
try {
File fileDir = new File(mCacheRootPath);
if(!fileDir.exists()) {
fileDir.mkdirs();
}
File file = new File(mCacheRootPath,new StringBuffer().append(MD5EncryptorUtils.md5Encryption(url)).toString());
if(file.exists()) {
return file.getAbsolutePath();
}
} catch (Exception e) {
e.printStackTrace();
}
return "";
}
public String getCacheNoExistsPath(String url) {
File fileDir = new File(mCacheRootPath);
if(!fileDir.exists()) {
fileDir.mkdirs();
}
return new StringBuffer().append(mCacheRootPath)
.append(MD5EncryptorUtils.md5Encryption(url)).toString();
}
여기 서 필 자 는 자신의 압축 알고리즘(이전 글 AndroidNDK 이미지 압축 의 Libjpeg 라 이브 러 리 사용)는 이미지 압축 을 하고 캐 시 를 했 습 니 다.세심 한 친구 들 은 mViews 집합 에 추 가 된 view 개 수 는 mDatas 의 size 크기 개수 라 는 것 을 알 아야 합 니 다.그러면 문제 가 발생 할 수 있 습 니 다.ViewPager 가 계속 아래로 미 끄 러 질 때 메모리 가 계속 증가 합 니 다.즉,자원 회수 입 니 다.또한 문 제 를 해결 할 수 없습니다.2.해결 방안:
그림 압축 도 하고 자원 회수 도 했 지만 ViewPager 가 점점 더 많은 그림 을 불 러 올 때 oom 은 피 할 수 없 을 것 입 니 다.믿 지 않 으 면 해 보 세 요.
여기 서 ViewPager 의 view 재 활용 메커니즘(자신 이 이해 하 는)을 사용 해 야 합 니 다.즉,mViews 는 우리 가 주어진 수량 을 고정 시 켜 야 합 니 다.예 를 들 어 4.이렇게 ViewPager 의 i 가 실제 필요 로 하 는 item 도 4 개 밖 에 없습니다.
수 정 된 부분 코드:
for (int i = 0; i < 4; i++) {
SubsamplingScaleImageView view = new SubsamplingScaleImageView(this);
mViews.add(view);
}
mBinding.viewpager.setAdapter(new MyAdapter());
class MyAdapter extends PagerAdapter {
@Override
public int getCount() {
return mDatas.size();
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
@Override
public Object instantiateItem(ViewGroup container, final int position) {
ViewGroup.LayoutParams params = new ViewGroup.LayoutParams(
ViewPager.LayoutParams.MATCH_PARENT,ViewPager.LayoutParams.MATCH_PARENT);
int i = position % 4;
final SubsamplingScaleImageView imageView = mViews.get(i);
imageView.setLayoutParams(params);
final String url = mDatas.get(position);
String cacheExists = cacheExists(url);
if(TextUtils.isEmpty(cacheExists)) {// ( )
new AsyncTask<Void, Void, String>() {
@Override
protected String doInBackground(Void... voids) {
String cacheNoExistsPath = getCacheNoExistsPath(url);
BitmapCompressUtils.compressBitmap(url, cacheNoExistsPath);
File file = new File(cacheNoExistsPath);
if (file.exists()) {//
return cacheNoExistsPath;
} else {
return url;
}
}
@Override
protected void onPostExecute(String s) {
imageView.setImage(ImageSource.uri(s));
}
}.execute();
} else {//
imageView.setImage(ImageSource.uri(cacheExists));
}
container.addView(imageView);
return imageView;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
int i = position % 4;
SubsamplingScaleImageView imageView = mViews.get(i);
if(imageView != null) {
imageView.recycle();
}
container.removeView(imageView);
}
간단 한 수정 으로 oom 을 효과적으로 방지 할 수 있 습 니 다. position%4 를 이용 하여 몇 번 째 컨트롤 을 가 져 와 mViews 에서 값 을 추출 하여 viewpager 에 불 러 온 mViews 에 저 장 된 그림 을 4 개 로 보장 합 니 다.계속 아래로 미 끄 러 지 는 메모리 동향 도 를 보 세 요.
메모리 가 기본적으로 안정 을 유지 하 다.
데모 데모
앨범 을 읽 으 려 면 시 뮬 레이 터 를 실행 하지 않 고 gif 를 직접 캡 처 합 니 다.
demo 다운로드:demo
총화
이것 은 간단 한 프 리 젠 테 이 션 일 뿐 실제 프로젝트 의 앨범 은 이것 보다 훨씬 복잡 합 니 다.쉽게 말 하면 압축 하고 회수 하 며 View 를 다시 사용 하 는 것 입 니 다.
이상 이 바로 본 고의 모든 내용 입 니 다.여러분 의 학습 에 도움 이 되 고 저 희 를 많이 응원 해 주 셨 으 면 좋 겠 습 니 다.
이 내용에 흥미가 있습니까?
현재 기사가 여러분의 문제를 해결하지 못하는 경우 AI 엔진은 머신러닝 분석(스마트 모델이 방금 만들어져 부정확한 경우가 있을 수 있음)을 통해 가장 유사한 기사를 추천합니다:
viewPager는 큰 그림 처리와 함께 동적으로 그림을 불러옵니다그림을 assets 아래에 놓으면 그림의 수량을 동적으로 읽을 수 있으며 그림의 내용과 수량이 바뀔 때 프로그램은 수정할 필요가 없다. 3 그림이 너무 크면 그림을 불러올 때 메모리가 넘치는 문제를 겪었다고 믿는다....
텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
CC BY-SA 2.5, CC BY-SA 3.0 및 CC BY-SA 4.0에 따라 라이센스가 부여됩니다.