2014-11-04 3 views
1

Я пишу приложение галереи. Он работает с шаблоном androidstudio для фрагмента списка с помощью AbsList.ListView перерабатывает растровое изображение без уведомления в lrucache

Я переопределяю getView для использования задачи и lrucache для кэширования некоторых растровых изображений.

Каждый вид из списка представляет собой RelativeLayout с ImageView над TextView. Если в кеше нет растрового изображения, тогда AsyncTask загружает его и помещает в кеш, а getView рисует ресурс в ImageView. После того, как он загружен, onPostExecute помещает растровое изображение в ImageView.

Если есть соответствующее изображение на кэше, он устанавливается в ImageView

Я установил объект, содержащий TextView и ImageView вместе с идентификатором в параметре тега convertView в GetView, чтобы следить из правильный битмап для рисования.

У меня есть эти две проблемы, хотя:

  1. Когда я прокручиваю вниз в первый раз, новые виды изображения появляются с предыдущим растрового изображения на мгновение до того, как задача завершает создание правильного растрового изображения (даже хотя я рисую битмап ресурсов на getView адаптера), я не понимаю, почему.

  2. Когда я прокручиваю назад, чаще всего приложение падает, потому что битмап в кеше оказывается переработанным, хотя я понятия не имею, кто его переработал.

Может ли кто-нибудь помочь мне понять, что здесь происходит?

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; 
     } 

Класс крышки имеет этот метод paintCover, где срединно является URI/потока к изображению

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; 
    } 

} 

более подробно. В OnCreate фрагмента, я запускаю этот метод:

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(); 
    } 

На данный момент, нет обложки определена, галереи список просто загружаются с названиями и общим содержанием и данными идентификаторов. Изображения (обложки) загружаются в 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; 
    } 
} 

ответ

0

Когда я прокручиваю вниз в первый раз, новые виды изображений появляются с предыдущего растровым изображения на мгновение перед задачей завершает настройку правильных точечного рисунка (даже хотя я рисую битмап ресурсов на адаптере getView) Я не понимаю, почему.

Это должно быть потому, что вы положили notifyDataSetChanged() не в том месте. Отправьте код, в который вы его положили.

Когда я прокручиваю обратно, в большинстве случаев в приложение падает, потому что Bitmap на кэш оказывается переработаны, хотя я понятия не имею, кто переработанной его.

Я думаю, что его, потому что вы не указали, что делать, если paintCover является true:

if (!getItem(position).paintCover(lViewHolder.getImageView())) { 
     Log.i(TAG,"getView: task"); 
     new GalleryItemTask(position, lViewHolder) 
       .executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR, null); 
} 
else 
{ 
    //what should the adapter do if paintCover is true? 
} 

Если ошибка все еще существует, пожалуйста, напишите свой GalleryItemTask код.

+0

Если paintCover возвращает false, это означает, что он нарисовал шаблон в ImageView, а поток запускает создание Bitmap и помещает его в кеш и нарисовывает его на ImageView позднее. Если он возвращает true, это означает, что изображение было найдено в кеше и помещено в ImageView, поэтому ничего не делается. Однако, пытаясь выяснить, я увидел, что изображение в кеше было переработано, но я не знаю, кто это сделал или как это произошло. – dabicho

+0

Что вы хотите сделать, если paintCover верно? –

+0

Спасибо, я только что узнал, что я сделал неправильно ... Если идентификатор отличается, я ошибочно перерабатываю растровое изображение, потому что я уже помещал его в кеш. Виноват. Но каким-то образом просмотр/обсуждение кода здесь дал мне понять. Если значение paintCover истинно, это означает, что обложка была нарисована финальным битовым рисунком (как было обнаружено в кеше), поэтому на данный момент ничего не происходит. – dabicho

Смежные вопросы