Android之Bitmap 一

读取位图的尺寸与类型

BitmapFactory(Creates Bitmap objects from various sources, including files, streams, and byte-arrays.)提供了一些解码的方法,用来从不同的资源中创建一个Bitmap。
这些方法在构造位图的时候会尝试分配内存,因此会容易导致OutOfMemory的异常。所以为了避免这个异常,我们需要在真正解析图片之前检查它的尺寸。
每一种解码方法都可以通过BitmapFactory.Options设置一些附加的标记,以此来指定解码选项。

BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(getResources(), R.id.myimage, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
String imageType = options.outMimeType;

设置 inJustDecodeBounds 属性为true可以在解码的时候避免内存的分配,它会返回一个null的Bitmap,但是可以获取到 outWidth, outHeight 与 outMimeType
因此我们可以按比例缩小图片
下面一段是根据目标图片大小来计算Sample图片大小:

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

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

我练习这个,用GridView来加载图片。
自定义的Adapter:

public class PictureAdapter extends BaseAdapter {
    Context context;
    int[] reseIds;
    int layId;

    public PictureAdapter(Context context,int[] reseIds,int layId) {
        super();
        this.context=context;
        this.reseIds = reseIds;
        this.layId=layId;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {

        View view = LayoutInflater.from(context).inflate(layId,parent,false);
        ImageView imageView = (ImageView)view.findViewById(R.id.item_image);
        //imageView.setImageResource(reseIds[position]);
        Log.d("getView",String.valueOf(reseIds[position]));
         loadBitmap(reseIds[position],imageView);

        return view;
    }

    @Override
    public int getCount() {
        return reseIds.length;
    }

    @Override
    public Object getItem(int position) {
        return reseIds[position];
    }

    @Override
    public long getItemId(int position) {
        return reseIds[position];
    }

    public void loadBitmap(int resId, ImageView imageView){
        if(cancelPotentialWork(resId,imageView)){
            BitmapWorkerTask task = new BitmapWorkerTask(imageView,context.getResources());
            Bitmap holder = BitmapFactory.decodeResource(context.getResources(),resId);
            final AsyncDrawable asyncDrawable =
                    new AsyncDrawable(context.getResources(),holder,task);
            imageView.setImageDrawable(asyncDrawable);
            Log.d("load",String.valueOf(resId));
            task.execute(resId);
        }
//        BitmapWorkerTask task = new BitmapWorkerTask(imageView,context.getResources());
//        task.execute(resId);


    }

    static class AsyncDrawable extends BitmapDrawable{
        private final WeakReference reference;

        public  AsyncDrawable(Resources resources, Bitmap bitmap,BitmapWorkerTask bitmapWorkerTask){
            super(resources,bitmap);
            reference= new WeakReference(bitmapWorkerTask);
        }

        public BitmapWorkerTask getBitTask(){
            return  (BitmapWorkerTask)reference.get();
        }
    }

    public static boolean cancelPotentialWork(int data,ImageView imageView){
        final BitmapWorkerTask bitmapWorkerTask = getBitmapTask(imageView);

        if(bitmapWorkerTask !=null){
            final  int bitmapData = bitmapWorkerTask.data;
            if(bitmapData == 0 || bitmapData != data){
                bitmapWorkerTask.cancel(true);
            }else {
                return false;
            }
        }
        return true;
    }
    public static BitmapWorkerTask getBitmapTask(ImageView imageView){
        if(imageView !=null){
            final Drawable drawable = imageView.getDrawable();
            if(drawable instanceof  AsyncDrawable){
                final AsyncDrawable asyncDrawable = (AsyncDrawable)drawable;
                return asyncDrawable.getBitTask();
            }
        }
        return null;
    }

}

在getView中调用loadBitmap(),用canclePotentialWork方法检查是否有另一个正在执行的任务与该Image关联了起来,如果关联了,就取消另一个任务。为什么要判断呢,因为我是用的AsyncTask来加载每一个图片。因为子Item视图会在用户滑动屏幕时被循环使用,如果每一个子视图都触发了一个AsyncTask,就没有办法确保关联的视图在结束任务时,分配的视图已经进入循环队列中,给另一个子视图进行重用。而且无法保证所有的异步任务的完成顺序和他们本身的启动顺序保存一致。(ListView也是一样的)(简单来说,就是不知道同一个ImageView是否在同一个任务中)
因此我们又专门创建一个Drawable的子类来存储任务的引用:

static class AsyncDrawable extends BitmapDrawable {
    private final WeakReference bitmapWorkerTaskReference;

    public AsyncDrawable(Resources res, Bitmap bitmap,
            BitmapWorkerTask bitmapWorkerTask) {
        super(res, bitmap);
        bitmapWorkerTaskReference =
            new WeakReference(bitmapWorkerTask);
    }

    public BitmapWorkerTask getBitmapWorkerTask() {
        return bitmapWorkerTaskReference.get();
    }
}

getBitmapTask()是用作检索AsyncTask是否已经被分配到指定的ImageView中。

 public static BitmapWorkerTask getBitmapTask(ImageView imageView){
        if(imageView !=null){
            final Drawable drawable = imageView.getDrawable();
            if(drawable instanceof  AsyncDrawable){
                final AsyncDrawable asyncDrawable = (AsyncDrawable)drawable;
                return asyncDrawable.getBitTask();
            }
        }
        return null;
    }

AsyncTask的代码:

public class BitmapWorkerTask extends AsyncTask<Integer,Integer,Bitmap> {

    private final WeakReference imageViewReference;
    public int data = 0;
    Resources resources;
    public BitmapWorkerTask(ImageView imageView,Resources resources){
        imageViewReference = new WeakReference(imageView);
        this.resources = resources;

    }


    @Override
    protected Bitmap doInBackground(Integer... params) {
        data = params[0];
        Log.d("back",String.valueOf(data));
        return decodeSampleBitmapFromResource(resources,data,100,150);
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {

        if(imageViewReference !=null && bitmap !=null){
            final ImageView imageView = (ImageView) imageViewReference.get();
            final BitmapWorkerTask bitmapWorkerTask = PictureAdapter.getBitmapTask(imageView);
            Log.d("post0","aaaaa");
            if(this == bitmapWorkerTask && imageView != null){
                Log.d("post","aaaaa");
                imageView.setImageBitmap(bitmap);
            }
//            if(imageView !=null){
//                imageView.setImageBitmap(bitmap);
//            }

            }
    }

    public static Bitmap decodeSampleBitmapFromResource(Resources resources,int resId,int reqWidth,int reqHeight){
        final BitmapFactory.Options options= new BitmapFactory.Options();
        options.inJustDecodeBounds=true;
        BitmapFactory.decodeResource(resources,resId,options);
        options.inSampleSize = calculateInSampleSize(options,reqWidth,reqHeight);

        options.inJustDecodeBounds = false;
        return BitmapFactory.decodeResource(resources,resId,options);
    }

    public  static int calculateInSampleSize(BitmapFactory.Options options,int reqWidth,int reqHeight){
        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;

            while((halfHeight /inSampleSize)>reqHeight &&(halfWidth / inSampleSize)>reqWidth){
                inSampleSize *=2;
            }
        }
        return inSampleSize;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值