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时都会考虑屏幕密度进行图片的缩放
图片肯定是先加载进内存后,才绘制到控件上,那么当图片要申请内存空间时,它此时还不知道要显示的控件大小的,怎么可能控件的大小会影响到图片占用的内存空间呢,除非提前告知,手动参与图片加载过程。
网友评论