美文网首页
APP查找图片资源时遵循先高后低原则(hdpi,mdpi,xhd

APP查找图片资源时遵循先高后低原则(hdpi,mdpi,xhd

作者: 陈萍儿Candy | 来源:发表于2020-09-18 20:00 被阅读0次

1.图片布局

<ImageView
        android:id="@+id/iv_mdpi"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_constraintLeft_toLeftOf="parent"/>
private void loadBitmap(final ImageView imageView) {
        BitmapFactory.Options options = new BitmapFactory.Options();
        // 前提  imageView设置的是wrapcontent

        // 三张不同的图片,命名都是icon_fox_sleep_0,分别放到xhdpi(320),xxhdpi(480),xxxhdpi(640)
        // 运行手机屏幕密度 420,运行后用的是xxhdpi下的图片,图片在xxhdpi下是222*170,运行到手机中,宽高缩小420/480,是194*149
        // 图片在手机中的内存自然变小

        // 两张不同的图片,命名都是icon_fox_sleep_0,分别放到xhdpi(320),xxxhdpi(640)
        // 运行手机屏幕密度 420,运行后用的是xxxhdpi下的图片,图片在xxxhdpi下是222*170,运行到手机中,宽高缩小420/640,是146*112
        // 图片在手机中的内存自然变小

        // 只有一张图片,放到xhdpi(320)中,从xxhdpi,xxxhdpi中都没有找到,就从低的xhdpi中寻找,然后放大420/320,
        // 内存也变大

        // 以上证明,APP查找图片资源时遵循先高后低原则,屏幕密度是420的手机,图片查找先从xxhdpi(480)查找,没有从xxxhdpi(640)查找,还是没有再从低的xhdpi查找,以此类推

        Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.icon_fox_sleep_0, options);
       imageView.setImageBitmap(bitmap);
     //   imageView.setImageResource(R.mipmap.icon_fox_sleep_0);

        // getByteCount获取图片的大小  图片大小计算方法  图片在运行手机中的宽高(所占用的像素点数),乘以图片每个像素点占用的大小(Config,比如:ARGB_8888占用4个字节)
        Log.i(TAG, "loadBitmap: bitmap getByteCount:" + bitmap.getByteCount() + "," + bitmap.getAllocationByteCount());

        // bitmap图片在运行手机中的宽高,计算方法:图片宽X手机的densityDpi/图片的densityDpi
        // 图片的densityDpi:xhdpi(超高)~320dpi
        // 此图的宽高在studio中是222*170  高170在运行手机的内存中大小为170*手机的densityDpi/图片的densityDpi  即170*480/320
        // 图片在手机中的内存大小 (222*480/320)*(170*480/320)*6
        Log.i(TAG, "loadBitmap: width "+bitmap.getWidth()+",height "+bitmap.getHeight());

        // options.inDensity为图片所在的文件夹对应的像素密度dpi,如:xhdpi(超高)~320dpi
        // options.inTargetDensity 运行的手机的像素密度,比如我的手机是480
        Log.i(TAG, "loadBitmap: "+options.inDensity+","+options.inTargetDensity);

        DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
        // 手机像素密度比例值 比如我的手机的像素密度是480  480/160 = 3
        float dens = displayMetrics.density;
        Log.i(TAG, "loadBitmap: dens "+dens);

        // 手机的像素密度 480
        int densityDpi = displayMetrics.densityDpi;
        Log.i(TAG, "loadBitmap: densityDpi"+densityDpi);

        // bitmap图片的argb格式,通过这个可以得到图片的每个像素点所占用的内存大小
        // ALPHA_8 1byte  RGB_565 2byte   ARGB_4444 2byte   ARGB_8888 4 bytes
        Bitmap.Config config = bitmap.getConfig();
        Log.i(TAG, "loadBitmap: config "+config);

        imageView.post(new Runnable() {
            @Override
            public void run() {
                Log.i(TAG, "loadBitmap: "+imageView.getWidth()+","+imageView.getHeight());
            }
        });

    }

解压缩后的图片大小 = 图片的像素宽 * 图片的像素高 * 每个像素所占的字节数

运行上述代码,bitmap.getByteCount或者bitmap.getAllocationByteCount的值,通过上述公式计算得到
bitmap.getWidth() * bitmap.getHeight() * 4(argh_8888)

疑问:如果我的imageview在xml中设置的是固定的宽高,图片的内存大小还是如上计算吗??
答案:是的

https://www.cnblogs.com/Potato-Eater/p/9781162.html

https://www.cnblogs.com/dasusu/p/9789389.html

图片的不同格式:png 或者 jpg 对于图片所占用的内存大小其实并没有影响. 有待验证

这里像素点大小以 4B 来计算是因为,当没有特别指定时,系统默认为 ARGB_8888 作为像素点的数据格式,其他的格式如下:

  • ALPHA_8 -- (1B)
  • RGB_565 -- (2B)
  • ARGB_4444 -- (2B)
  • ARGB_8888 -- (4B)
  • RGBA_F16 -- (8B)

误区:图片占据内存空间大小与图片在界面上显示的大小会有关系,显示控件越大占用内存越多
错误:图片占据内存空间大小和图片在界面上显示的大小没有关系

重点:当图片在磁盘中,SD 卡也好,assert 目录也好,网络也好(网络上的图片其实最终也是下载到磁盘),只要不是在 res 目录内,那么图片占据内存大小的计算公式,就是按原图的分辨率 * 像素点大小来。

ivBitmap.setImageResource(R.mipmap.icon_fox_sleep_0);
占用的内存大小和BitmapFactory.decodeResource方法转化为bitmap,ivBitmap.setImageBitmap占用的内存一样吗?
是一样的,代码中都是转化为bitmap,都遵循先高后低。

Xml中ImageView设置src和ivBitmap.setImageResource一样

Imageview。setImageDrawable和setImageBitmap区别
都是遵循先高后低
主要是setImageBitmap最后也是转化为BitmapDrawable,都是drawable,但是外面调用setImageDrawable时转化为drawable的方法影响这两个方法占用的内存是否一样。

setImageResource(id)会根据设备分辨率进行图片大小缩放适配。
setImageBitmap(BitmapFactory.decodeResource(res, id))大小需要手动调。
如果提供了完整的各种分辨率下的图片,两种方法没有区别。

setImageDrawable是最省内存最高效的,如果担心图片过大或者图片过多影响内存和加载效率,可以自己解析图片然后通过调用setImacgeDrawable方法进行设置

setImageResource:这个方法是在UI线程中对图片读取和解析的,所以有可能对一个Activity的启动造成延迟。所以如果顾虑到这个官方建议用setImageDrawable和setImageBitmap来代替。

setImageBitmap:做的事情就是把Bitmap对象封装成Drawable对象,然后调用setImageDrawable来设置图片。因此代码里面才写上了建议,如果需要频繁调用这个方法的话最好自己封装个固定的Drawable对象,直接调用setImageDrawable,这样可以减少Drawable对象。因为每次调用setImageBitmap方法都会对Bitmap对象new出一个Drawable

setImageDrawable参数是Drawable,也是可以接受不同来源的图片,方法中所做的事情就是更新ImageView的图片。上面两个方法实际上最后调用的都是setImageDrawable(setImageResource没有直接调用,不过更新的方法与setImageDrawable一样)。

三个方法都会把图片转换为drawable,转换为drawable时都会考虑屏幕密度进行图片的缩放

图片肯定是先加载进内存后,才绘制到控件上,那么当图片要申请内存空间时,它此时还不知道要显示的控件大小的,怎么可能控件的大小会影响到图片占用的内存空间呢,除非提前告知,手动参与图片加载过程。

相关文章

网友评论

      本文标题:APP查找图片资源时遵循先高后低原则(hdpi,mdpi,xhd

      本文链接:https://www.haomeiwen.com/subject/dnzjyktx.html