我正在寻找有关如何优化以下代码的想法,这些代码是for循环的主体:
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;
options.inJustDecodeBounds = false;
ImageButton view = new ImageButton(this);
view.setBackgroundColor(0);
view.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
finalThis.onBorderClicked(v);
}
});
view.setTag(i); //i is the loop counter
Bitmap big = BitmapFactory.decodeResource(getResources(), borders[i], options);
Bitmap smaller = Bitmap.createScaledBitmap(big, borderDimension, borderDimension, false);
view.setImageBitmap(smaller);
view.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.FILL_PARENT));
((LinearLayout.LayoutParams)view.getLayoutParams()).setMargins(0, 0, -5, 0);
group.addView(view);
big.recycle();
基本上我有600x600的图像,我希望它们的大小约为50dp。所以很自然地,我首先将样本大小设置为4(600/4 = 150),这样我就不会占用不必要的内存,然后进一步将图像调整到指定的大小。然后我用它将它加载到ImageButton
,然后我回收更大的,现在无用的Bitmap
。
这是一个动态UI创建代码,ImageButtons
已添加到HorizontalScrollView
。事情是,在一个案例中,我必须向UI添加超过一百ImageButtons
,这段代码非常慢。
问题是:如何让它更快地运作?它目前在MainActivity
上执行,在这种情况下可以多线程(也许是AsyncTask
)帮助吗?有没有其他方法可以更快地将位图变为所需的大小?如果没有办法让这个过程明显加快,那么有没有办法逐个添加ImageButtons(但顺序相同),这样当所有这些都发生时UI不会被冻结?
答案 0 :(得分:1)
我在http://developer.android.com/training/displaying-bitmaps/index.html
找到了一个很好的解决方案它有以下代码,可动态设置Bitmap
到ImageView
。
class BitmapWorkerTask extends AsyncTask<Integer, Void, Bitmap> {
private final WeakReference<ImageView> imageViewReference;
private int data = 0;
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(Integer... params) {
data = params[0];
return decodeSampledBitmapFromResource(getResources(), data, 100, 100));
}
// 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 void loadBitmap(int resId, ImageView imageView) {
BitmapWorkerTask task = new BitmapWorkerTask(imageView);
task.execute(resId);
}
此处,只需将ImageView
更改为ImageButton
即可。
编辑:
public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,
int reqWidth, int reqHeight) {
// First decode with inJustDecodeBounds=true to check dimensions
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
// Calculate inSampleSize
options.inSampleSize = 4;
// Decode bitmap with inSampleSize set
options.inJustDecodeBounds = false;
return BitmapFactory.decodeResource(res, resId, options);
}
您可以找到有关处理Bitmaps Efficiently
here
答案 1 :(得分:1)
您无需自己缩放图像。你可以通过要求ImageButton
为你缩放来做到这一点,这要快得多。
ImageButton view = new ImageButton(this);
view.setBackgroundColor(0);
view.setOnClickListener(new OnClickListener(){
@Override
public void onClick(View v) {
finalThis.onBorderClicked(v);
}
});
view.setTag(i); //i is the loop counter
view.setAdjustViewBounds(true);
view.setMaxHeight(borderDimension);
view.setMaxWidth(borderDimension);
view.setImageResource(border[i]);
view.setLayoutParams(new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
((LinearLayout.LayoutParams)view.getLayoutParams()).setMargins(0, 0, -5, 0);
group.addView(view);
我已经更改了布局参数以使用WRAP_CONTENT作为高度,因为我不知道你的图像是怎样的。您可以稍微使用布局,但这通常应该可以解决问题。
答案 2 :(得分:1)
将代码从主线程中移除将不会使应用程序更快地处理图像,但是在该过程发生时它将保持UI对用户的响应,并且当您有这么多数据时绝对是必要的步骤立即加载。但是,请记住,您不能从主线程以外的任何线程操作视图层次结构,因此您不能将整个操作放在AsyncTask.doInBackground()
内。您将必须拆分占用时间最多的行(即decodeResource()
和createScaledBitmap()
调用),但实例化并向父级添加视图的代码需要在{{1}中进行}或onPostExecute()
(取决于您如何实现任务逻辑)。
事情是,在一种情况下,我必须向UI添加超过一百个ImageButtons,这段代码非常慢。
要记住的另一个重要事项是,在任何时候在您的层次结构中拥有超过100个基于图像的视图仍然是一大块浪费的内存。加速该过程的最佳方法不是一次添加所有视图,而是仅在需要时添加它们(即,当用户滚动时),然后删除/回收不再在屏幕上的视图。这就是publishProgress()
实现的原因,只使用您需要的内存,您的应用程序将更快,更高效。
我意识到框架中没有AdapterView
,但是有第三方实现为您提供此功能,或者您可以查看其中一个框架类的源代码来构建您自己的。 / p>