android – view changed unexpectedly when scroll list-ThrowExceptions

Exception or error:

I am facing an unexpected problem in inflating listview.

I am creating a listview in which I am showing image title and thumbnail. We can also show audio files thumbnail but giving class of only image.

When I scroll list speedily. Its view changed many times. Below my adapter class in which I am using an AsynkTask class to get thumbnail and set this thumbnail to imageview.

public class AdapterForBooks extends ArrayAdapter<ModelFile> {

    List<ModelFile> list;
    Context context;
    WindowManager wm;
    Display display;
    int w;

    public AdapterForBooks(Context context, List<ModelFile> list) {
        super(context, R.layout.list_layout_home, list);
        // TODO Auto-generated constructor stub
        this.list = list;
        this.context = context;
        wm = (WindowManager) context
                .getSystemService(Context.WINDOW_SERVICE);
        display = wm.getDefaultDisplay();
        w = display.getWidth();

    }

    static class ViewHolder {
        TextView txtName;
        ImageView img;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        // TODO Auto-generated method stub
        View view = null;
        if (convertView == null) {
            LayoutInflater inflter = (LayoutInflater) LayoutInflater
                    .from(context);
            view = inflter.inflate(R.layout.list_layout_home, null);
            final ViewHolder holder = new ViewHolder();
            holder.txtName = (TextView) view
                    .findViewById(R.id.textViewName);
            holder.img = (ImageView) view.findViewById(R.id.imageView);
            LayoutParams params = (LayoutParams) holder.img
                    .getLayoutParams();
            params.height = w / 4;
            params.width = w / 4;
            holder.img.setLayoutParams(params);
            view.setTag(holder);
        } else {
            view = convertView;
        }
        final ViewHolder holder = (ViewHolder) view.getTag();
        String name = list.get(position).getFileName();
        holder.txtName.setText(name);

        String filePath = list.get(position).getFilePath();
        // holder.img.setImageBitmap(Bitmap.createScaledBitmap(BitmapFactory.decodeFile(filePath),100,100,false));
        new SetThumbnail()
                .execute(new Thumbnail(holder, filePath, position));
        return view;
    }

    class Thumbnail {
        ViewHolder holder;
        String path;
        int position;

        public Thumbnail(ViewHolder holder, String path, int position) {
            this.holder = holder;
            this.path = path;
            this.position = position;
        }

        public ViewHolder getHolder() {
            return holder;
        }

        public String getPath() {
            return path;
        }

        public int getPosition() {
            return position;
        }

    }

    class SetThumbnail extends AsyncTask<Thumbnail, Void, Bitmap> {

        ViewHolder holder;

        int position;

        @Override
        protected Bitmap doInBackground(Thumbnail... params) {
            // TODO Auto-generated method stub
            int pos = params[0].getPosition();
            position = pos;
            String path = params[0].getPath();
            holder = params[0].getHolder();

            Log.e("Ref", "Pos = " + pos + " " + holder);
            try {
                Bitmap thumbnail = BitmapFactory.decodeFile(path);
                thumbnail = Bitmap.createScaledBitmap(thumbnail, 100, 100,
                        false);

                return thumbnail;
            } catch (Exception e) {

                return null;
            }
        }

        @Override
        protected void onPostExecute(Bitmap result) {
            // TODO Auto-generated method stub
            super.onPostExecute(result);

            if (holder != null && result != null) {

                Log.i("Ref", "Position = " + position + " " + holder);
                holder.img.setImageBitmap(result);
            } else {
                holder.img.setImageResource(R.drawable.format_picture);
            }
        }
    }
}

I can also set thumbnail by the help of commented line before starting asynktask but it will slow my list inflation.

How to solve:

ListView recycles views, when you scroll. Your problem is happening because the AsyncTask finishes after the view has been recycled, so “old” images are displayed in the recycled views. Here is how you can solve it:

Step 1) Update your get view to include a line just before starting the AsyncTask

 holder.img.setTag(new Integer(position))
 new SetThumbnail().execute(new Thumbnail(holder, filePath, position));

Step 2) Set the image only if the position is same as the tag (update your onPostExecute):

@Override
protected void onPostExecute(Bitmap result) {
    if(holder == null) return;

    int viewPosition = (Integer) holder.img.getTag();
    if(position == viewPosition) {
        if(result != null) {
            holder.img.setImageBitmap(result);
        }
        else {
            holder.img.setImageResource(R.drawable.format_picture);
        }
    }
}

###

first of all declare inflater on class level and in getview only write if condition if view is null then create and run it. it will definitely work.

   LayoutInflater inflter = (LayoutInflater) LayoutInflater
                .from(context);
         ......
         ......

 public View getView(int position, View convertView, ViewGroup parent) {
    // TODO Auto-generated method stub
    if (convertView == null) {

      view = inflter.inflate(R.layout.list_layout_home, null);
   }

###

As I suspect, you are downloading images from internet to set in your imageviews. The images change or shuffle because of lazy loading, it means that your imageViews get created before the image is downloaded and while you scroll android set the downloaded images in the first imageview it finds. The imageview it find might be wrong because in getview method in adapter reuse memory allocated to objects and this reusability causes images to shuffle.

However, this is a nice project to solve this problem, which I also used and solved mine.

You might wanna try it out.

Hope this helps, Happy coding…:)

Leave a Reply

Your email address will not be published. Required fields are marked *