Android之解析加载大图

现在的世界是图片的世界,一切都只看如,就像“没图没真相”、“没图你说个XX”
可是图片有这么多,高清图片这么大,Android手机的内存又有限,用有限的内存加载无限大的图片,这是一个很严峻的问题,所以大图加载技术应运而生。

我们先看加载大图的全部代码,然后在细细解析代码的意思吧!

public class MainActivity extends Activity {

private ImageView iv;
private int screenWidth;
private int screenHeight;

@SuppressWarnings("deprecation")
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    
    //[1]找到iv 显示加载图片        
    iv = (ImageView) findViewById(R.id.iv);
    
    //[2]获取手机的分辨率  获取windowmanager 实例 
    WindowManager wm  = (WindowManager) getSystemService(WINDOW_SERVICE);
    // 用于android 8以上
    screenWidth = wm.getDefaultDisplay().getWidth();
    screenHeight = wm.getDefaultDisplay().getHeight();      
    // 只能用于android 13以上
    //Point outSize = new Point();
    //wm.getDefaultDisplay().getSize(outSize);
    //screenWidth = outSize.x;
    //screenHeight = outSize.y;
    
    System.out.println("手机的宽和高:"+screenWidth+"---"+screenHeight);
}

//点击按钮  加载dog.jpg 这张图片
@SuppressLint("SdCardPath")
public void click(View v) {
    //[2]把xxxx.jpg 转换成bitmap  
    
    //创建bitmap工厂的配置参数 
    BitmapFactory.Options options = new Options();
    
    //返回一个null 没有bitmap   不去真正解析位图 但是能返回图片的一些信息(宽和高)
    options.inJustDecodeBounds = true;
    BitmapFactory.decodeFile("/mnt/sdcard/xxxx.jpg",options);
    //[3]获取图片的宽和高  
    int imgWidth = options.outWidth;
    int imgHeight = options.outHeight;
    System.out.println("图片的宽:"+imgWidth+"-----"+imgHeight);
    
    //[4]计算缩放比 
    int scale = 1;  //我们定义的缩放比 
    int scalex =  imgWidth/screenWidth;
    int scaley = imgHeight /screenHeight;
    if (scalex >=scaley&&scalex > scale) {
        scale = scalex;
    }
    if (scaley > scalex && scaley>scale) {
        scale = scaley;
    }
    System.out.println("缩放比为:"+scale);      
    
    //[5]按照缩放比显示图片 
    options.inSampleSize = scale;
    
    //[6]开始真正的解析位图 
    options.inJustDecodeBounds = false;
    Bitmap bitmap = BitmapFactory.decodeFile("/mnt/sdcard/dog.jpg",options);
    
    //[7]把bitmap显示到控件上
    iv.setImageBitmap(bitmap);  
}
}

好了,上面就是解码大图Demo的全部代码了。
我们首先获得屏幕的大小,然后获得图片的大小,最后通过计算屏幕与图片的缩放比,按照缩放比来解析位图。

其中有两个方法比较重要,在这里我们进行解析:

options.inJustDecodeBounds

这一个方法的意思是,如果给它赋值true,那么它就不会解析图片,如果不解析图片,那么我们就不能够将图片展示在手机屏幕之中。
使用它的目的是为了获得图片的一些信息,如图片高度和宽度,然后进行下一步工作,也就是计算缩放比。
重点,在计算好缩放比(options.inSampleSize)之后不要忘记将options.inJustDecodeBounds设置为false,否则仍然不会展示图片。

options.inSampleSize 

这一个方法是给图片赋予缩放比,当它的值大于1的时候,它就会按照缩放比返回一个小图片用来节省内存。举个例子,如果她的值为4,那么返回的图片大小将会是原始高度和宽度的1/4大小。
如果它的值小于1的话,不会有任何的效果。
顺便友情提示options.inSampleSize的值最后会按照2的倍数来进行缩放,所以最好将缩放值设置为2的倍数。

关于计算缩放比的问题,在上面的代码中我们是直接通过图片高宽/屏幕高宽计算的,缩放比的值这是通过比较高度缩放比和宽度缩放比,那个数值大就取哪一个。
当然,这不是唯一的算法,也可以制定自己的算法。

补充说明:
计算缩放比,也就是inSampleSize的值的方式被 mcarthorlee 大神批评了,不过大神也说的对,

如果屏幕是1280720,图片大小是1300800,那你算出来的inSampleSize就是1,完全没有缩小。

为了让大家不被我的计算方式误导,这里也放出Android提供的缩放比计算方法:

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

在这个方法中,我们只需要提供图片的元数据options提供进去,然后填入自己想获得图片的宽高的数值,然后就能够计算出缩放比。

Android官方关于加载大图的技术指导:

https://developer.android.com/training/displaying-bitmaps/load-bitmap.html#

对大图需要特殊处理的原因

要对大图进行处理除了因为图片大小自身的原因之外,还有Android对图片解码的因素在内。

比如一张宽度2400px,高度为3200px的jpg格式的图片,假设它现在的大小为3mb,但是如果我们直接在android中解码,使用以下代码:

BitmapFactory.decodeFile("bigImage.jpg");

那么结果会怎样呢?

Android在解码这种图片的时候会申请29MB左右的内存来进行解码。

这是怎么回事呢?

因为图片的大小 = 图片总像素 * 图片当个像素的大小

在Android中使用ARGB来展示颜色的,一般情况下使用的是ARGB_8888,每个像素的大小约为4byte。

每个像素4 byte的是ARGB_8888,还有一个ARGB_4444是2 byte,RGB_565也是2 byte。

详情请看官方文档:

https://developer.android.com/reference/android/graphics/Bitmap.Config.html

所以上面的宽2400px,高3200px的大图在Android中解码出来的大小的计算公式:

2400 * 3200 * 4 = 30720000byte

换算成mb,大小为29mb左右。

这就无怪乎Android需要为加载大图做出特殊的处理了,就这么一张大小为2mb的jpg图片解码出来就有29mb,那么其他图片一起解码出来,Android的内存怎么够用!

以上为作者对Android加载大图的个人理解,如有错漏之处,请不吝赐教!

最后编辑于
?著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,100评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,308评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事?!?“怎么了?”我有些...
    开封第一讲书人阅读 159,718评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,275评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,376评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,454评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,464评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,248评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,686评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,974评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,150评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,817评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,484评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,140评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,374评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,012评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,041评论 2 351

推荐阅读更多精彩内容