android加载大图

故事要从一场面试说起,如何加载一个大图而不会发生OOM?这里有两种途径,一、降采样大图;二、局部加载大图。
由于android内存的限制,andoid系统给每个应用分配的内存是有限的,当直接加载一个占用内存加大的图片时就会发生OOM。

一、降采样大图

主要是利用BitmapFactory.Options对象的inSampleSize参数,根据空间尺寸与大图尺寸的比率来缩小大图,从而显示大图的缩略图。

关键代码如下:

//大图压缩看缩略图
    private void loadImageView() {
        imageView.setVisibility(View.VISIBLE);
        largeImageView.setVisibility(View.GONE);
        try {
            if (inputStream==null) {
                inputStream = getAssets().open("beauty.jpg");
            }
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true; //只读取图片,不加载到内存中
            inputStream.mark(inputStream.available()); //标记起点
            BitmapFactory.decodeStream(inputStream,null,options);
            inputStream.reset(); //用完inputStream后就重置状态,否则下次(inputStream.available()为0,无法再次使用
            DisplayMetrics dm = new DisplayMetrics();
            getWindowManager().getDefaultDisplay().getMetrics(dm);
            options.inSampleSize = calculateSampleSize(options,imageView.getWidth()==0?dm.widthPixels:imageView.getWidth(),imageView.getHeight()==0?dm.heightPixels:imageView.getHeight());
            options.inJustDecodeBounds = false; //读取降采样图片,加载到内存中
            inputStream.mark(inputStream.available());
            Bitmap bitmap=BitmapFactory.decodeStream(inputStream,null,options);
            imageView.setImageBitmap(bitmap);
            inputStream.reset();
            isLarge=false;
        } catch (Exception e) {
            e.printStackTrace();
        }
        btn.setText("看大图");
    }
//计算缩放比
    private int calculateSampleSize(BitmapFactory.Options options, int maxWidth, int maxHeight) {
        int height=options.outHeight; //获取原始图片的高度
        int width=options.outWidth; //获取原始图片的宽度
        int inSampleSize=1; //采样率越大则图片缩小的越厉害
        if (height>maxHeight || width>maxWidth) {
            int widthRatio=Math.round(width*1.0f/maxWidth);
            int heightRatio=Math.round(height*1.0f/maxHeight);
            inSampleSize= Math.max(widthRatio,heightRatio);
        }
        return inSampleSize;
    }
二、 局部加载大图
主要利用BitmapRegionDecoder类的decodeRegion方法来加载局部区域,通过重写View的onTouchEvent方法监听手指滑动事件,更新显示区域。

关键代码如下:

public void initStream(InputStream inputStream) {

        try {
            Timber.d("initStream,inputStream="+inputStream+",size="+inputStream.available());
            BitmapFactory.Options tmpOptions = new BitmapFactory.Options();
            tmpOptions.inJustDecodeBounds = true;
            BitmapFactory.decodeStream(inputStream, null, tmpOptions);
            mImageHeight = tmpOptions.outHeight;
            mImageWidth = tmpOptions.outWidth;
            bitmapRegionDecoder = BitmapRegionDecoder.newInstance(inputStream, false); //要放在BitmapFactory.decodeStream(inputStream, null, tmpOptions)后面,否则tmpOptions.outHeight与tmpOptions.outWidth为-1
            requestLayout();
            invalidate();
        } catch (IOException e) {
            Timber.e(e);
            e.printStackTrace();
        }
        Timber.d("initStream,mImageHeight="+mImageHeight+",,mImageWidth="+mImageWidth);
    }
@Override
    public boolean onTouchEvent(MotionEvent event) {
        Timber.d("onTouchEvent,event.getAction()="+event.getAction()+",mImageHeight="+mImageHeight+",,getHeight()="+getHeight()+",mImageWidth="+mImageWidth
        +",,getWidth()="+getWidth());
        switch (event.getAction() & MotionEvent.ACTION_MASK) {
            case MotionEvent.ACTION_DOWN:
                mStartX=event.getX();
                mStartY=event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                if (mImageHeight>getHeight()) {
                    rect.offset(0, (int) (mStartY-event.getY()));
                    measureHeight();
                    invalidate();
                }
                if (mImageWidth>getWidth()) {
                    rect.offset((int) (mStartX-event.getX()), 0);
                    measureWidth();
                    invalidate();
                }
                break;
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL:
                break;

        }
        return true;
    }
 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.drawBitmap(bitmapRegionDecoder.decodeRegion(rect, options), 0, 0, null);
    }

效果图如下:



工程源码


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值