Ashish Bhatia
Ashish Bhatia

Reputation: 51

Gridview images changes/shuffle on scroll

I have a gridview with the custom arrayadapter. On scrolling the images shuffle. I am sure there is something wrong with the adapter. I am missing something. I have posted the code of adapter.

public class CustomAdapterForDealsGrid extends ArrayAdapter{

private  final boolean checkBoxState[] ;

private TCLruCache cache;

Context context;
int layoutResourceId;
private BtnClickListener mClickListener = null;
private OnClickListener clickListner = null;


ArrayList<Ads> data = new ArrayList<Ads>();
Map<String,Bitmap> imageMap = new HashMap<String, Bitmap>();

public CustomAdapterForDealsGrid(Context context, int resource,
        ArrayList<Ads> objects,BtnClickListener listener) {
    super(context, resource, objects);

    ActivityManager am = (ActivityManager) context.getSystemService(
            Context.ACTIVITY_SERVICE);
        int memoryClass = am.getMemoryClass() * 1024 * 1024;
        cache = new TCLruCache(memoryClass);

    this.layoutResourceId = resource;
    this.context = context;
    this.data = objects;
    checkBoxState=new boolean[this.data.size()];

    mClickListener = listener;
    //new GetImageAsync().execute();
}

 private class GetImageAsync extends AsyncTask<Void, Void, Boolean> {

    @Override
    protected Boolean doInBackground(Void... arg0) {

        setImageMap();  
        return null;
    }

 }
public void setImageMap(){
    for(Ads ads : data){
        try {
            imageMap.put("http://"+ApplicationConstant.host+ "/"+ads.getImagepath(),getImageFromUrl("http://"+ApplicationConstant.host+ "/"+ads.getImagepath()));
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }
}

@Override
public int getCount() {
    return data.size();
}

@Override
public Ads getItem(int item) {
    return data.get(item);
}

@Override
public long getItemId(int position) {
    return position;
}




@Override
public View getView(final int position, View convertView, ViewGroup parent) {
    View row = convertView;
    DealHolder holder = null;


    if (row == null) {
        LayoutInflater inflater = ((Activity) context).getLayoutInflater();
        row = inflater.inflate(layoutResourceId, parent, false);

        holder = new DealHolder();
        holder.imageItem = (ImageView) row.findViewById(R.id.item_deal);
        holder.txtURL =(TextView) row.findViewById(R.id.item_url);
        holder.txtDesc =(TextView) row.findViewById(R.id.item_desc);
        holder.chkGrid = (CheckBox)row.findViewById(R.id.chkGrid);
        holder.txtPrice =(TextView) row.findViewById(R.id.item_price);

        holder.button = (Button) row.findViewById(R.id.btnDeal);
        holder.button.setTag(Integer.valueOf(position));
        holder.button.setOnClickListener(new OnClickListener() {

            @Override
            public void onClick(View v) {

                if(mClickListener != null)
                    mClickListener.onBtnClick((Integer)v.getTag());                

            }
        });
        row.setTag(holder);
    } else {
        holder = (DealHolder) row.getTag();
    }

    if(holder.setFlag!=true){
    Ads ads = data.get(position);

    holder.imageItem.setImageResource(R.drawable.powerelectronics);
    holder.txtPrice.setText(ads.getPricerange());
    holder.txtURL.setText(ads.getUrl());
    holder.txtDesc.setText(ads.getDesc());
    holder.chkGrid.setChecked(checkBoxState[position]);
            holder.chkGrid.setOnClickListener(new OnClickListener() {

                @Override
                public void onClick(View v) {


                           if(((CheckBox)v).isChecked()){
                               checkBoxState[position]=true;
                               data.get(position).setChecked(true);
                           }else{
                               checkBoxState[position]=false;
                               data.get(position).setChecked(false);
                           }

                }

                }
            );

    try {
        if(cache.get("http://"+ApplicationConstant.host+ "/"+ads.getImagepath()) != null){
            holder.imageItem.setImageBitmap(cache.get("http://"+ApplicationConstant.host+ "/"+ads.getImagepath()));
        }
        else{
BitmapFactory.decodeResource(context.getResources(),        R.drawable.abs__activated_background_holo_light));
        setBitmap(holder.imageItem, "http://"+ApplicationConstant.host+ "/"+ads.getImagepath(),ads.getDesc());
        }
        holder.setFlag = true;

    } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
    }
    return row;

}

static class DealHolder {
    TextView txtPrice,txtURL,txtDesc;
    ImageView imageItem;
    Button button;
    CheckBox chkGrid;
    Boolean setFlag = new Boolean(false);

}


public Bitmap getImageFromUrl(String imgPath) throws Exception{
 HttpGet httpRequest = null;
 URL url = new URL(imgPath);

 httpRequest = new HttpGet(url.toURI());

 HttpClient httpclient = new DefaultHttpClient();
 HttpResponse response = (HttpResponse) httpclient
         .execute(httpRequest);

 HttpEntity entity = response.getEntity();
 BufferedHttpEntity b_entity = new BufferedHttpEntity(entity);
 InputStream input = b_entity.getContent();

 Bitmap bitmap = BitmapFactory.decodeStream(input);
 return bitmap;
}

private Bitmap methodScaledImage(int width,int height,Bitmap origBitmap) throws FileNotFoundException{

Bitmap background = Bitmap.createBitmap((int)width, (int)height, Config.ARGB_8888);
float originalWidth = origBitmap.getWidth(), originalHeight = origBitmap.getHeight();
Canvas canvas = new Canvas(background);
float scale = width/originalWidth;
float xTranslation = 0.0f, yTranslation = (height - originalHeight * scale)/2.0f;
Matrix transformation = new Matrix();
transformation.postTranslate(xTranslation, yTranslation);
transformation.preScale(scale, scale);
Paint paint = new Paint();
paint.setFilterBitmap(true);
canvas.drawBitmap(origBitmap, transformation, paint);
return background;
}



private void setBitmap(final ImageView iv, final String path,final String desc) {

new AsyncTask<Void, Void, Bitmap>() {

    @Override
    protected Bitmap doInBackground(Void... params) {

        Bitmap imageBtMP= null;
        try {
            imageBtMP = getImageFromUrl(path);
            if(imageBtMP!= null){
                cache.put(path, imageBtMP);
            }
        } catch (Exception e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return imageBtMP;
    }

    @Override
    protected void onPostExecute(Bitmap result) {
        super.onPostExecute(result);
        iv.setImageBitmap(result);

        iv.setOnClickListener(new OnClickListener() {


            public void onClick(View v) {


                LayoutInflater layoutInflater = LayoutInflater.from(getContext());
               View popupView = layoutInflater.inflate(R.layout.activity_desc_deal, null);  
                        final PopupWindow popupWindow = new PopupWindow(
                          popupView, 
                          LayoutParams.WRAP_CONTENT,  
                                LayoutParams.WRAP_CONTENT);  

                        final TextView descTextview = (TextView) popupView.findViewById(R.id.descdeal);
                        descTextview.setText(desc);


                        Button btnDismiss = (Button)popupView.findViewById(R.id.dismiss);
                        btnDismiss.setOnClickListener(new Button.OnClickListener(){

                @Override
                public void onClick(View v) {
                 // TODO Auto-generated method stub
                 popupWindow.dismiss();
                }});

                        popupWindow.showAsDropDown(v, 50, -30);


            }
        });

    }
}.execute();
}
private class TCLruCache extends LruCache<String, Bitmap> {


public TCLruCache(int maxSize) {
    super(maxSize);
}
}

}

Upvotes: 1

Views: 799

Answers (1)

Ifrit
Ifrit

Reputation: 6821

Looks like the problem is with your setBitmap() method. During the whole async, there's absolutely no guarantee that the ImageView you passed in, is the same one which represents the Bitmap in onPostExecute(). This is due to the View recycling the adapter does. Also, it's imperative that you store that ImageView as a WeakReference. Else you risk leaking it.

You're async should follow along more like this:

private class ExampleAsync extends AsyncTask<Void, Void, Bitmap> {
    private WeakReference<ImageView> mImageViewRef;
    private String mPath;
    private String mDesc;

    public ExampleAsync(ImageView iv, String path, String desc) {
        iv.setTag(path);    //Records which path the ImageView represents
        mImageViewRef = new WeakReference<ImageView>(iv);
        mPath = path;
        mDesc = desc;
    }

    @Override
    protected Bitmap doInBackground(Void... params) {
        ImageView iv = mImageViewRef.get();
        if (iv == null || !mPath.equals(iv.getTag())) {
            return null;
        }

        //Retrieve bitmap logic. Return results or null if it fails
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        ImageView iv = mImageViewRef.get();
        if (iv == null || bitmap == null || !mPath.equals(iv.getTag())) {
            //In an invalid state or results had error. Ignore everything and just exit Async.
            return;
        }

        //Received valid results and in good state. Set ImageView and do all your other logic
    }
}

It's just a rough sketch but should get the point across. This will handle the varying outcomes of rendering views with the adapter and/or during a user scroll. Recording the path within the ImageView tag catches when an ImageView is recycled and used for a different position. Storing in a WeakReference ensures an ImageView being destroyed can actually be destroyed. Otherwise you'll keep the reference around and continue to load and put a Bitmap in it. You always null check the reference to ensure the View wasn't destroyed. When using, you always temporarily store in a local variable to prevent it from being GCed.

Upvotes: 1

Related Questions