android 图片加载
来源:互联网 发布:燕十八js高手之路 编辑:程序博客网 时间:2024/04/29 03:31
1.首先解析一下基本的知识
位图模式,bitmap颜色位数是1位
灰度模式,bitmap颜色位数是8位,和256色一样
RGB模式,bitmap颜色位数是24位 在RGB模式下,一个像素对应的是红、绿、蓝三个字节
CMYK模式,bitmap颜色位数是32位 在CMYK模式下,一个像素对应的是青、品、黄、黑四个字节
图像文件的字节数(Byte) =图像分辨率*颜色深度/8(bit/8)
例如:一幅640*480图像分辨率、RGB色一般为24位真彩色,图像未经压缩的数据容量为:640X480X24/8=921600字节=900KB(1KB=l千字节=1024字节)。
注:一个图像文件占的磁盘空间大小还和磁盘的文件格式有关。如:NTFS最小单位为4KB 所以图像文件大小肯定是4KB的倍数。但是有图图片压缩算法的存在,图片文件在保存时,体积要比在内存的大小小得多,如640x480的图片文件大小一般只在200K~300K。这也是为什么,加载几MB的图片文件,会导致JVM内存溢出,导致OutofMemoryException的原因。由上面的公式,我们可以得出,加载的图片所占的内存大小,取决于其分辨率和颜色数。
2. Android虚拟机(DVM)内存分配
堆(HEAP)是VM中占用内存最多的部分,通常是动态分配的。堆的大小不是一成不变的,通常有一个分配机制来控制它的大小。比如初始的HEAP是4M大,当4M的空间被占用超过75%的时候,重新分配堆为8M大;当8M被占用超过75%,分配堆为16M大。倒过来,当16M的堆利用不足30%的时候,缩减它的大小为8M大。重新设置堆的大小,尤其是压缩,一般会涉及到内存的拷贝,所以变更堆的大小对效率有不良影响。可以看到三个参数:max heap size, min heap size, heap utilization(堆利用率)。
Max Heap Size,是堆内存的上限值,Android的缺省值是16M(某些机型是24M),对于普通应用这是不能改的。函数setMinimumHeapSize其实只是改变了堆的下限值,它可以防止过于频繁的堆内存分配,当设置最小堆内存大小超过上限值时仍然采用堆的上限值(16M),对于内存不足没什么作用。VMRuntime.getRuntime().setTargetHeapUtilization 可以设定内存利用率的百分比,当实际的利用率偏离这个百分比的时候,虚拟机会在GC的时候调整堆内存大小,让实际占用率向个百分比靠拢。由于每个app都有最大堆内存的限制,因此加载图片时,如果超出这个限制,则会报OutofMemoryException。
3.android加载图片的方式
1)通过java层分配内存
Resources.getDrawable
BitmapFactory.decodeResource
Bitmap.createBitmap
Bitmap.createScaledBitmap
通过Java层来createBitmap来完成图片的加载,增加了java层的内存消耗。使得app很容易就超出最大堆内存的限制。
2)通过native本地代码分配内存
BitmapFactory.decodeFile
BitmapFactory.decodeStream
直接调用JNI>>nativeDecodeAsset()来完成decode,无需再使用java层的createBitmap,从而节省了java层的空间。
a.解析图片宽高:
BitmapFactory.Options options = newBitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeStream(stream, null,options);
通过此方式,我们可以解析出图片的宽高,而不必把整张图片加载到内存,然后将options传给computeSampleSize计算采样频率,根据计算得到的inSampleSize加载图片,这样可以节省内存。
b. 计算采样频率
public static int computeSampleSize(BitmapFactory.Options options,
int minSideLength, int maxNumOfPixels) {
int initialSize = computeInitialSampleSize(options, minSideLength,
maxNumOfPixels);
int roundedSize;
if (initialSize <= 8 ) {
roundedSize = 1;
while (roundedSize < initialSize) {
roundedSize <<= 1;
}
} else {
roundedSize = (initialSize + 7) / 8 * 8;
}
return roundedSize;
}
public static int computeInitialSampleSize(BitmapFactory.Options options,
int minSideLength, int maxNumOfPixels) {
double w = options.outWidth;
double h = options.outHeight;
int lowerBound = (maxNumOfPixels == UNCONSTRAINED) ? 1 :
(int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
int upperBound = (minSideLength == UNCONSTRAINED) ? 128 :
(int) Math.min(Math.floor(w / minSideLength),
Math.floor(h / minSideLength));
if (upperBound < lowerBound) {
// return the larger one when there is no overlapping zone.
return lowerBound;
}
if ((maxNumOfPixels == UNCONSTRAINED) &&
(minSideLength == UNCONSTRAINED)) {
return 1;
} else if (minSideLength == UNCONSTRAINED) {
return lowerBound;
} else {
return upperBound;
}
}
c.实际加载图片:
BufferedInputStream bs = new BufferedInputStream(fs,16348);
// decode image size
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inScaled = false;
options.inDither = true;
//options.inSampleSize = scale;
options.inSampleSize = ImageUtils.computeSampleSize(bs,
MAX_IMAGE_HEIGHT, MAX_IMAGE_WIDTH);
FileInputStream fbmp = new FileInputStream(f);
Bitmap bmp = BitmapFactory.decodeStream (fbmp, null, options);
- Android 图片异步加载 加载网络图片
- android加载网络图片,圆形图片加载
- android加载本地图片
- Android图片加载机制
- android 加载图片方式
- android异步加载图片
- android 异步加载图片
- android中加载图片
- android异步加载图片
- android异步加载图片
- android 图片加载进度条
- android加载网络图片
- android 加载图片方式
- Android 异步加载图片
- android 图片加载 方法
- Android 异步加载图片
- Android图片异步加载
- Android图片异步加载
- Hadoop集群Master节点部署方案
- UVa739 - Soundex Indexing
- 用一条SQL语句将数据表中某列更新到另一个数据表里
- Spring数据校验JPA及遇见错误解决方法。
- C++: byte 和 int 的相互转化
- android 图片加载
- Windows的build版本:chk和fre的区别
- C#数据类型的转换
- www-authenticate认证过程浅析
- 迭代求解
- coding - 计算由n到1最少次数
- #pragma指令
- OnInitialUpdate
- 命令行出错Exception in thread "main" java.lang.UnsupportedClassVersionError: