ListView scroll slow while loading image from Internal Storage

…衆ロ難τιáo~ 提交于 2019-12-23 03:45:10

问题


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

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!