首页 > 代码库 > android客户端加载网络大图片如何避免内存溢出

android客户端加载网络大图片如何避免内存溢出

在Android开发中加载sdcard上的大图片到内存时容易导致OOM异常,常见的解决办法是基于BitmapFactory.Options类提供的方法定义指定的解码方式,设置inJustDecodeBounds属性为true,避免分配内存,返回一个null的Bitmap对象(包含outWidth,outHeightandoutMimeType),然后读取图片的尺寸和类型。再根据屏幕的高和宽对图片进行缩放,最后将缩放的图片加载到内存,主要代码如下:

 1         Options opts = new Options(); 2         opts.inJustDecodeBounds = true; //设置为true, 加载器不会返回图片, 而是设置Options对象中以out开头的字段.即仅仅解码边缘区域 3         BitmapFactory.decodeFile(filePath, opts); 4          5         // 得到图片的宽和高 6         int imageWidth = opts.outWidth; 7         int imageHeight = opts.outHeight; 8          9         // 获取屏幕的宽和高10         Display display = this.getWindowManager().getDefaultDisplay(); // 获取默认窗体显示的对象11         int screenWidth = display.getWidth();12         int screenHeight = display.getHeight();13         14         // 计算缩放比例15         int widthScale = imageWidth / screenWidth;16         int heightScale = imageHeight / screenHeight;17         18         int scale = widthScale > heightScale ? widthScale:heightScale;20         21          // 指定加载可以加载出图片.22         opts.inJustDecodeBounds = false;23         // 使用计算出来的比例进行缩放24         opts.inSampleSize = scale;25         Bitmap bm = BitmapFactory.decodeFile(path, opts);

这段代码主要是针对用户存储在sdcard上的大图片,如果现在要从网络上获取一张大图片并在Android机上显示出来,应该如何避免OOM异常呢?

首先加载网络大图片如果是通过BitmapFactory.decodeStream(inputStream)方法的话会出现内存溢出,所以我们同样可以考虑使用Options 类对图片进行缩放处理,然后用BitmapFactory.decodeStream(is, outPadding, opts)方法加载网络图片流对象,但是options的缩放比例该如何确定,如果直接写options.inSampleSize = 固定值;会存在两个问题:一是如果固定值太小任然有内存溢出的可能,二是如果固定值太大会导致加载出来的图片模糊不清,所以现在同样考虑根据图片的高和宽与屏幕的高和宽进行缩放?但是图片都还没加载出来怎样得到图片高和宽呢?你可能会想到通过把options.inJustDecodeBounds 设置为true; 然后调用BitmapFactory.decodeStream(is, outPadding, options),再通过options.outWidth;和options.outHeight;得到图片的高和宽,想法很好,但是当你计算出缩放比再通过options.inJustDecodeBounds = false;options.inSampleSize = scale;Bitmap bm = BitmapFactory.decodeStream(is, outPadding, options)方法获取缩放后的图片时,你会看到手机界面上啥到没有,再看日志发现输出一行SkImageDecoder::Factory returned null信息,返回的竟然是空对象,郁闷吧,这是为什么呢?原来你在代码中两次使用了BitmapFactory.decodeStream(is, outPadding, options)方法,进一步说是因为你两次使用了同一个InputStream流对象,在第二次使用时流的起始位置已经移动到末尾了,所以返回的是空,那该怎么办呢?我目前使用的方法是分别打开两个流对象,一个用于设置options的缩放比例,一个用于BitmapFactory.decodeStream(is, outPadding, options)方法调用,经过测试我发现如果先设置options后再传递给BitmapFactory.decodeStream时会非常卡,图片老半天加载不出来,所以我换了一种方式:先通过HttpClient得到图片的流对象,获取它的宽高并根据屏幕的宽高计算出缩放比例;然后再通过HttpClient得到图片的流对象,根据计算出的缩放比例进行缩放,主要代码如下:

    /**     * 计算图片的缩放比例     * @return     */    public int getScare() {        try {            HttpClient client = new DefaultHttpClient();            HttpGet httpGet = new HttpGet(imageUrl);            HttpResponse response = client.execute(httpGet);            int code = response.getStatusLine().getStatusCode();            if (200 == code) {                InputStream is = response.getEntity().getContent();                Options opts = new Options();                opts.inJustDecodeBounds = true;                BitmapFactory.decodeStream(is, null, opts);                int imageWidth = opts.outWidth;                int imageHeight = opts.outHeight;                Display display = ImageActivity.this.getWindowManager()                        .getDefaultDisplay();                int screenWidth = display.getWidth();                int screenHeight = display.getHeight();                int widthscale = imageWidth / screenWidth;                int heightscale = imageHeight / screenHeight;                int scale = widthscale > heightscale ? widthscale : heightscale;                return scale;            }        } catch (Exception e) {            e.printStackTrace();        }        return 1;//网络连接失败时默认返回1    }
/**     * 获取网络图片     */    protected void getNetImage() {        try {            HttpClient client = new DefaultHttpClient();            HttpGet httpGet = new HttpGet(imageUrl);            HttpResponse response = client.execute(httpGet);            int code = response.getStatusLine().getStatusCode();            if (200 == code) {                InputStream is = response.getEntity().getContent();                Options opts = new Options();                                //根据计算出的比例进行缩放                int scale = getScare();                opts.inSampleSize = scale;                                 Bitmap bm = BitmapFactory.decodeStream(is, null, opts);                //将bm发生给主线程用于显示图片,更新UI                Message msg = Message.obtain();                msg.obj = bm;                handler.sendMessage(msg);            }        } catch (Exception e) {            e.printStackTrace();        }    }
//显示图片    Handler handler = new Handler() {        public void handleMessage(Message msg) {            Bitmap bm = (Bitmap) msg.obj;            iv.setImageBitmap(bm);        };    };

 

android客户端加载网络大图片如何避免内存溢出