Android BaseAdapter With LruCache Some ui problems

让人想犯罪 __ 提交于 2019-12-11 09:38:41

问题


I am trying to implement to a list view with all contact images with the help of base adapter and LruCache. But on a long scroll on screen all the images(corresponding to that view) are displayed before setting actual image.

eg: list view with 5 items per page, if we scrolled from first contact to 60th, on first view of list view images of 1,6,11,16,21..51 are displayed for a few milli seconds before the 55th images is shown

Main codes are

//Adapter
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView = (ImageView) convertView;
if(imageView == null){
 imageView = new ImageView(getActivity());
}    
int id =  contactId[position];
final String imageKey = String.valueOf(contactId);
final Bitmap bitmap = cache.get(imageKey);
if (bitmap != null) {
  imageView.setImageBitmap(bitmap);
} else {    
  Resources res = context.getResources();
  BitmapManager bm = new BitmapManager(imageView, res, cache);
  bm.setContext(getActivity());
  bm.execute(id);
}
return imageView;
}

BitmapManager Post Execute Code

@Override
protected void onPostExecute(Bitmap bitmap) {
    // TODO Auto-generated method stub
    try{
        if(isCancelled()){
            bitmap = null;
        }
        if(imageViewReference != null && bitmap != null){
            ImageView imageView = imageViewReference.get();
            imageView.setImageBitmap(bitmap);
            cache.put(String.valueOf(res), bitmap);
            if(imageView != null){
                imageView.setImageBitmap(bitmap);
            }

        }
    }catch(Exception e){

    }
    super.onPostExecute(bitmap);
}

How to solve this problem. Thanks


回答1:


As you scroll down, your views get reused for new list positions that come into view. Since you start a new BitmapManager task each time getView is called, the tasks get lined up, waiting to update the image. As they each finish loading their bitmap, they put it into the ImageView in order, which is what you are seeing.

It looks like you were trying to use a reference to the ImageView to avoid using the bitmap after it was scrolled out of view, but the reason that didn't work is that the adapter is recycling your ImageViews, and so the reference stays valid, even though in reality the ImageView is being used for a different list item now.

There are different ways to solve this, but the simplest that comes to mind is to construct your BitmapManager with a list index, rather than the ImageView itself. Then in getView you can keep a map of what views are being used on what positions. When BitmapManager finishes, check if there is a current ImageView for the position that you've just loaded into the cache. If not, then do nothing.

Here is some code that shows what I'm talking about. I didn't try it, so apologies if there are errors.

//Adapter
private SparseArray<ImageView> ivMap = new SparseArray<ImageView>();
public View getView(int position, View convertView, ViewGroup parent) {
    ImageView imageView = (ImageView) convertView;
    if(imageView == null){
      imageView = new ImageView(getActivity());
    } else {
      // If recycled, remove the ImageView's previous position from map
      int oldPosition = ivMap.indexOfValue(imageView);
      if (oldPosition >= 0) {
        ivMap.remove(oldPosition);
      }
    }
    // Keep track of which view is representing this position
    ivMap.put(position, imageView);

    int id =  contactId[position];
    final String imageKey = String.valueOf(contactId);
    final Bitmap bitmap = cache.get(imageKey);
    if (bitmap != null) {
      imageView.setImageBitmap(bitmap);
    } else {    
      Resources res = context.getResources();
      BitmapManager bm = new BitmapManager(ivMap, position, res, cache);
      bm.setContext(getActivity());
      bm.execute(id);
    }
    return imageView;
}

//BitmapManager
@Override
protected void onPostExecute(Bitmap bitmap) {
    // TODO Auto-generated method stub
    try{
        if(isCancelled()){
            bitmap = null;
        }
        if(bitmap != null){
            cache.put(String.valueOf(res), bitmap);
            ImageView imageView = ivMap.get(position);
            if (imageView != null) {
                imageView.setImageBitmap(bitmap);
            }
        }
    }catch(Exception e){

    }
    super.onPostExecute(bitmap);
}


来源:https://stackoverflow.com/questions/27425696/android-baseadapter-with-lrucache-some-ui-problems

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!