갤러리 앱을 쓰고 있습니다. AbstList가있는 androidstudio 템플릿의 목록 조각에 사용됩니다.ListView는 lrucache에서 인식하지 않고 비트 맵을 재활용합니다.
일부 비트 맵을 캐시하기 위해 태스크와 lrucache를 사용하기 위해 getView를 대체합니다.
listview의 각 뷰는 TextView 위에 ImageView가있는 RelativeLayout입니다. 캐시에 비트 맵이 없으면 AsyncTask가이를로드하고이를 캐시에 저장하고 getView가 ImageView에 리소스를 그립니다. 로드 된 후 onPostExecute는 비트 맵을 ImageView에 저장합니다. 캐시에 해당하는 비트 맵이있는 경우
는 그것은 이미지 뷰에 설정되어
나는 추적 할의 getView의 convertView 매개 변수 태그에 id를 사용하여 텍스트 뷰와 이미지 뷰를 함께 보유하는 객체를 설정올바른 비트 맵을 그리십시오.
그래도,이 두 가지 문제가있다 : 내가 처음을 아래로 스크롤하면 작업이도 (올바른 비트 맵을 설정 완료되기 전에는, 새로운 이미지보기 인스턴트에 대한 이전 비트 맵 표시 비록 리소스 비트 맵을 어댑터의 getView에 그렸지만) 나는 왜 그런지 이해하지 못한다.
다시 스크롤하면 캐시의 비트 맵이 누가 재활용했는지 알 수 없지만 캐시의 비트 맵이 재생 된 것으로 판명되어 앱이 대부분 중단됩니다.
여기에 무슨 일이 일어날 지 이해할 수있는 사람이 있습니까?
public View getView(int position, View convertView, ViewGroup parent) {
Log.i(TAG, "getView: Asking for view " + position);
GalleryItemViewHolder lViewHolder;
if (convertView == null) {
convertView = getActivity().getLayoutInflater().inflate(R.layout
.gallery_item, null);
lViewHolder = new GalleryItemViewHolder();
convertView.setTag(lViewHolder);
} else {
lViewHolder = (GalleryItemViewHolder) convertView.getTag();
}
lViewHolder.setId(position);
lViewHolder.setTextView((TextView) convertView.findViewById(R.id.gallery_infoTextView));
lViewHolder.setImageView((ImageView) convertView.findViewById(R.id.gallery_imageView));
lViewHolder.getTextView().setText(getItem(position).getName() + ": (" + getItem
(position).getCount() + ")");
if (!getItem(position).paintCover(lViewHolder.getImageView())) {
Log.i(TAG,"getView: task");
new GalleryItemTask(position, lViewHolder)
.executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null);
}
Log.i(TAG,"getView: return");
return convertView;
}
커버 클래스 중간 이미지
public boolean paintCover(ImageView imageView) {
Bitmap lBitmap;
if (mId == null || (lBitmap = BitmapCacheManager.getInstance().get(mId)) == null) {
i(TAG, "paintCover: Sin Cache ");
imageView.getHeight();
imageView.getWidth();
imageView.setImageResource(android.R.drawable.alert_dark_frame);
return false;
} else
{
i(TAG, "paintCover: En Cache "+lBitmap.isRecycled());
imageView.setImageBitmap(lBitmap);
return true;
}
}
더 구체적으로 URI/스트림이 paintCover 방법이있다. 이 정의 된 덮개가없는, 갤러리 목록 그냥 제목과 전체 내용과 ID 데이터와 함께로드됩니다,이 시점에서
private void prepareGalleryLoaders() {
LoaderManager lm = getLoaderManager();
Log.i(TAG, "prepareGalleryLoaders: Iniciando loader");
lm.initLoader(IdConstants.GALLERY_LOADER, null, new GalleryLoaderCallbacks());
}
/**
* Callbacks para cargar los datos de las galerías
* Al terminar de cargarlas, se crea el nuevo arreglo
*/
private class GalleryLoaderCallbacks implements LoaderManager.LoaderCallbacks<List<Gallery>> {
@Override
public Loader<List<Gallery>> onCreateLoader(int id, Bundle args) {
return new GalleriesLoader(getActivity());
}private class GalleryItemTask extends AsyncTask<Void, Void, Gallery> {
private static final String TAG = "GalleryItemTask";
private int mId;
private String mCoverId;
private GalleryItemViewHolder mViewHolder;
private Bitmap mBitmap;
GalleryItemTask(int id, GalleryItemViewHolder galleryItemViewHolder) {
mViewHolder = galleryItemViewHolder;
mId = id;
}
@Override
protected void onPostExecute(Gallery galleries) {
if (mId != mViewHolder.getId()) {
Log.i(TAG, "onPostExecute: IDs difieren!!! "+mId+" - "+mViewHolder.getId());
mBitmap.recycle();
mBitmap=null;
return;
}
// Validar y actualizar bitmap
mViewHolder.getImageView().setImageBitmap(mBitmap);
//mGalleries.get(mId).setBitmap(mBitmap);
super.onPostExecute(galleries);
}
@Override
protected Gallery doInBackground(Void... params) {
// generar bitmap (y posiblemente agregarlo a algún cache)
String[] queryProjection = {
MediaStore.Images.ImageColumns.DATA, MediaStore.Images.ImageColumns.TITLE};
String[] selectionArgs = new String[]{String.valueOf(mGalleries.get(mId).getId())};
Cursor lCursor = getView().getContext().getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
queryProjection, MediaStore.Images.ImageColumns.BUCKET_ID + "= ?",
selectionArgs, MediaStore.Images.ImageColumns.TITLE);
lCursor.moveToFirst();
while (!lCursor.isAfterLast()) {
//Log.i(TAG,"doInBackground: "+mGalleries.get(mId).getName()+" - "+lCursor.getString
// (1)+" - "+ lCursor.getString(0));
lCursor.moveToNext();
}
lCursor.moveToFirst();
Log.i(TAG, "doInBackground: " + mId + " - " + mViewHolder.getId());
BitmapFactory.Options lOptions = new BitmapFactory.Options();
lOptions.inJustDecodeBounds = true;
mBitmap = BitmapFactory.decodeFile(lCursor.getString(0), lOptions);
lOptions.inSampleSize = ImageUtils.calculateInSampleSize(lOptions, 256, 256);
lOptions.inJustDecodeBounds = false;
mBitmap = BitmapFactory.decodeFile(lCursor.getString(0), lOptions);
BitmapCacheManager.getInstance().put(lCursor.getString(0), mBitmap);
//if(mGalleries.get(mId).getBitmap()!=null)
// mGalleries.get(mId).getBitmap().recycle();
//mGalleries.get(mId).setBitmap(mBitmap);
if(!mGalleries.get(mId).hasCover()) {
SimpleCover lSimpleCover=new SimpleCover(getActivity(),lCursor.getString(0));
mGalleries.get(mId).setCover(lSimpleCover);
}
lCursor.close();
return null;
}
}
@Override
public void onLoadFinished(Loader<List<Gallery>> loader, List<Gallery> data) {
if (mGalleries != null) {
mGalleries.clear();
} else
mGalleries = new ArrayList<Gallery>();
mGalleries.addAll(data);
for (Gallery lGallery : data) {
Log.i(TAG, "onLoadFinished: " + lGallery.getName());
}
mAdapter.notifyDataSetChanged();
}
다음 조각의에서 onCreate에서 , 나는이 방법을 실행합니다. 이미지 (커버)는 목록 어댑터의 getView에서로드됩니다.
GalleryItemTask 클래스 : 내가 처음을 아래로 스크롤하면
private class GalleryItemTask extends AsyncTask<Void, Void, Gallery> {
private static final String TAG = "GalleryItemTask";
private int mId;
private String mCoverId;
private GalleryItemViewHolder mViewHolder;
private Bitmap mBitmap;
GalleryItemTask(int id, GalleryItemViewHolder galleryItemViewHolder) {
mViewHolder = galleryItemViewHolder;
mId = id;
}
@Override
protected void onPostExecute(Gallery galleries) {
if (mId != mViewHolder.getId()) {
Log.i(TAG, "onPostExecute: IDs difieren!!! "+mId+" - "+mViewHolder.getId());
mBitmap.recycle();
mBitmap=null;
return;
}
// Validar y actualizar bitmap
mViewHolder.getImageView().setImageBitmap(mBitmap);
//mGalleries.get(mId).setBitmap(mBitmap);
super.onPostExecute(galleries);
}
@Override
protected Gallery doInBackground(Void... params) {
// generar bitmap (y posiblemente agregarlo a algún cache)
String[] queryProjection = {
MediaStore.Images.ImageColumns.DATA, MediaStore.Images.ImageColumns.TITLE};
String[] selectionArgs = new String[]{String.valueOf(mGalleries.get(mId).getId())};
Cursor lCursor = getView().getContext().getContentResolver().query(
MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
queryProjection, MediaStore.Images.ImageColumns.BUCKET_ID + "= ?",
selectionArgs, MediaStore.Images.ImageColumns.TITLE);
lCursor.moveToFirst();
while (!lCursor.isAfterLast()) {
//Log.i(TAG,"doInBackground: "+mGalleries.get(mId).getName()+" - "+lCursor.getString
// (1)+" - "+ lCursor.getString(0));
lCursor.moveToNext();
}
lCursor.moveToFirst();
Log.i(TAG, "doInBackground: " + mId + " - " + mViewHolder.getId());
BitmapFactory.Options lOptions = new BitmapFactory.Options();
lOptions.inJustDecodeBounds = true;
mBitmap = BitmapFactory.decodeFile(lCursor.getString(0), lOptions);
lOptions.inSampleSize = ImageUtils.calculateInSampleSize(lOptions, 256, 256);
lOptions.inJustDecodeBounds = false;
mBitmap = BitmapFactory.decodeFile(lCursor.getString(0), lOptions);
BitmapCacheManager.getInstance().put(lCursor.getString(0), mBitmap);
//if(mGalleries.get(mId).getBitmap()!=null)
// mGalleries.get(mId).getBitmap().recycle();
//mGalleries.get(mId).setBitmap(mBitmap);
if(!mGalleries.get(mId).hasCover()) {
SimpleCover lSimpleCover=new SimpleCover(getActivity(),lCursor.getString(0));
mGalleries.get(mId).setCover(lSimpleCover);
}
lCursor.close();
return null;
}
}
paintCover가 false를 반환하면 ImageView에 템플릿이 그렸고 스레드가 실행되어 비트 맵을 만들어 캐시에 넣은 다음 나중에 ImageView에 그립니다. true를 반환하면 이미지가 캐시에서 발견되어 ImageView에 저장된다는 것을 의미하므로 아무 것도 수행되지 않습니다. 그러나, 캐쉬의 이미지가 재활용되었다는 것을 알기 위해 노력한 후 누가 그것을했는지 또는 어떻게되었는지를 알지 못합니다. – dabicho
paintCover가 true이면 무엇을하고 싶습니까? –
고마워요, 제가 잘못 한 것을 발견했습니다 ... ID가 다르다면 이미 캐시에 넣었 기 때문에 잘못 비트 맵을 재활용하고 있습니다. 내 잘못이야. 그러나 어떻게 든 여기에서 코드를보고/discusing하는 것은 나에게 명백하게했다. paintCover가 true이면 커버가 마지막 비트 맵 (캐시에서 발견 됨)으로 그려 졌음을 의미하므로 아무 것도 표시되지 않습니다. – dabicho