MyException - 我的异常网
当前位置:我的异常网» Android » 【Android开发经验】Bit地图高效显示系列——怎么有

【Android开发经验】Bit地图高效显示系列——怎么有效的加载大尺寸Bit地图

www.MyException.Cn  网友分享于:2015-02-11  浏览:0次
【Android开发经验】Bitmap高效显示系列——如何有效的加载大尺寸Bitmap

    转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992

    Bitmap的处理在Android开发中一直是一个大问题,因为稍不注意,Bitmap就能够吃掉我们的所有内存,然后崩溃退出!但是,只要我们掌握了Bitmap的一些常见处理技巧,就可以有效的避免这个问题,从此不再惧怕Bitmap。


    图片有不同的形状与大小。在大多数情况下它们的实际大小都比需要呈现出来的要大很多。例如,系统的Gallery程序会显示那些你使用设备camera拍摄的图片,但是那些图片的分辨率通常都比你的设备屏幕分辨率要高很多。

    考虑到程序是在有限的内存下工作,理想情况是你只需要在内存中加载一个低分辨率的版本即可。这个低分辨率的版本应该是与你的UI大小所匹配的,这样才便于显示。一个高分辨率的图片不会提供任何可见的好处,却会占用宝贵的的内存资源,并且会在快速滑动图片时导致附加的效率问题。

     这一课会介绍如何通过加载一个缩小版本的图片到内存中去加载一个大的bitmaps,从而避免超出程序的内存限制。


    1.读取位图的尺寸与类型

    BitmapFactory 类提供了一些decode的方法 (decodeByteArray(), decodeFile(), decodeResource(), etc.) 用来从不同的资源中创建一个Bitmap. 根据你的图片数据源来选择合适的decode方法. 那些方法在构造位图的时候会尝试分配内存,因此会容易导致OutOfMemory的异常。每一种decode方法都提供了通过 B itmapFactory.Options 来设置一些附加的标记来指定decode的选项。设置 inJustDecodeBounds 属性为true可以在decoding的时候避免内存的分配,它会返回一个null的bitmap,但是 outWidth, outHeight 与 outMimeType 还是可以获取。这个技术可以允许你在构造bitmap之前优先读图片的尺寸与类型。

    通过下面的方式就可以在不加载内存的基础之上,获取到Bitmap的宽高和类型等信息

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;

   

 为了避免java.lang.OutOfMemory 的异常,我们需要在真正decode图片之前检查它的尺寸,除非你确定这个数据源提供了准确无误的图片且不会导致占用过多的内存。


    2.加载一个按比例缩小的版本到内存中

    通过上面的步骤我们已经知道了图片的尺寸,那些数据可以用来决定是应该加载整个图片到内存中还是加载一个缩小的版本。有下面一些因素需要考虑:
    ☞评估加载完整图片所需要耗费的内存。
    ☞程序在加载这张图片时会涉及到其他内存需求。
    ☞呈现这张图片的组件的尺寸大小。 
    ☞屏幕大小与当前设备的屏幕密度。
    

    例如,如果把一个原图是1024*768 pixel的图片显示到ImageView为128*96 pixel的缩略图就没有必要把整张图片都加载到内存中。
    为了告诉decoder去加载一个低版本的图片到内存,需要在你的BitmapFactory.Options 中设置 inSampleSize 为 true 。For example, 一个分辨率为2048x1536 的图片,如果设置 inSampleSize 为4,那么会产出一个大概为512x384的bitmap。加载这张小的图片仅仅使用大概0.75MB,如果是加载全图那么大概要花费12MB(前提都是bitmap的配置是 ARGB_8888). 下面有一段根据目标图片大小来计算Sample图片大小的Sample Code:


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

    设置inSampleSize为2的幂是因为decoder最终还是会对非2的幂的数进行向下处理,获取到最靠近2的幂的数。
    为了使用这个方法,首先需要设置 inJustDecodeBounds 为 true, 把options的值传递过来,然后使用 inSampleSize 的值并设置 inJustDecodeBounds 为 false 来重新Decode一遍。


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

    使用上面这个方法可以简单的加载一个任意大小的图片并显示为100*100 pixel的缩略图形式。像下面演示的一样:

mImageView.setImageBitmap(
    decodeSampledBitmapFromResource(getResources(), R.id.myimage, 100, 100));

    我以一张1920*1200的图为例,向你展示这样做之后产生的效果。

    下面是测试代码:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ImageView img = (ImageView) findViewById(R.id.img);
        long startTime = System.currentTimeMillis();
//        img.setImageBitmap(BitmapLoadUtils.decodeSampledBitmapFromResource(getResources(), R.drawable.mylove, 100, 100));
        img.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.mylove));
        Log.d("TAG", "alloca time = " + (System.currentTimeMillis() - startTime));

    }

    我们先看一下加载原图消耗的时间和内存,内存分配190ms,内存占用44.92M,因为我的Smartisan1内存充足,所以没问题,如果是比较老的机型,可能就直接崩掉了!


    

    下面我们再看使用小尺寸的运行结果,内存分配花费89ms,内存占用10.39M,相比之前内存少占用34.53M,所以说使用小尺寸的Bitmap时非常有必要的!





5楼The_Great_Engineer2小时前
很喜欢博主的文章,刚刚用豆约翰博客备份专家备份了您的全部博文。
Re: bz4199270892小时前
回复The_Great_Engineern推广好给力,到处都是你
4楼jiankeufo2小时前
哥们你是怎么看到使用内存大小的啊最后一张图片
Re: bz4199270892小时前
回复jiankeufonb这是as自带的,Memory Monitor,可以时时监控内存分配和垃圾回收,非常好用
3楼mtgodd4小时前
good
2楼cheyiliu5小时前
点赞
1楼Silver__Lining7小时前
你旁边这个个人说明好帅
Re: bz4199270896小时前
回复Silver__Liningn谢谢,嵌入的html代码,查看当前网页的源代码可以得到

文章评论

一个程序员的时间管理
一个程序员的时间管理
Java 与 .NET 的平台发展之争
Java 与 .NET 的平台发展之争
老美怎么看待阿里赴美上市
老美怎么看待阿里赴美上市
Google伦敦新总部 犹如星级庄园
Google伦敦新总部 犹如星级庄园
当下全球最炙手可热的八位少年创业者
当下全球最炙手可热的八位少年创业者
十大编程算法助程序员走上高手之路
十大编程算法助程序员走上高手之路
如何区分一个程序员是“老手“还是“新手“?
如何区分一个程序员是“老手“还是“新手“?
程序员的一天:一寸光阴一寸金
程序员的一天:一寸光阴一寸金
老程序员的下场
老程序员的下场
科技史上最臭名昭著的13大罪犯
科技史上最臭名昭著的13大罪犯
“肮脏的”IT工作排行榜
“肮脏的”IT工作排行榜
初级 vs 高级开发者 哪个性价比更高?
初级 vs 高级开发者 哪个性价比更高?
程序员周末都喜欢做什么?
程序员周末都喜欢做什么?
看13位CEO、创始人和高管如何提高工作效率
看13位CEO、创始人和高管如何提高工作效率
要嫁就嫁程序猿—钱多话少死的早
要嫁就嫁程序猿—钱多话少死的早
程序员和编码员之间的区别
程序员和编码员之间的区别
2013年美国开发者薪资调查报告
2013年美国开发者薪资调查报告
不懂技术不要对懂技术的人说这很容易实现
不懂技术不要对懂技术的人说这很容易实现
聊聊HTTPS和SSL/TLS协议
聊聊HTTPS和SSL/TLS协议
“懒”出效率是程序员的美德
“懒”出效率是程序员的美德
写给自己也写给你 自己到底该何去何从
写给自己也写给你 自己到底该何去何从
做程序猿的老婆应该注意的一些事情
做程序猿的老婆应该注意的一些事情
为啥Android手机总会越用越慢?
为啥Android手机总会越用越慢?
总结2014中国互联网十大段子
总结2014中国互联网十大段子
5款最佳正则表达式编辑调试器
5款最佳正则表达式编辑调试器
亲爱的项目经理,我恨你
亲爱的项目经理,我恨你
每天工作4小时的程序员
每天工作4小时的程序员
2013年中国软件开发者薪资调查报告
2013年中国软件开发者薪资调查报告
为什么程序员都是夜猫子
为什么程序员都是夜猫子
程序猿的崛起——Growth Hacker
程序猿的崛起——Growth Hacker
60个开发者不容错过的免费资源库
60个开发者不容错过的免费资源库
漫画:程序员的工作
漫画:程序员的工作
Web开发者需具备的8个好习惯
Web开发者需具备的8个好习惯
程序员最害怕的5件事 你中招了吗?
程序员最害怕的5件事 你中招了吗?
那些性感的让人尖叫的程序员
那些性感的让人尖叫的程序员
程序员必看的十大电影
程序员必看的十大电影
中美印日四国程序员比较
中美印日四国程序员比较
Web开发人员为什么越来越懒了?
Web开发人员为什么越来越懒了?
10个调试和排错的小建议
10个调试和排错的小建议
什么才是优秀的用户界面设计
什么才是优秀的用户界面设计
编程语言是女人
编程语言是女人
我跳槽是因为他们的显示器更大
我跳槽是因为他们的显示器更大
如何成为一名黑客
如何成为一名黑客
Java程序员必看电影
Java程序员必看电影
代码女神横空出世
代码女神横空出世
程序员眼里IE浏览器是什么样的
程序员眼里IE浏览器是什么样的
我的丈夫是个程序员
我的丈夫是个程序员
那些争议最大的编程观点
那些争议最大的编程观点
团队中“技术大拿”并非越多越好
团队中“技术大拿”并非越多越好
软件开发程序错误异常ExceptionCopyright © 2009-2015 MyException 版权所有