0

Hello I fill my ListView with a BaseAdapter, here a Download an Image from url, then I set the BitMap result in ImageView inside the xml row. It works fine, but when I scroll the images appear and disapear in diferent places.

This my Code:

Activity:

public class MyActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity);

        lvData = (ListView) findViewById(R.id.listview1);

        AdapterClass adapter = new AdapterClass(this, String[] urls);

        lvData.setAdapter(adapter);
    }
}

Adapter:

public class PopularAdapter extends BaseAdapter {

    private String[] mList;
    private LayoutInflater mLayotInflalter;

    public PopularAdapter(Context context, String[] list) {
        mList = list;
        mLayotInflalter = ((Activity) context).getLayoutInflater();
    }

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

    @Override
    public Object getItem(int position) {
        return mList.get(position);
    }

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

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

        if (convertView == null) {
            convertView = mLayotInflalter.inflate(R.layout.row, null);
            wrapper = new WrapperRow (convertView);

            convertView.setTag(wrapper);
        } else
            wrapper = (WrapperRow ) convertView.getTag();

        // //

        new DownloadImage(wrapper.getImageView()).execute(mList.[position]);

        return convertView;
    }

}

Image Downloader Class:

public class DownloadImage extends AsyncTask<String, Void, Bitmap> {
    ImageView bmImage;

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

Can you help me please? :D

SBH
  • 1,787
  • 3
  • 22
  • 27
  • Try using a library to deal with that. I know that's not an answer, but I'd recommend using [Android-Universal-Image-Loader](https://github.com/nostra13/Android-Universal-Image-Loader) – ezcoding Oct 24 '14 at 19:25

1 Answers1

3

This happens because the views get recycled in a ListView. This answer does a good job of explaining how the recycling mechanism works. Now coming on to your case, whenever getView gets called in your adapter, you are kick starting a new AsyncTask that downloads the image at the given url and sets it in the imageView inside WrapperRow.

Let's see why exactly the views flicker. Consider that you have a wrapper rows - wr1, wr2, wr3 .... wr8 and they get recycled by the listView (i arbitrarily chose to explain with 8 rows. the listView could use less or more). As soon as getView gets called the first time, you inflate a wrapper row (wr1) and then pass it to the AsyncTask which downloads the image & then sets it. Now you scroll through the list and the same process takes place for views wr2 to wr8 and on further scrolling it is time to recycle the views and wr1 comes into play again. You kick start another asyncTask to download the image but you never cleared the imageView (it already holds the first image now) and when the task is done downloading it sets the new image in imageview and this is when you an image disappearing and a new image showing up. When you scroll through the list, you see this happening repeatedly for all the rows!!

You could use any of the libraries like Picasso or UIL, but if you wanna spin up your own implementation remember these things

  • Don't hold on to strong references of views in asyncTasks (this would prevent the activity instance from GC even if it gets destroyed leading to memory leaks)
  • Whenever you start a new asyncTask make sure to cancel the previous asyncTask (if any) that still works with this view
  • And it always better to use caches (memory & disk)
Community
  • 1
  • 1
x-treme
  • 1,606
  • 2
  • 21
  • 39