Android - ListView with scrollable images is not smooth
I am trying to show a ListView with products. Products is a SQLite table with title, quantity and image (BLOB). Therefore my ListView is not smooth.
What I have tried:
- Open camera intent, capture, get additional functionality and insert into SQLite. So I only used one bitmap. This method worked fine until the number of Products was less than 50.
I went the other way:
- Open camera intent, capture and save to file.
- Check
ExifInterface
and rotate the image if necessary. - Scale using http://developer.android.com/training/displaying-bitmaps/load-bitmap.html to 300x300 and move to my folder. This image file is for full screen mode.
- Now I will need a sketch in order to put it in the ListView in the future. So I scale the file (3) to thumbnail size (for example 60x60) using the method
setPic()
from http://developer.android.com/training/camera/photobasics.html and save that little thumb in the products SQLite database .
Now the ListView scrolls when the number of Products exceeds 100. This is not a problem.
So I need a slightly different way to fill the ListView with images.
Please guide me correctly)))
Thank!
PS I am using a custom SimpleCursorAdapter to display 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;
}
source to share
Ok guys, I tried almost all the methods you suggested. And here is my report:
-
@HareshChhelana's method uses the
inSampleSize
(fromBitmapFactory.Options
) parameter . The method is better and then save a small thumbnail in SQLite (as I did at the beginning), but became not smooth for over 200 list items with images -
@ Close suggestion to use google solution ( http://developer.android.com/training/displaying-bitmaps/process-bitmap.html ). This also works great.
-
Paging from @ Prachi. Works fine. But I didn't add any logic to load the next batch in the listview onscroll. My solution was: extract the first 30 rows and use the "Next 30 rows" and "Prev 30 rows" buttons. Since this method was the last solution for me, if no one is using no pagination won't work, I'll skip it. :)
-
@ Pankaj's suggestion. I went through this class and it looks like a working solution , but I haven't tried it. The answer is helpful anyway.
I found a library that I used in my project: https://github.com/nostra13/Android-Universal-Image-Loader This is really cool and has a lot of useful settings!
PS Sorry for my english :)
source to share
Trying to load images from the UI thread - using 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 change
if (byteArray != null) {
BitmapWorkerTask task = new BitmapWorkerTask(imageView);
task.execute(mainCursor);
}else{......}
source to share
Use a lazy list to load the image into the listview. Link link: http://www.prandroid.com/2014/07/how-to-lazy-load-of-images-in-listview.html
source to share
Use pagination..fetch 5/10 lines and for loading 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;
}
}
}
});
source to share
Load all bitmaps outside of getview () either into the constructor or rather from an external adapter and then assign it to the adapter. Loading an image every time from the database when creating a view can slow down scrolling.
If you are experiencing a memory problem In prelate mode, images try to cache them in memory instead of saving them to the database
source to share