Romowski
Romowski

Reputation: 1548

Android - ListView with images scrolls not smooth

I'm trying to to show a ListView with goods. Goods is a SQLite table with title, count and image (BLOB). So my ListView is not smooth.

What have I tried:

  1. Open camera intent, capture, get Extras and insert to SQLite. So I have used only one bitmap. This method worked fine until number of Goods was less then 50.

I went by another way:

  1. Open camera intent, capture and save to file.
  2. Checking ExifInterface and rotate image if needed.
  3. Scale using http://developer.android.com/training/displaying-bitmaps/load-bitmap.html to the size 300x300 and moving to my folder. This image file is for fullscreen.
  4. Now I need a thumbnail to put it into ListView in future. So I scale file(3) to thumbnail size (for example 60x60) using setPic() method from http://developer.android.com/training/camera/photobasics.html and save this small thumb to SQLite database Goods table.

Now ListView become scrolling hard when number of Goods is over 100. And this is not the problem solution.

So I need some different way to fill ListView with images.

Please, direct me in right way )))

Thanks!

P.S. I'm using custom SimpleCursorAdapter to show data:

public class GoodsCursorAdapter extends SimpleCursorAdapter {
    public GoodsCursorAdapter(Context context) {
        super(context, R.layout.cell_goods, null,
                new String[] { "title", "countAvail" },
                new int[] { R.id.lbTitle, R.id.lbCount }, 0);

    }

    private class ViewHolder {
        ImageView imageView;
        TextView lbTitle, lbCount;
    }

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

        ViewHolder viewHolder;

        if (convertView == null){
            LayoutInflater inflater = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = inflater.inflate(R.layout.cell_goods, parent, false);
            viewHolder = new ViewHolder();
            viewHolder.imageView = (ImageView) convertView.findViewById(R.id.ivThumb);
            viewHolder.lbTitle = (TextView) convertView.findViewById(R.id.lbTitle);
            viewHolder.lbCount = (TextView) convertView.findViewById(R.id.lbCount);
            convertView.setTag(viewHolder);
        } else {
            viewHolder = (ViewHolder) convertView.getTag();
        }

        mainCursor.moveToPosition(position);
        byte[] byteArray = mainCursor.getBlob(mainCursor.getColumnIndex("photo"));
        if (byteArray != null) {
            Bitmap bitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
            Log.d("INFO", mainCursor.getString(mainCursor.getColumnIndex("title"))+": "+String.valueOf(bitmap.getWidth())+"x"+String.valueOf(bitmap.getHeight())+"("+String.valueOf(bitmap.getByteCount()/1024)+"Kb)");
            viewHolder.imageView.setImageBitmap(bitmap);
        } else {
            viewHolder.imageView.setImageResource(R.drawable.ic_action_picture);
        }
        viewHolder.lbTitle.setText(mainCursor.getString(mainCursor.getColumnIndex("title")));
        viewHolder.lbCount.setText(String.format(getString(R.string.lbCount), mainCursor.getString(mainCursor.getColumnIndex("countAvail"))));

        return convertView;
    }

Upvotes: 3

Views: 2558

Answers (5)

Romowski
Romowski

Reputation: 1548

Ok guys, I have tried almost all methods you suggested. And here is my report:

  1. @HareshChhelana's method is use inSampleSize option (from BitmapFactory.Options). Method is better then storing small thumbnail in SQLite (as I have done first), but become not smooth for more then 200 list items with images

  2. @Zain's suggestion to use Google solution (http://developer.android.com/training/displaying-bitmaps/process-bitmap.html). This also works fine.

  3. Pagination from @Prachi. Works fine. But I did not add any logic to load next batch on listview's onscroll. My solution was: fetch first 30 rows and as use "Next 30 rows" and "Prev 30 rows" button. As this method was the last solution for me if no one methods without pagination won't work, I skip it. :)

  4. @Pankaj's suggestion. I walked through this class and it looks like working solution, but I did not try it. Anyway answer is useful.

I have found a library, which I used in my project: https://github.com/nostra13/Android-Universal-Image-Loader It's really great and have a lot of useful settings!

P.S. Sorry for my english :)

Upvotes: 0

Zain
Zain

Reputation: 2372

Trying loading the images off the UI thread - using an AsyncTask.

Something like this (taken from here)

class BitmapWorkerTask extends AsyncTask<Cursor, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
private Cursor mCursor;;

public BitmapWorkerTask(ImageView imageView) {
    // Use a WeakReference to ensure the ImageView can be garbage collected
    imageViewReference = new WeakReference<ImageView>(imageView);
}

// Decode image in background.
@Override
protected Bitmap doInBackground(Cursor... params) {
    mCursor = params[0];
    byte[] byteArray = mCursor.getBlob(mCursor.getColumnIndex("photo"));
    if (byteArray != null) {
     Bitmap bitmap = BitmapFactory.decodeByteArray(byteArray, 0, byteArray.length);
    return bitmap;
  }
}

// Once complete, see if ImageView is still around and set bitmap.
@Override
protected void onPostExecute(Bitmap bitmap) {
    if (imageViewReference != null && bitmap != null) {
        final ImageView imageView = imageViewReference.get();
        if (imageView != null) {
            imageView.setImageBitmap(bitmap);
        }
    }
  }
}

So modify

 if (byteArray != null) {     
  BitmapWorkerTask task = new BitmapWorkerTask(imageView);
  task.execute(mainCursor);
 }else{......}

Upvotes: 2

Prachi
Prachi

Reputation: 2559

Use pagination ..fetch 5/10 rows and to load bitmaps use Picasso or you can load bitmap in async

EDIT

mListView.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {
                if (scrollState == 1) {
                    isUserScroll = true;
                } else {
                    isUserScroll = false;
                }
            }

            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {

                if (isUserScroll) {

                    int lastInScreen = firstVisibleItem + visibleItemCount;
                    if (!isDataLoading && (lastInScreen == totalItemCount)) {
                       //load data

                        isDataLoading = true;
                    }
                }
            }
        });

Upvotes: 1

Pankaj
Pankaj

Reputation: 861

Use lazy list for downloading image in listview. Ref link: http://www.prandroid.com/2014/07/how-to-lazy-load-of-images-in-listview.html

Upvotes: 1

amodkanthe
amodkanthe

Reputation: 4530

Load all bitmaps outside getview() either in constructor or rather outside adapter then assign it to adapter. Loading image every time from database when view is created may slow down the scroll.

In case you face any memory issue In preloding Images try caching them on memory instead of saving to database

Upvotes: 0

Related Questions