从内部存储加载图像时ListView滚动速度慢

时间:2012-08-23 05:43:05

标签: android android-listview

我创建了一个自定义ListView,其中我将图像显示为列表项。我作为列表项显示的图像存储在设备的InternalStorage中,当项目数超过7时,我注意到列表视图滚动变慢,ListView混蛋中的项目滚动时。我的代码中有什么问题,或者在我的代码中遗漏了一些事情。请帮我解决这个问题。

显示列表视图项的代码

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;
        }
}

图像加载器类代码

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();
    }

}

2 个答案:

答案 0 :(得分:1)

您必须为 PhotosLoader 线程对象设置setPriority。我在像这样的构造函数中这样做。

// Make the background thread low priority. This way it will not affect the UI performance
mImageRequstController.setPriority(Thread.NORM_PRIORITY - 1);

通过优先级低于正常值,它不会影响用户界面并继续在后台运行。

答案 1 :(得分:0)

正在发生的事情是,出于速度原因,在需要之前不会加载视图之外的列表项。当用户将列表项滚动到视图中时,它将被加载。但是,从SD卡加载图像是一项耗时的操作,足以让用户看到延迟。

您的代码会加载UI线程上的图像,阻止其更新并平滑滚动列表。相反,您应该在另一个线程上加载图像,而UI线程上的列表项应该只显示进度微调器或一些其他加载指示器,直到加载图像。并且,与列表一样,只有在列表项处于视图中时才应启动线程,而不是一次全部启动。