简体   繁体   中英

Listview shows images in wrong positions when scrolling

I have a ListView which I am filling from server. Everything works fine but the single problem is that the downloaded images are shown in wrong item positions when scroll. Only after a few seconds then it shows the correct image on the right position.

Here is my ArrayAdapter class, which includes the AsynchTask:

public class ApplicationAdapter extends ArrayAdapter<Application> {
    private List<Application> items;

    public ApplicationAdapter(Context context, List<Application> items) {
        super(context, R.layout.app_custom_list, items);
        this.items = items;
    }

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

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        View v = convertView;

        if (v == null) {
            LayoutInflater li = LayoutInflater.from(getContext());
            v = li.inflate(R.layout.app_custom_list, null);
        }

        Application app = items.get(position);

        if (app != null) {
            ImageView imageView = (ImageView) v.findViewById(R.id.appIcon);
            TextView titleText  = (TextView) v.findViewById(R.id.titleTxt);

            if (imageView != null) {

                String path_image = app.getImagePath();

                // Call AsynchTask to load image into ImageView from path
                DownloadImageTask1 d = new DownloadImageTask(imageView);
                d.execute(path_image);
            }


            if (titleText != null) {

                titleText.setText(app.getTitle());

            }

        }

        return v;
    }

private class DownloadImageTask1 extends AsyncTask<String, Void, Bitmap> {
    ImageView bmImage;

    public DownloadImageTask1(ImageView bmImage) {
        this.bmImage = bmImage;
    }

    protected Bitmap doInBackground(String... urls) {
        String urldisplay = urls[0];
        Bitmap mIcon11 = null;
        try {
            InputStream in = new java.net.URL(urldisplay).openStream();
            mIcon11 = BitmapFactory.decodeStream(in);
        } catch (Exception e) {
            Log.e("Error", e.getMessage());
            e.printStackTrace();
        }
        return mIcon11;
    }

    protected void onPostExecute(Bitmap result) {
        bmImage.setImageBitmap(getRoundedCornerBitmap(result));

    }
}

Can somebody please guide me to the right direction? I am already working for days to solve this issue. Thanks!!!

This is because the ImageView is reused when the listview is scrolled. show a loading image in the listview onPreExecute . it woluld be better if you use some library like picasso for this. as it does all the work for you including saving the image in the catch

You should use another class for holding your objects, it helps you keep a good reference once set.

And it's best you change your adapter a little bit.

It's best you get a reference to your layoutInflater once , since getView is called for every item in the listview.

So declare your layoutInflater for the whole class and get a reference only once

For example :

 private LayoutInflater inflater;


 @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ImageHolder holder = new ImageHolder();

        if (inflater == null)
            inflater = (LayoutInflater) activity
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);

        if(convertView == null){
            convertView = inflater.inflate(R.layout.fragment_list_item_transition, null);
            ImageView imageView = (ImageView) convertView.findViewById(R.id.appIcon);
            TextView titleText  = (TextView) convertView.findViewById(R.id.titleTxt);
            holder.image = imageView;
            holder.title = titleText;
            convertView.setTag(holder); 

        }else{
            holder = (ImageHolder) convertView.getTag(position);
        }

        Application app = items.get(position);

        if (app != null) {


            holder.title.seText(app.getTitle());
            String path_image = app.getImagePath();

            // Call AsynchTask to load image into ImageView from path
            DownloadImageTask1 d = new DownloadImageTask1(holder.imageView);

            d.execute(path_image);
        }

        return convertView;
    }


    private static class ImageHolder{
        ImageView image;
        TextView title;

    }

You can also try UniversalImageLoader library to load images.. Try this

ImageLoader.getInstance().displayImage(url, holder.imgView, options);

to load images inside adapter..

Use DisplayImageOptions as follows inside constructor of adapter

 options = new DisplayImageOptions.Builder()
                .showImageOnLoading(android.R.color.transparent)
                .showImageForEmptyUri(android.R.color.transparent)
                .showImageOnFail(android.R.color.transparent)
                .cacheInMemory(true)
                .cacheOnDisk(true)
                .considerExifParams(true)
                .bitmapConfig(Bitmap.Config.RGB_565)
                .build();

and add

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build();
        StrictMode.setThreadPolicy(policy);

inside onCreateView/onCreate of fragment/activity contaning the list

Try something like this...

replace

 if (v == null) {
            LayoutInflater li = LayoutInflater.from(getContext());
            v = li.inflate(R.layout.app_custom_list, null);
        }

with

if (v == null) {
            LayoutInflater li = LayoutInflater.from(getContext());
            v = li.inflate(R.layout.app_custom_list, null);
            convertView.setTag(v);
        } else {
            v = (View) convertView.getTag();
        }

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM