0

I am using a listview and each items use an image called from a server with an asynctask class.

@Override
public View getView(final int position, View convertView, ViewGroup parent) {
        View view = convertView;
        final ViewHolder viewHolder;

        if (view == null) {
            view = getActivity().getLayoutInflater().inflate(R.layout.item_liste, null);
            viewHolder = new ViewHolder();
            viewHolder.image = (ImageView) view.findViewById(R.id.imageView);
            view.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) view.getTag();
        }

        if (/* Image not loaded */) {

            /* Create and execute the request using an AsyncTask */
            mRequestManager.getDrawable("0", listItemInformation.resumeBien.Identifiant, new SendBitmap() {

                /* SendBack is called when the bitmap is received from the server */

                @Override
                public void sendBack(Bitmap bitmap) {
                    listItemInformation.drawable.add(bitmap);
                    listItemInformation.drawableCalled = false;
                    viewHolder.image.setImageBitmap(bitmap);
                } 
           });
        } else {
            viewHolder.image.setImageBitmap(listItemInformation.drawable.get(0));
        }

        return view;
    }

The problem is, when the image is received, the ImageView is not the good one. And all the pictures are loaded in the first item of the listview..

I tried to use adapter.notifyDataSetChanged();

But the listview motion is cut when it is called during a scroll..

What are my possibilities to avoid those issues? I want the same result as the googleplay's listview.

Thanks in advance :)

nsvir
  • 8,781
  • 10
  • 32
  • 47
  • 1
    You could use an image loading library like Universal Image Loader to help you with loading of images. It will save you a bunch of the legwork with writing code to properly queue up downloading and displaying of images. – dymmeh Nov 14 '13 at 16:27
  • can you post the rest of your `Adapter`? are you sure you have the correct number of items being returned by `getCount()`? – Emmanuel Nov 14 '13 at 16:38

2 Answers2

2

You can try Volley's NetworkImageView with just one or two lines to complete your job.

     //Dummy:

    public static class BitmapLruCache extends LruCache<String, Bitmap> implements ImageCache {

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


    @Override
    protected int sizeOf(String key, Bitmap value) {
        return value.getRowBytes() * value.getHeight();
    }


    @Override
    public Bitmap getBitmap(String url) {
        return get(url);
    }


    @Override
    public void putBitmap(String url, Bitmap bitmap) {
        put(url, bitmap);
    }
  }

    ImageLoader sImageLoader = new ImageLoader(sRequestQueue, new BitmapLruCache(100));

    networkImageView.setImageUrl(url_to_image, sImageLoader);
TeeTracker
  • 7,064
  • 8
  • 40
  • 46
  • I have some difficulties with the lib. Could you help me ? http://stackoverflow.com/questions/20059576/import-android-volley-to-android-studio – nsvir Nov 18 '13 at 23:59
  • @TeeTracker I am having problem with [http://stackoverflow.com/questions/30850315/volley-is-losing-images-from-imageview-after-scrolling-list-up-down]. – Roon13 Jun 16 '15 at 14:28
1

what you need is called "Lazy adapter", to load images in list view you can try my code:

public class MainActivity extends Activity {

ListView list;
LazyAdapter adapter;

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.main);

    list=(ListView)findViewById(R.id.list);
    adapter=new LazyAdapter(this, mStrings);
    list.setAdapter(adapter);
    adapter.imageLoader.clearCache();
    adapter.notifyDataSetChanged();

    list.setOnItemClickListener(new AdapterView.OnItemClickListener() {

        @Override
        public void onItemClick(AdapterView<?> parent, View view,
                                int position, long id) {
            //Toast.makeText(getApplicationContext(), id + "", 2000).show();
            String wallcategory =(String) ((TextView) view.findViewById(R.id.text)).getText();
            //Toast.makeText(getApplicationContext(),mStrings[position], 2000).show();


            Intent myIntent = new Intent(MainActivity.this, Wallgrid.class);
           myIntent.putExtra("cat", wallcategory); //Optional parameters
            MainActivity.this.startActivity(myIntent);


        }
    });
}

@Override
public void onDestroy()
{
    list.setAdapter(null);
    super.onDestroy();
}



public String[] mStrings={
        "http://www.bourax.com/android/paradise/categories/nature.jpg",
        "http://www.bourax.com/android/paradise/categories/animals.jpg",
        "http://www.bourax.com/android/paradise/categories/colorful.jpg",
        "http://www.bourax.com/android/paradise/categories/cars.jpg",
        "http://www.bourax.com/android/paradise/categories/city.jpg",
        "http://www.bourax.com/android/paradise/categories/flowers.jpg",
        "http://www.bourax.com/android/paradise/categories/girls.jpg",
        "http://www.bourax.com/android/paradise/categories/sport.jpg",
        "http://www.bourax.com/android/paradise/categories/cats.jpg",
        "http://www.bourax.com/android/paradise/categories/fish.jpg",
        "http://www.bourax.com/android/paradise/categories/sea.jpg",
        "http://www.bourax.com/android/paradise/categories/love.jpg",
        "http://www.bourax.com/android/paradise/categories/buildings.jpg",
        "http://www.bourax.com/android/paradise/categories/paintings.jpg",
        "http://www.bourax.com/android/paradise/categories/pink.jpg",
        "http://www.bourax.com/android/paradise/categories/travel.jpg",
        "http://www.bourax.com/android/paradise/categories/fantasy.jpg",
        "http://www.bourax.com/android/paradise/categories/tree.jpg",
        "http://www.bourax.com/android/paradise/categories/portrait.jpg",
        "http://www.bourax.com/android/paradise/categories/top.jpg"



};

}

public class LazyAdapter extends BaseAdapter {

private Activity activity;
private String[] data;
private static LayoutInflater inflater=null;
public ImageLoader imageLoader; 

public LazyAdapter(Activity a, String[] d) {
    activity = a;
    data=d;
    inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    imageLoader=new ImageLoader(activity.getApplicationContext());
}

public int getCount() {
    return data.length;
}

public Object getItem(int position) {
    return position;
}

public long getItemId(int position) {
    return position;
}
public String[] Category={
        "Nature",
        "Animals",
        "Colorful",
        "Cars",
        "City",
        "Flowers",
        "Girls",
        "Sport",
        "Cats & Dogs",
        "Fish",
        "Sea",
        "Love",
        "Buildings",
        "Paintings",
        "Pink",
        "Travel",
        "Fantasy",
        "Tree",
        "Portrait",
        "Top Rated"


};
public View getView(int position, View convertView, ViewGroup parent) {

    View vi=convertView;
    if(convertView==null)
        vi = inflater.inflate(R.layout.item, null);

    TextView text=(TextView)vi.findViewById(R.id.text);
    ImageView image=(ImageView)vi.findViewById(R.id.image);
    text.setText(Category[position]);
    imageLoader.DisplayImage(data[position], image);
    return vi;
}
}




 public class ImageLoader {

MemoryCache memoryCache=new MemoryCache();
FileCache fileCache;
private Map<ImageView, String> imageViews=Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
ExecutorService executorService;
Handler handler=new Handler();//handler to display images in UI thread

public ImageLoader(Context context){
    fileCache=new FileCache(context);
    executorService=Executors.newFixedThreadPool(5);
}

final int stub_id=R.drawable.stub;
public void DisplayImage(String url, ImageView imageView)
{
    imageViews.put(imageView, url);
    Bitmap bitmap=memoryCache.get(url);
    if(bitmap!=null)
        imageView.setImageBitmap(bitmap);
    else
    {
        queuePhoto(url, imageView);
        //imageView.setImageResource(stub_id);
    }
}

private void queuePhoto(String url, ImageView imageView)
{
    PhotoToLoad p=new PhotoToLoad(url, imageView);
    executorService.submit(new PhotosLoader(p));
}

private Bitmap getBitmap(String url) 
{
    File f=fileCache.getFile(url);

    //from SD cache
    Bitmap b = decodeFile(f);
    if(b!=null)
        return b;

    //from web
    try {
        Bitmap bitmap=null;
        URL imageUrl = new URL(url);
        HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection();
        conn.setConnectTimeout(30000);
        conn.setReadTimeout(30000);
        conn.setInstanceFollowRedirects(true);
        InputStream is=conn.getInputStream();
        OutputStream os = new FileOutputStream(f);
        Utils.CopyStream(is, os);
        os.close();
        conn.disconnect();
        bitmap = decodeFile(f);
        return bitmap;
    } catch (Throwable ex){
       ex.printStackTrace();
       if(ex instanceof OutOfMemoryError)
           memoryCache.clear();
       return null;
    }
}

//decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f){
    try {
        //decode image size
        BitmapFactory.Options o = new BitmapFactory.Options();
        o.inJustDecodeBounds = true;
        FileInputStream stream1=new FileInputStream(f);
        BitmapFactory.decodeStream(stream1,null,o);
        stream1.close();

        //Find the correct scale value. It should be the power of 2.
        final int REQUIRED_SIZE=70;
        int width_tmp=o.outWidth, height_tmp=o.outHeight;
        int scale=1;
        while(true){
            if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
                break;
            width_tmp/=2;
            height_tmp/=2;
        }

        //decode with inSampleSize
        BitmapFactory.Options o2 = new BitmapFactory.Options();
        o2.inSampleSize=scale;
        FileInputStream stream2=new FileInputStream(f);
        Bitmap bitmap=BitmapFactory.decodeStream(stream2, null, o2);
        stream2.close();
        return bitmap;
    } catch (FileNotFoundException e) {
    } 
    catch (IOException e) {
        e.printStackTrace();
    }
    return null;
}

//Task for the queue
private class PhotoToLoad
{
    public String url;
    public ImageView imageView;
    public PhotoToLoad(String u, ImageView i){
        url=u; 
        imageView=i;
    }
}

class PhotosLoader implements Runnable {
    PhotoToLoad photoToLoad;
    PhotosLoader(PhotoToLoad photoToLoad){
        this.photoToLoad=photoToLoad;
    }

    @Override
    public void run() {
        try{
            if(imageViewReused(photoToLoad))
                return;
            Bitmap bmp=getBitmap(photoToLoad.url);
            memoryCache.put(photoToLoad.url, bmp);
            if(imageViewReused(photoToLoad))
                return;
            BitmapDisplayer bd=new BitmapDisplayer(bmp, photoToLoad);
            handler.post(bd);
        }catch(Throwable th){
            th.printStackTrace();
        }
    }
}

boolean imageViewReused(PhotoToLoad photoToLoad){
    String tag=imageViews.get(photoToLoad.imageView);
    if(tag==null || !tag.equals(photoToLoad.url))
        return true;
    return false;
}

//Used to display bitmap in the UI thread
class BitmapDisplayer implements Runnable
{
    Bitmap bitmap;
    PhotoToLoad photoToLoad;
    public BitmapDisplayer(Bitmap b, PhotoToLoad p){bitmap=b;photoToLoad=p;}
    public void run()
    {
        if(imageViewReused(photoToLoad))
            return;
        if(bitmap!=null)
            photoToLoad.imageView.setImageBitmap(bitmap);
       // else
           // photoToLoad.imageView.setImageResource(stub_id);
    }
}

public void clearCache() {
    memoryCache.clear();
    fileCache.clear();
}

}



 public class FileCache {

private File cacheDir;

public FileCache(Context context){
    //Find the dir to save cached images
    if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
        cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),"LazyList");
    else
        cacheDir=context.getCacheDir();
    if(!cacheDir.exists())
        cacheDir.mkdirs();
}

public File getFile(String url){
    //I identify images by hashcode. Not a perfect solution, good for the demo.
    String filename=String.valueOf(url.hashCode());
    //Another possible solution (thanks to grantland)
    //String filename = URLEncoder.encode(url);
    File f = new File(cacheDir, filename);
    return f;

}

public void clear(){
    File[] files=cacheDir.listFiles();
    if(files==null)
        return;
    for(File f:files)
        f.delete();
}

}
bourax webmaster
  • 748
  • 7
  • 18