【问题标题】:How to pass the Bitmap argument?如何传递位图参数?
【发布时间】:2014-01-15 15:59:32
【问题描述】:

我想从我的 sd 卡加载一些图像并将它们设置为我的应用程序布局的背景。我想有效地做到这一点,所以我不会得到 OutOfMemory Exception 并在后台进行。所以我在Processing Bitmaps 中阅读并使用了几乎关于使用位图的确切代码 在安卓开发者那里。这是我的代码:

public class ImageLoader {

    private final Context context;
    private int imageWidth;
    private int imageHeight;

    public ImageLoader(Context context, int imageWidth, int imageHeight) {

        this.context = context;
        setImageSize(imageWidth, imageHeight);
    }

    public ImageLoader(Context context, int imageSize) {

        this.context = context;
        setImageSize(imageSize);
    }

    public void setImageSize(int width, int height) {
        imageWidth = width;
        imageHeight = height;
    }

    public void setImageSize(int size) {
        setImageSize(size, size);
    }

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

    public static Bitmap decodeSampleBitmapFromResource(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 = calculateInSampleSize(options, reqWidth, reqHeight);

        // Decode bitmap with inSampleSize set
        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(res, resId, options);
    }

    public static boolean cancelPotentialWork(int data, ImageView imageView) {

        final BitmapWorkerTask bitmapWorkerTask = getBitmapWorkerTask(imageView);

        if (bitmapWorkerTask != null) {

            final int bitmapData = bitmapWorkerTask.data;

            if (bitmapData != data) {

                // Cancel previous task
                bitmapWorkerTask.cancel(true);

            } else {
                // The same work is already in progress
                return false;
            }
        }

        // No task associated with the ImageView, or an existing task was cancelled
        return true;
    }

    private static BitmapWorkerTask getBitmapWorkerTask(ImageView imageView) {

        if (imageView != null) {

            final Drawable drawable = imageView.getDrawable();

            if (drawable instanceof AsyncDrawable) {

                final AsyncDrawable asyncDrawable = (AsyncDrawable) drawable;

                return asyncDrawable.getBitmapWorkerTask();
            }
        }

        return null;
    }

    public void loadBitmap(int resId, ImageView imageView) {

        if (cancelPotentialWork(resId, imageView)) {

            final BitmapWorkerTask task = new BitmapWorkerTask(imageView);

            final AsyncDrawable asyncDrawable =
                    new AsyncDrawable(context.getResources(), ???mPlaceHoderBitmap???, task);

            imageView.setImageDrawable(asyncDrawable);

            task.execute(resId);
        }
    }

    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 decodeSampleBitmapFromResource(context.getResources(), data, imageWidth, imageHeight);
        }

        @Override
        protected void onPostExecute(Bitmap bitmap) {

            if (isCancelled()) {
                bitmap = null;
            }

            if (imageViewReference != null && bitmap != null) {

                final ImageView imageView = imageViewReference.get();

                final BitmapWorkerTask bitmapWorkerTask =
                        getBitmapWorkerTask(imageView);

                if (this == bitmapWorkerTask && imageView != null) {

                    imageView.setImageBitmap(bitmap);
                }
            }
        }

    }

    static class AsyncDrawable extends BitmapDrawable {

        private final WeakReference<BitmapWorkerTask> bitmapWorkerTaskReference;

        public AsyncDrawable(Resources res, Bitmap bitmap,
                BitmapWorkerTask bitmapWorkerTask) {

            super(res, bitmap);

            bitmapWorkerTaskReference = 
                    new WeakReference<ImageLoader.BitmapWorkerTask>(bitmapWorkerTask);
        }

        public BitmapWorkerTask getBitmapWorkerTask() {

            return bitmapWorkerTaskReference.get();
        }
    }
}

但是在 loadBitmap(int resId, Bitmap bitmap, ImageView imageView) 方法中我不知道如何传递位图。如果我使用 BitmapFactory.decode* 我可能会遇到异常。我应该如何为我的图像数据源传递位图参数?

【问题讨论】:

  • “如果我使用 BitmapFactory.decode* 我可能会得到异常”你是什么意思?你试过吗?
  • 如果您直接解码图像文件以将其分配给位图而不考虑其大小和尺寸,它可能会变得太大并超出内存限制。我已经试过了。这就是我使用上面代码的原因。
  • 这就是 doInBackground() 方法的作用,我也传递了 BitmapWorkerTask 对象。
  • 如果您阅读了我在问题开头链接的文章,他们编写的 loadBitmap 没有参数位图,但传递了参数 mPlaceHolderBitmap,我不知道那是什么。这是我的问题。
  • 我明白了,尝试在该参数中传递 null

标签: android bitmap


【解决方案1】:

在那篇文章中:

public void loadBitmap(int resId, ImageView imageView) {
    if (cancelPotentialWork(resId, imageView)) {
        final BitmapWorkerTask task = new BitmapWorkerTask(imageView);
        final AsyncDrawable asyncDrawable =
                new AsyncDrawable(getResources(), mPlaceHolderBitmap, task);
        imageView.setImageDrawable(asyncDrawable);
        task.execute(resId);
    }
}

您传递给AsyncDrawable 的位图应该是加载实际图像时的占位符。

因此,您可以对占位符图像进行一次解码,然后将其传递。

在Activity中创建一个Bitmap对象:

Bitmap placeHolder=null;

onCreate

placeHolder=BitmapFactory.decodeResource(getResources(), R.drawable.place_holder);

现在每次你想从 SD 卡调用加载一些图像:

loadBitmap(<resId>,placeHolder,imageView);

【讨论】:

  • 你的意思是我使用 BitmapFactory.decode* 方法之一,如 decodeFile 并传递图像?
  • 我只是不明白图片占位符是什么意思。
  • 是的,但只有一次。将占位符图像放入 res/drawable 并在 onCreate 中对其进行解码并传递该对象
  • 它没有调整大小??
  • 再问一个问题。我使用 getResources().getIdentifier(...) 获取我的 resId 但是外部图像的资源 id 呢?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-12-09
  • 2011-06-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-09-24
  • 2020-10-11
相关资源
最近更新 更多