优化Android中的位图创建/大小调整

时间:2013-01-24 03:26:28

标签: android optimization bitmap

我正在寻找有关如何优化以下代码的想法,这些代码是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不会被冻结?

3 个答案:

答案 0 :(得分: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);
}

此处,只需将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>