在 Picasso 图像加载器中加载位图图像会减慢列表视图中的滚动速度
Posted
技术标签:
【中文标题】在 Picasso 图像加载器中加载位图图像会减慢列表视图中的滚动速度【英文标题】:Loading bitmap images in Picasso Image loader slows down scrolling in a listview 【发布时间】:2015-09-21 23:42:16 【问题描述】:我正在尝试生成在 sdcard 文件夹中找到的所有视频的缩略图,并使用 Picasso Image loader 在列表视图中填充所有生成的位图。一切正常,但速度非常慢,我无法滚动列表视图,它的滞后非常缓慢。我在该列表视图中有大约 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);
【问题讨论】:
你的代码的问题是你的 Inflating TextView 和 ImageView 每次单元格视图被回收,基本上它会减慢你的滚动体验。 那么解决办法是什么?? @龙 我现在正在编码,我可能会在明天之前发送给您 :) 我会尽可能解释每个部分。 【参考方案1】:更新 看起来您并没有以任何方式存储/缓存这些位图,所以它一遍又一遍地做。试试这里找到的解决方案:Video thumbnail arrayadopter is slow on scroll
我不认为毕加索会减慢您ListView
的滚动速度。您的列表项有多复杂?如果它们嵌套了许多视图,可能就是这样,我在 ListView
中有超过 700 个项目,没有性能问题。
【讨论】:
我知道速度变慢是因为ThumbnailUtils.createVideoThumbnail
函数会生成文件夹中所有视频文件的缩略图。有什么办法可以解决吗?【参考方案2】:
当我查看代码时,我看到 TextView
和 ImageView
每次调用 getView
时都会被夸大。通货膨胀是一项非常昂贵的任务,因此我们希望尽可能避免使用它。
在其他任何事情之前,请确保您将在 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。
我希望这会提高您的应用性能:)
【讨论】:
07-05 23:14:17.282: E/AndroidRuntime(4681): java.lang.***Error: 堆栈大小 8MB 07-05 23:14:17.282: E/AndroidRuntime(4681): 在com.example.myapp.helper.MyLRU.getImage(MyLRU.java:34) 我认为问题是您的设备内存不足,请尝试将 availableMemory / 8 更改为 availableMemory / 4 并告诉我会发生什么发生。以上是关于在 Picasso 图像加载器中加载位图图像会减慢列表视图中的滚动速度的主要内容,如果未能解决你的问题,请参考以下文章
当我在我的 android 应用程序中从图库中加载图像时,为啥位图返回较小的图像?