问题
I have created an custom ListView
in which i display image as an list Item. The image i display as a list item is stored in my InternalStorage
of the device, What i notice is when number of item is more then seven the list view scroll become slow and the items in the ListView
jerk while scrolling. Is anything wrong in my code, or miss something to do in my code. Please help me to solve this out.
Code for displaying List View item
public class ListViewAdapter extends BaseAdapter
{
private Activity activity;
private ArrayList<String> fileNameArray;
private LayoutInflater inflater=null;
public ImageLoader imageLoader;
public ListViewAdapter(Activity a, ArrayList<String> d)
{
activity = a;
fileNameArray = d;
inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
imageLoader = new ImageLoader(activity.getApplicationContext());
}
public int getCount()
{
return fileNameArray.size();
}
public Object getItem(int position)
{
return position;
}
public long getItemId(int position)
{
return position;
}
public class ViewHolder
{
ImageView image;
}
public View getView(final int position, View convertView, ViewGroup parent)
{
ViewHolder holder;
if(convertView == null)
{
holder = new ViewHolder();
convertView = inflater.inflate(R.layout.page_list_item, null);
holder.image = (ImageView)convertView.findViewById(R.id.image);
convertView.setTag(holder);
}
else
{
holder = (ViewHolder)convertView.getTag();
}
// Load image from internalstoarage and display in image view
imageLoader.DisplayImage(m_DirectoryPath.getPath() + "/" + fileNameArray.get(position), holder.image, true);
return convertView;
}
}
Code for image loader class
public class ImageLoader
{
MemoryCache memoryCache = new MemoryCache();
private Map<ImageView, String> imageViews=Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
ExecutorService executorService;
Context m_context;
public ImageLoader(Context context)
{
m_context = context;
executorService = Executors.newFixedThreadPool(5);
}
public void DisplayImage(String url, ImageView imageView, boolean useCachedImage)
{
imageViews.put(imageView, url);
Bitmap bitmap = memoryCache.get(url);
if(bitmap!=null && useCachedImage)
{
imageView.setImageBitmap(bitmap);
}
else
{
queuePhoto(url, imageView);
}
}
private void queuePhoto(String url, ImageView imageView)
{
PhotoToLoad p = new PhotoToLoad(url, imageView);
executorService.submit(new PhotosLoader(p));
}
private Bitmap getBitmap(String url)
{
File filePath = new File(url);
// from internal storage cache
Bitmap b = decodeFile(filePath);
if (b != null)
{
return b;
}
return null;
}
// decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File filePath)
{
try
{
// decode image size
int Required_Height = 0;
BitmapFactory.Options option = new BitmapFactory.Options();
Bitmap bitmap = BitmapFactory.decodeStream(new FileInputStream(filePath), null, option);
WindowManager wm = (WindowManager) m_context.getSystemService(Context.WINDOW_SERVICE);
Display display = wm.getDefaultDisplay();
if(display.getWidth() == 480)
{
Required_Height = 150;
}
else if(display.getWidth() == 800)
{
Required_Height = 200;
}
bitmap = Bitmap.createBitmap(bitmap, 0, 0, option.outWidth, Required_Height);
return bitmap;
}
catch (FileNotFoundException e){
}
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()
{
if(imageViewReused(photoToLoad))
return;
Bitmap bmp = getBitmap(photoToLoad.url);
memoryCache.put(photoToLoad.url, bmp);
if(imageViewReused(photoToLoad))
return;
BitmapDisplayer bd = new BitmapDisplayer(bmp, photoToLoad);
Activity a = (Activity)photoToLoad.imageView.getContext();
a.runOnUiThread(bd);
}
}
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);
}
}
public void clearCache()
{
memoryCache.clear();
}
}
回答1:
You have to setPriority for PhotosLoader thread object. I am doing it in constructor like this.
// Make the background thread low priority. This way it will not affect the UI performance
mImageRequstController.setPriority(Thread.NORM_PRIORITY - 1);
By make priority less then normal , it will not effect the UI and will continue its working in background.
回答2:
What's happening is that, for speed reasons, list items out of view are not loaded until needed. When the user scrolls the list item into view, it is loaded. However, loading an image from the SD card is a time consuming action, enough that the user can see a lag.
Your code loads the images on the UI thread, blocking it from updating and smoothly scrolling the list. Instead, you should be loading the images on another thread, while the list item on the UI thread should display only a progress spinner or some other loading indicator until the image is loaded. And, like the list, the threads should only be started once the list item is in view, not all at once.
来源:https://stackoverflow.com/questions/12085405/listview-scroll-slow-while-loading-image-from-internal-storage