Adrian
Adrian

Reputation: 360

Loading large Images into Listview

So my Listview has been lagging, because I am loading too many Pictures into it. So I searched the web and found two particular ideas to solve the problem:

  1. using a AsyncTask, as mentioned here
  2. downscaling the images, as mentioned here

So since I am new to Developing with Android I gave the AsyncTask a shot and failed. The examples I have seen, were mostly using URLs to download pictures, and since I am using a sqlite DB I just couldn't get the examples to work for me.

So here is my try:

static class ViewHolder {
    TextView imageTextView;
    ImageView favImageView;
    int position;
}

//Constructor for List Items
private class favImagesListAdapter extends ArrayAdapter<FavImages>{
    private LayoutInflater mInflater = LayoutInflater.from(context);

    public favImagesListAdapter(){
        super (MainActivity.this, R.layout.listview_item, FavImages);
    }



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

        ViewHolder holder;

        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.listview_item, parent, false);
            holder = new ViewHolder();
            holder.imageTextView = (TextView) convertView.findViewById(R.id.favName);
            holder.favImageView = (ImageView) convertView.findViewById(R.id.favImage);

            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        FavImages currentFav = FavImages.get(position);

        holder.imageTextView.setText(currentFav.getImageName());

        new AsyncTask<ViewHolder, Void, Bitmap>() {
            private ViewHolder v;


            @Override
            protected Bitmap doInBackground(ViewHolder... params) {
                v = params[0];
                return mFakeImageLoader.getImage();
            }

            @Override
            protected void onPostExecute(Bitmap result) {
                super.onPostExecute(result);
                if (v.position == position) {
                    // If this item hasn't been recycled already, hide the
                    // progress and set and show the image
                    //v.progress.setVisibility(View.GONE);
                    v.favImageView.setVisibility(View.VISIBLE);
                    v.favImageView.setImageBitmap(result);
                }
            }
        }.execute(holder);

        //old Version that causes lags
            ContentResolver cr = getContentResolver();
            try {
                holder.favImageView.setImageBitmap(MediaStore.Images.Media.getBitmap(cr, currentFav.getImagePath()));
            } catch (IOException e) {
                e.printStackTrace();
            }


        return convertView;
    }
}

Since I didn't have a reference what the FakeImageLoader does, I tried to reduce the size of the Images in there, but it didn't work, so I took a reference Code I found on a google Site like so:

public class FakeImageLoader {
private Bitmap mBmp;

public FakeImageLoader(Context cxt)
{
    mBmp= BitmapFactory.decodeResource(cxt.getResources(), R.drawable.ic_launcher);
}


public Bitmap getImage()
{
    try {
        Thread.sleep(new Random().nextInt(5000));
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
    return mBmp;
}
}

But using that class just caused errors (because used for something totally different?).

So I am asking, what do I need the FakeImageLoader (maybe not that good of a name) to do, to load the images best (guessing just have to scale the images down) and mostly how do I do it.

I have also read about Picasso, but I want to keep the App small and learn by doing (or asking). If more code helps I will do so if asked.

Edit:

Using the FakeImageLoader class did not work (actually pretty obvious), so I changed my whole ListAdapter with the Asynctask to this:

static class ViewHolder {
    TextView imageTextView;
    ImageView favImageView;
    int position;
}

//Constructor for List Items
private class favImagesListAdapter extends ArrayAdapter<FavImages>{
    private LayoutInflater mInflater = LayoutInflater.from(context);

    public favImagesListAdapter(){
        super (MainActivity.this, R.layout.listview_item, FavImages);
    }



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

        ViewHolder holder;

        if (convertView == null) {
            convertView = mInflater.inflate(R.layout.listview_item, parent, false);
            holder = new ViewHolder();
            holder.imageTextView = (TextView) convertView.findViewById(R.id.favName);
            holder.favImageView = (ImageView) convertView.findViewById(R.id.favImage);

            convertView.setTag(holder);
        } else {
            holder = (ViewHolder) convertView.getTag();
        }

        final FavImages currentFav = FavImages.get(position);

        holder.imageTextView.setText(currentFav.getImageName());

        class MyAsyncTask extends AsyncTask<ViewHolder, Void, Bitmap> {
            private ViewHolder v;

            @Override
            protected Bitmap doInBackground(ViewHolder... params) {
                v = params[0];
                return getImage();
            }

            private Bitmap getImage() {
                Bitmap mBmp;
                ContentResolver cr = getContentResolver();
                MainActivity.ViewHolder holder = null;
                com.adrianopaulus.favoriten.FavImages currentFav1 = FavImages.get(position);
                try {
                    mBmp = holder.favImageView.setImageBitmap(MediaStore.Images.Media.getBitmap(cr, currentFav1.getImagePath()));
                    return mBmp;
                } catch (FileNotFoundException e) {
                    e.printStackTrace();
                    return null;
                } catch (IOException e) {
                    e.printStackTrace();
                    return null;
                }
            //return mBmp;
            }

            @Override
            protected void onPostExecute(Bitmap result) {
                super.onPostExecute(result);
                if (v.position == position) {
                    // If this item hasn't been recycled already, hide the
                    // progress and set and show the image
                    //v.progress.setVisibility(View.GONE);
                    v.favImageView.setVisibility(View.VISIBLE);
                    v.favImageView.setImageBitmap(result);
                }
            }
        }MyAsyncTask.execute((Runnable) holder);

        return convertView;
    }
}

But it some has a Problem with following line:

mBmp = holder.favImageView.setImageBitmap(MediaStore.Images.Media.getBitmap(cr, currentFav1.getImagePath()));

and I don't know what I am doing wrong.

Upvotes: 0

Views: 1070

Answers (2)

Adam
Adam

Reputation: 51

//Lazy Loading for image loading for Aquery.

//Try to use a query to load image in a listview

http://programmerguru.com/android-tutorial/introduction-to-aquery-android-query/

        AQuery aq = aq = new AQuery(convertView);
        // id means -> ImageView object or Imageview id
        // path means-> Url of Image.
        //Download a jar file, Copy and Past into a lib folder.
        aq.id(imgDisplay).image(path,true, true, 0,R.drawable.default_image, null,AQuery.CACHE_DEFAULT,0.0f).visible(); 

Upvotes: 0

Fahim
Fahim

Reputation: 12358

Make use of Universal image loader library. This load images asynchronously and it doesn't lags your listview.

https://github.com/nostra13/Android-Universal-Image-Loader

It has an example in it.

Enjoy :)

Upvotes: 1

Related Questions