Android:列表视图滚动期间的 setImageBitmap 与 setImageURI
Android: setImageBitmap vs setImageURI during listview scrolling
我有一个包含未知数量自定义项目的列表视图,在滚动过程中 - 在 getView 中)我检查本地是否存在与 aConvertView 相关的图像并将其设置为列表视图项目 (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 上工作并导致延迟。
正在使用 new File ,File.exists() 对 UI 线程有影响吗?
不用说,我为我的列表视图项目使用了一个 holder,并为我的列表视图使用了以下参数:
android:smoothScrollbar="true"
android:scrollingCache="false"
android:animationCache="false"
两个 运行 在 UI 线程上。我会说第一个可能比第二个快一点点。第二个实际上取决于 Uri 资源的来源(例如,uri 可能指向甚至未存储在 phone 上的远程文件)。
我认为这里的问题是您是否应该在 UI 线程上加载位图,答案是否定的,尤其是在列表视图中。 Google 在 developers.android.com 上发布了关于从 UI 线程加载位图的精彩教程:http://developer.android.com/training/displaying-bitmaps/process-bitmap.html
您有延迟问题,因为您在 UI 线程上执行文件 IO,主要是 decodeFile
这里的问题,您实际访问光盘上的文件数据(尽管没有理由从 UI 线程调用 File.exists()
)。
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 启动一个 AsyncTask 的问题 - 我从来没有这样做过,我想这是可能的。就我而言,我将所有流程都放在一个 doInBackground
:
中
- 首先下载数据(我猜您正在使用一些 REST 调用来执行此操作)。
- 从您的回复中获取内容
- 如果文件存在,覆盖
- 如果文件不存在,则创建
对我来说,最重要的是 运行 在后台线程中进行 REST 调用和文件 IO - 我不在乎它是一个任务还是两个任务。
我之前遇到过同样的问题。我试图在 ListView
中加载 6 个本地大图像(使用 Uri
)。为了使您的应用 运行 顺利进行,您可能需要做两件事。
- 不要在主线程上加载图像。这是一个 android 文档,说明如何在单独的线程上加载图像:link.There are many libraries already implement this for you. If you are loading image from internet, server, etc. i would recommend Picasso。
2.Scale 使图像更适合 ImageView
的图像大小。这是一个 android 文档,说明如何缩放图像大小。 link
毕竟这是我的 AsyncTask
class 在新线程上加载图像并根据 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 是我的图像视图尺寸
我有一个包含未知数量自定义项目的列表视图,在滚动过程中 - 在 getView 中)我检查本地是否存在与 aConvertView 相关的图像并将其设置为列表视图项目 (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 上工作并导致延迟。
正在使用 new File ,File.exists() 对 UI 线程有影响吗?
不用说,我为我的列表视图项目使用了一个 holder,并为我的列表视图使用了以下参数:
android:smoothScrollbar="true"
android:scrollingCache="false"
android:animationCache="false"
两个 运行 在 UI 线程上。我会说第一个可能比第二个快一点点。第二个实际上取决于 Uri 资源的来源(例如,uri 可能指向甚至未存储在 phone 上的远程文件)。
我认为这里的问题是您是否应该在 UI 线程上加载位图,答案是否定的,尤其是在列表视图中。 Google 在 developers.android.com 上发布了关于从 UI 线程加载位图的精彩教程:http://developer.android.com/training/displaying-bitmaps/process-bitmap.html
您有延迟问题,因为您在 UI 线程上执行文件 IO,主要是 decodeFile
这里的问题,您实际访问光盘上的文件数据(尽管没有理由从 UI 线程调用 File.exists()
)。
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 启动一个 AsyncTask 的问题 - 我从来没有这样做过,我想这是可能的。就我而言,我将所有流程都放在一个 doInBackground
:
- 首先下载数据(我猜您正在使用一些 REST 调用来执行此操作)。
- 从您的回复中获取内容
- 如果文件存在,覆盖
- 如果文件不存在,则创建
对我来说,最重要的是 运行 在后台线程中进行 REST 调用和文件 IO - 我不在乎它是一个任务还是两个任务。
我之前遇到过同样的问题。我试图在 ListView
中加载 6 个本地大图像(使用 Uri
)。为了使您的应用 运行 顺利进行,您可能需要做两件事。
- 不要在主线程上加载图像。这是一个 android 文档,说明如何在单独的线程上加载图像:link.There are many libraries already implement this for you. If you are loading image from internet, server, etc. i would recommend Picasso。
2.Scale 使图像更适合 ImageView
的图像大小。这是一个 android 文档,说明如何缩放图像大小。 link
毕竟这是我的 AsyncTask
class 在新线程上加载图像并根据 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 是我的图像视图尺寸