1

我正在寻找有关如何优化以下代码的想法,该代码是 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. 事情是,在一种情况下,我必须向ImageButtonsUI 添加一百多个,而这段代码非常慢。

问题是:我怎样才能让它工作得更快?它目前在 上执行MainActivity,多线程(也许AsyncTask)在这种情况下有帮助吗?还有其他方法可以更快地将位图设置为所需的大小吗?如果没有办法使这个过程显着加快,那么有没有办法逐步添加 ImageButtons(但顺序相同),以便在所有这些发生时 UI 不会冻结?

4

3 回答 3

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 作为高度,因为我不知道您的图像看起来如何。您可以稍微调整一下布局,但这通常应该可以解决问题。

于 2013-01-24T03:46:54.247 回答
1

我在http://developer.android.com/training/displaying-bitmaps/index.html找到了一个很好的解决方案

它有以下代码,动态设置BitmapImageView.

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);
}

在这里,只需更改ImageViewImageButton.

编辑:

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

于 2013-01-24T03:36:19.290 回答
1

将您的代码从主线程中移除不会使应用程序更快地处理图像,但它会在该过程发生时保持 UI 对用户的响应,并且当您一次加载这么多数据时绝对是必要的步骤. 但是,请记住,您不能从除主线程之外的任何线程操作视图层次结构,因此您不能将整个操作放在AsyncTask.doInBackground(). 您将不得不拆分花费最多时间的行(即您的decodeResource()andcreateScaledBitmap()调用),但是用于实例化并向父级添加视图的代码将需要在onPostExecute()or中发生publishProgress()(取决于您如何实现任务逻辑)。

问题是,在一种情况下,我必须在 UI 中添加一百多个 ImageButton,而这段代码非常慢。

要记住的另一件重要事情是,在任何时候在您的层次结构中拥有超过 100 个基于图像的视图仍然是一大块浪费的内存。加快进程的最佳方法不是一次添加所有视图,而是仅在需要时添加它们(即当用户滚动时),然后删除/回收不再出现在屏幕上的视图。正是AdapterView出于这个原因,实现的工作方式就是这样,只使用您需要的内存,您的应用程序将更快更高效。

我意识到HorizontalListView框架中没有,但有 3rd 方实现为您提供此功能,或者您可以查看其中一个框架类的源代码以构建您自己的。

于 2013-01-24T03:51:30.280 回答