我有一个包含未知数量自定义项目的列表视图,并且在滚动期间 - 在getView内部)我检查aConvertView的相关图像是否在本地存在并将其设置为listview项目(aConvertView):
// out of getView(...)
Bitmap mBitmap;
BitmapFactory.Options mOptions = new BitmapFactory.Options();
mOptions.inPreferredConfig = Bitmap.Config.ARGB_8888;
// Inside getView(...)
File file = new File(mContext.getFilesDir(), picture_file_name);
if(file.exists())
{
**// Which one has less impact on the UI thread?**
mBitmap = BitmapFactory.decodeFile(file.getPath(), mOptions);
aImageView.setImageBitmap(mBitmap);
// OR
aImageView.setImageURI(Uri.fromFile(file));
}
当然我有滚动延迟的已知问题,我想知道在滚动期间设置项目的ImageView的最佳方法/方法。
setImageBitmap对UI线程的影响小于setImageURI?,或者两者都在UI上工作并导致延迟。
使用新文件,File.exists()会对UI线程产生影响吗?
毋庸置疑,我为listview项目使用了一个持有者,并使用以下参数进行了我的列表视图:
android:smoothScrollbar="true"
android:scrollingCache="false"
android:animationCache="false"
答案 0 :(得分:3)
两者都在UI线程上运行。我会说第一个可能比第二个快一点。第二个真正取决于Uri资源的来源(例如,uri可能指向甚至没有存储在手机上的远程文件)。
我认为这里的问题是否应该在UI线程上加载位图,答案是否定的,尤其是在listview中。 Google在developers.android.com上发布了一个关于从UI线程加载位图的精彩教程:http://developer.android.com/training/displaying-bitmaps/process-bitmap.html
答案 1 :(得分:1)
您有延迟问题,因为您在UI线程上执行文件IO,主要是decodeFile
这里是一个问题,您实际访问光盘上的文件数据(尽管没有理由调用File.exists()
来自UI线程)。
Quanturium的答案是正确的
示例解释了如何在后台加载位图并使用WeakReference
到ImageView
将位图指定为背景可绘制。请记住,所有文件IO工作都应该在doInBackground
内,onPostExecute
实际上发生在UI线程上。
编辑:如何在AsyncTask中使用File.Exists()
// Decode image in background.
@Override
protected Bitmap doInBackground(Integer... params) {
File file = new File(mContext.getFilesDir(), picture_file_name);
if(file.exists())
{
return BitmapFactory.decodeFile(file.getPath(), mOptions);
}
else
{
return null;
}
}
注意:我无法访问我的开发机器,所以我不确定这是否会构建。
要回答关于从另一个启动一个AsyncTask的问题 - 我从来没有这样做过,我想这是可能的。就我而言,我将所有流量都放在一个doInBackground
:
对我来说,最重要的是在后台线程中运行REST调用和文件IO - 我不在乎它是一个还是两个任务。
答案 2 :(得分:0)
之前我遇到过同样的问题。我试图在Uri
中加载6个本地大图像(使用ListView
)。为了让您的应用顺利运行,您可能需要做两件事。
2.缩放图像大小以使图像更适合ImageView
。这是一个如何缩放图像大小的android文档。 link
毕竟这是我的AsyncTask
类,它在新线程上加载图像并根据imageview缩放图像:
class BitmapWorkerTask extends AsyncTask<Uri, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
private Uri data = null;
public BitmapWorkerTask(ImageView imageView) {
// Use a WeakReference to ensure the ImageView can be garbage collected
imageViewReference = new WeakReference<ImageView>(imageView);
}
// Decode image in background.
@Override
protected Bitmap doInBackground(Uri... params) {
data = params[0];
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeFile(data.toString(),options);
options.inSampleSize= calculateInSampleSize(options,300,300);
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(data.toString(),options);
}
// Once complete, see if ImageView is still around and set bitmap.
@Override
protected void onPostExecute(Bitmap bitmap) {
if (imageViewReference != null && bitmap != null) {
final ImageView imageView = imageViewReference.get();
if (imageView != null) {
imageView.setImageBitmap(bitmap);
}
}
}
}
public static int calculateInSampleSize(
BitmapFactory.Options options, int reqWidth, int reqHeight) {
// Raw height and width of image
final int height = options.outHeight;
final int width = options.outWidth;
int inSampleSize = 1;
if (height > reqHeight || width > reqWidth) {
final int halfHeight = height / 2;
final int halfWidth = width / 2;
// Calculate the largest inSampleSize value that is a power of 2 and keeps both
// height and width larger than the requested height and width.
while ((halfHeight / inSampleSize) > reqHeight
&& (halfWidth / inSampleSize) > reqWidth) {
inSampleSize *= 2;
}
}
return inSampleSize;
}
300 * 300是我的图片视图尺寸