在Picasso Image loader中加载位图图像会减慢列表视图中的滚动速度

时间:2015-07-04 08:16:25

标签: android listview android-listview android-imageview picasso

我正在尝试生成sdcard文件夹中找到的所有视频的缩略图,并使用Picasso Image loader在listview中填充所有生成的位图。一切正常,但它非常慢,我无法滚动浏览它的滞后非常缓慢。我在该列表视图中有大约150个视图。任何帮助?谢谢,谢谢。

public class VideoFilesAdapter extends ArrayAdapter<String> {
    private List<String> mpath;
    private Context mContext;
    public static ArrayList<String> mSelectedPaths = null;

    public VideoFilesAdapter(Context context, List<String> path) {
        super(context, R.layout.fileadapter_list, path);
        this.mContext = context;
        this.mpath = path;
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        if (convertView == null) {
            LayoutInflater mInflater = (LayoutInflater) mContext
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            convertView = mInflater.inflate(R.layout.fileadapter_list, null);
        }
        TextView txtTitle = (TextView) convertView.findViewById(R.id.txt);
        ImageView imageView = (ImageView) convertView.findViewById(R.id.img);

        File file = new File(mpath.get(position));

        if (file.exists()) {

            txtTitle.setText(file.getName());

            Bitmap bitmap = ThumbnailUtils.createVideoThumbnail(
                    file.getAbsolutePath(),
                    MediaStore.Video.Thumbnails.MICRO_KIND);

            Picasso.with(mContext).load(getImageUri(mContext, bitmap))
                    .centerInside().resize(100, 100)
                    .placeholder(R.drawable.holder).error(R.drawable.error)
                    .into(imageView);

        }

        return convertView;
    }

    public Uri getImageUri(Context inContext, Bitmap inImage) {
        ByteArrayOutputStream bytes = new ByteArrayOutputStream();
        inImage.compress(Bitmap.CompressFormat.JPEG, 20, bytes);
        String path = Images.Media.insertImage(inContext.getContentResolver(),
                inImage, "Title", null);
        return Uri.parse(path);
    }

}

2 个答案:

答案 0 :(得分:0)

<强>更新 它看起来不像是以任何方式存储/缓存这些位图,所以它一遍又一遍地进行。试试这里找到的解决方案:Video thumbnail arrayadopter is slow on scroll

我不认为毕加索正在减慢你ListView的滚动速度。您的列表项有多复杂?如果它们嵌套了许多视图,那可能是它,我在ListView中有超过700个项目没有性能问题。

答案 1 :(得分:0)

在我查看代码时,我看到每次调用TextViewImageViewgetView都会被充气。通货膨胀是一项非常昂贵的任务,因此我们希望尽可能避免使用它。

在任何其他事项之前确保您将在Gradle中声明它

compile 'com.android.support:support-v4:21.0.0'

VideoFilesAdapter.java

中添加此辅助类
 class Helper {
        public TextView textView;
        public ImageView image;
  }

然后我们将使用LRUcache存储图像,这样我们就可以一遍又一遍地使用这个图像而无需做太多任务。

在项目中添加MyLRU.java

import android.content.Context;
import android.graphics.Bitmap;
import android.support.v4.util.LruCache;

public class MyLRU {

    private LruCache<String, Bitmap> cache = null;
    private static MyLRU myLru = null;

    private MyLRU() {
        int availableMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
        cache = new LruCache<String, Bitmap>(availableMemory / 8) {
            @Override
            protected int sizeOf(String key, Bitmap value) {
                // this is the only way to get the Bitmap size below API 12
                return (value.getRowBytes() * value.getHeight()) / 1024;
            }
        };
    }

    public static MyLRU getInstance() {
        if (myLru == null) {
            myLru = new MyLRU();
        }
        return myLru;
    }

    public void addImage(String key, Bitmap image) {
        myLru.addImage(key, image);
    }

    public Bitmap getImage(String key) {
        return myLru.getImage(key);
    }

}

VideoFilesAdapter.java

中添加实用程序方法
public static Bitmap scaleCenterCrop(Bitmap source, int newHeight, int newWidth) {
        int sourceWidth = source.getWidth();
        int sourceHeight = source.getHeight();

        // Compute the scaling factors to fit the new height and width, respectively.
        // To cover the final image, the final scaling will be the bigger
        // of these two.
        float xScale = (float) newWidth / sourceWidth;
        float yScale = (float) newHeight / sourceHeight;
        float scale = Math.max(xScale, yScale);

        // Now get the size of the source bitmap when scaled
        float scaledWidth = scale * sourceWidth;
        float scaledHeight = scale * sourceHeight;

        // Let's find out the upper left coordinates if the scaled bitmap
        // should be centered in the new size give by the parameters
        float left = (newWidth - scaledWidth) / 2;
        float top = (newHeight - scaledHeight) / 2;

        // The target rectangle for the new, scaled version of the source bitmap will now
        // be
        RectF targetRect = new RectF(left, top, left + scaledWidth, top + scaledHeight);

        // Finally, we create a new bitmap of the specified size and draw our new,
        // scaled bitmap onto it.
        Bitmap dest = Bitmap.createBitmap(newWidth, newHeight, source.getConfig());
        Canvas canvas = new Canvas(dest);
        canvas.drawBitmap(source, null, targetRect, null);

        return dest;
    }

以下是VideoFilesAdapter.java

的完整修改
public class VideoFilesAdapter extends ArrayAdapter<String> {
    private List<String> mpath;
    private Context mContext;
    public static ArrayList<String> mSelectedPaths = null;
    private MyLRU lruCache;

    public VideoFilesAdapter(Context context, List<String> path) {
        super(context, R.layout.fileadapter_list, path);
        this.mContext = context;
        this.mpath = path;
        // My LRU
        lruCache = MyLRU.getInstance();
    }

    @Override
    public View getView(final int position, View convertView, ViewGroup parent) {
        View v;
        if (convertView == null) {
            LayoutInflater mInflater = (LayoutInflater) mContext
                    .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            v = mInflater.inflate(R.layout.fileadapter_list, null);
            Helper h = new Helper();
            h.textView = (TextView) convertView.findViewById(R.id.txt);
            h.textView = (ImageView) convertView.findViewById(R.id.img);
            v.setTag(h);
        } else {
            v = convertView;
        }

        Helper myHelper = (Helper) v.getTag();

        File file = new File(mpath.get(position));
        String fullPath = file.getAbsolutePath();

        if (file.exists()) {
            myHelper.textView.setText(file.getName());

            Bitmap cacheImage = lruCache.getImage(fullPath);
            if (cacheImage == null) {
                Bitmap bm = scaleCenterCrop(ThumbnailUtils.createVideoThumbnail(fullPath, MediaStore.Video.Thumbnails.MICRO_KIND),100,100);
                lruCache.addImage(fullPath, bm);
                cacheImage = bm;
            }
            myHelper.image.setImageBitmap(cacheImage);

        }

        return v;
    }

    class Helper {
        public TextView textView;
        public ImageView image;
    }

    public static Bitmap scaleCenterCrop(Bitmap source, int newHeight, int newWidth) {
        int sourceWidth = source.getWidth();
        int sourceHeight = source.getHeight();

        // Compute the scaling factors to fit the new height and width, respectively.
        // To cover the final image, the final scaling will be the bigger
        // of these two.
        float xScale = (float) newWidth / sourceWidth;
        float yScale = (float) newHeight / sourceHeight;
        float scale = Math.max(xScale, yScale);

        // Now get the size of the source bitmap when scaled
        float scaledWidth = scale * sourceWidth;
        float scaledHeight = scale * sourceHeight;

        // Let's find out the upper left coordinates if the scaled bitmap
        // should be centered in the new size give by the parameters
        float left = (newWidth - scaledWidth) / 2;
        float top = (newHeight - scaledHeight) / 2;

        // The target rectangle for the new, scaled version of the source bitmap will now
        // be
        RectF targetRect = new RectF(left, top, left + scaledWidth, top + scaledHeight);

        // Finally, we create a new bitmap of the specified size and draw our new,
        // scaled bitmap onto it.
        Bitmap dest = Bitmap.createBitmap(newWidth, newHeight, source.getConfig());
        Canvas canvas = new Canvas(dest);
        canvas.drawBitmap(source, null, targetRect, null);

        return dest;
    }

}

正如你所看到的,我暂时删除了getImageUri方法和Picasso,因为它已经没有意义了,因为我们已经有了LRU-cache的缓存。

我希望这会提高您的应用效果:)