Bitmap的深入理解

Android内存分配

Java Head(Dalvik Head),这部分的内存是由Dalvik虚拟机管理,可以通过java的new方法来分配内存;而内存的回收是符合GC Root回收规则。内存的大小受到系统限制,如果使用内存超过App最大可用内存时会抛出OOM错误。

Native Head,这部分内存,不受Dalvik虚拟机管理的,内存的分配和回收是通过C++的方式来创建和释放的,没有自动回收机制。而内存的大小受硬件的限制(手机内存的限制)。

Ashmem(Android匿名共享内存),这部分内存和Native内存区类似,有点不同的是,它是由Android系统底层管理的,Android系统在内存不足时,会回收Ashmem区域中状态是unpin的对象内存,如果不希望对象被回收,可以通过pin来保护一个对象。

Bitmap内存

Bitmap对象的内存分为两部分:

  • Bitmap对象
  • Bitmap像素数据(即一张图片的数据)。

在Android 2.3.3(API 10)之前,Bitmap的像素数据的内存时分配在Native堆上的,而Bitmap对象的内存则分配在Dalvik堆上的;

由于Native堆上的内存时不受DVM管理的,如果想要回收Bitmap的所占用内存的话,那么需要调用Bitmap.recyle()方法。

而API 10之后呢,谷歌将像素数据的内存分配也移到DVM堆上,由DVM管理,因此在dvm回收前;

只需要保证Bitmap对象不被任何GC Roots强引用就可以回收这部分内存。

Bitmap.Config

Bitmap.Config是影响图片画质的重要因素,单位像素占用字节越大,画质越高。ARGB是一种存储色彩的模式,其中A:透明度;R:红色;G:绿色;B:蓝色

Bitmap.Config 描述 占用内存(字节)
Bitmap.Config ARGB_8888 表示32位的ARGB位图 4
Bitmap.Config ARGB_4444 表示16位的ARGB位图 2
Bitmap.Config RGB_565 表示16位的RGB位图 2
Bitmap.Config ALPHA_8 表示16位的Alpha位图 1

注意:ARGB_8888单位像素点占用内存是最高的,所以该模式下画质最好,虽然ARGB_4444单位像素点占用内存是ARGB_8888的一般,但是画质较差,如果不需要Alpah通道的话,可以使用RGB_565,jpg格式图片是没有Alpha通道的

density,densityDpi,targetDensity的区别

density densityDpi(dpi) 分辨率 res
1 160 320 X 533 mdpi
1.5 240 480 X 800 hdpi
2 320 720 X 1280 xhdpi
3 480 1080 X 1920 xxhdpi
3.5 560 xxxhdpi

density:密度,指每平方英寸中的像素数,在DisplayMetrics类中属性density的值为dpi/160

densityDpi,单位密度下可存在的点。

Bitmap对象创建

Bitmap的构造方法不是共有的,因此外部不能通过new的方式来创建,不过可以Bitmap的createBitmap方法和BitmapFactory

Bitmap

createBitmap -> nativeCreate

Bitmap中的

BitmapFactory

// resource
BitmapFactory.decodeResource(...)
// 字节数组
BitmapFactory.decodeByteArray()
// 文件
BitmapFactory.decodeFile()
// 流
BitmapFactory.decodeStream()
// FileDescriptor
BitmapFactory.decodeFileDescriptor()

decodeResource流程图

Created with Rapha?l 2.1.0decodeFiledecodeResourceStreamdecodeStream返回Bitmap

decodeResourceStream方法会inDensity和inTargetDensity进行处理,如果inDensity值为0的话,那么则会采用默认的(160dp),

同样,如果inTargetDensity值为0的话,会使用手机系统的density

比如手机的分辨率是720*1280的话,那么手机的density为320,则inTargetDensity=320。

这两个值影响图片最终显示出来是否缩放。

decodeFile流程图

c1=>operation: decodeFile|current
c2=>operation: decodeStream|current
e2=>operation: 返回Bitmap

c1(right)->c6->e2

decodeStream流程图

Created with Rapha?l 2.1.0decodeStream是否是Assets目录下的流nativeDecodeAsset返回BitmapdecodeStreamInternalnativeDecodeStreamyesno

decodeByteArray流程图

Created with Rapha?l 2.1.0decodeByteArraynativeDecodeByteArray

decodeFileDescriptor流程图

Created with Rapha?l 2.1.0decodeFileDescriptornativeIsSeekablenativeDecodeFileDescriptor返回BitmapnativeDecodeStreamyesno

Bitmap占用内存计算

Bitmap占用内存计算 = 图片最终显示出来的宽 * 图片最终显示出来的高 * 图片品质(Bitmap.Config的值)

比如SDcard中A图片的分辨率为300 X 600,使用ARGB_8888的品质加载,那么这张图片占用的内存 = 300 * 600 * 4 = 720000(byte) = 0.686(mb)

Bitmap中哟getByteCount()可以获取图片占用内存字节大小。

注意,为什么计算的公式是图片最终显示出来的宽 * 图片最终显示出来的高,而不是,图片的宽和图片的高呢?

主要是这样的,Android为了适配不同分辨率的机型,对放到不同drawable下的图片,在创建Bitmap的过程中,进行了缩放判断,如果需要缩放的话,

那么最终创建出来的图片宽和高都进行了修改。

ImageView iv = (ImageView) findViewById(R.id.iv);
Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.french_girl);
iv.setImageBitmap(bitmap);

bitmap创建流程,decodeResource -> decodeStream -> nativeDecodeStream;可以看到最终是通过jni调用nativeDecodeStream方法来创建Bitmap。

BitmapFactory.cpp

nativeDecodeStream

static jobject nativeDecodeStream(JNIEnv* env, jobject clazz, jobject is, jbyteArray storage,
        jobject padding, jobject options) {

    jobject bitmap = NULL;
    SkAutoTUnref<SkStream> stream(CreateJavaInputStreamAdaptor(env, is, storage));
    if (stream.get()) {
        SkAutoTUnref<SkStreamRewindable> bufferedStream(SkFrontBufferedStream::Create(stream, 64));
        SkASSERT(bufferedStream.get() != NULL);
        // 调用doDecode方法创建bitmap
        bitmap = doDecode(env, bufferedStream, padding, options, false, false);
    }
    return bitmap;
}

doDecode

static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding,
        jobject options, bool allowPurgeable, bool forcePurgeable = false) {

    // ....省略

    float scale = 1.0f;

    // ....省略
    if (options != NULL) {

        // ....省略

        // 计算出图片是否需要缩放
        // density,如果不设置opts.inDensity的话,该值默认为160, 代码查看BitmapFactory中decodeResourceStream方法
        // 比如,如果图片放到drawable-hdpi目录下,该值为240,
        // targetDensity,如果不设置opts.inTargetDensity的话,该值默认为DisplayMetrics的densityDpi,注意该值是由手机自身设置的
        // 比如720 X 1280分辨率的手机,该值为320;1080 X 1920分辨率的手机,该值为480
        // scale = (float) targetDensity / density;
        // 图片放到drawable-hdpi目录下,手机分辨率为720*1280;scale = 320 / 240 = 1.333
        if (env->GetBooleanField(options, gOptions_scaledFieldID)) {
            const int density = env->GetIntField(options, gOptions_densityFieldID);
            const int targetDensity = env->GetIntField(options, gOptions_targetDensityFieldID);
            const int screenDensity = env->GetIntField(options, gOptions_screenDensityFieldID);
            if (density != 0 && targetDensity != 0 && density != screenDensity) {
                scale = (float) targetDensity / density;
            }
        }
    }

    // 判断图片是否需要缩放
    const bool willScale = scale != 1.0f;
    isPurgeable &= !willScale;

    // 图片缩放宽高默认为原图宽高
    int scaledWidth = decodingBitmap.width();
    int scaledHeight = decodingBitmap.height();

    if (willScale && mode != SkImageDecoder::kDecodeBounds_Mode) {
        // 计算出缩放后图片的宽高,也就是最终显示出来的宽高
        scaledWidth = int(scaledWidth * scale + 0.5f);
        scaledHeight = int(scaledHeight * scale + 0.5f);
    }

    // 更新options
    if (options != NULL) {
        // 设置图片最终显示出来的宽高为缩放后的宽高
        env->SetIntField(options, gOptions_widthFieldID, scaledWidth);
        env->SetIntField(options, gOptions_heightFieldID, scaledHeight);
        env->SetObjectField(options, gOptions_mimeFieldID,
                getMimeTypeString(env, decoder->getFormat()));
    }

    // ....省略

    // 创建Bitmap对象
    return GraphicsJNI::createBitmap(env, outputBitmap, javaAllocator.getStorageObj(),
            bitmapCreateFlags, ninePatchChunk, layoutBounds, -1);
}

原图大小为165*221,图片放到drawable-hdpi目录下,手机分辨率为720*1280:

ImageView iv = (ImageView) findViewById(R.id.iv);
Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.french_girl);
iv.setImageBitmap(bitmap1);
Log.d("MYTAG", "getByteCount " + bitmap1.getByteCount());
Log.d("MYTAG", "getRowBytes " + bitmap1.getRowBytes());
Log.d("MYTAG", "getHeight " + bitmap1.getHeight());
Log.d("MYTAG", "getHeight " + bitmap1.getWidth());

输出

MYTAG: getByteCount 259600
MYTAG: getRowBytes 880
MYTAG: getHeight 295
MYTAG: getHeight 220

如果是:图片占用内存 = 图片宽 * 图片高 * Bitmap.Config

那么这张图所占用内存 = 165 * 221 * 4 = 145860(b) = 142.44(kb)

但是打印出出来的值为259600,很明显该Bitmap在创建的时候,进行了缩放

而使用图片占用内存 = 图片最终的宽 * 图片最终的高 * Bitmap.Config

scale = (float) targetDensity / density = 320 / 240 = 1.333

scaledWidth = int(scaledWidth * scale + 0.5f) = 165 * 1.333 + 0.5 = 220

scaledHeight = int(scaledHeight * scale + 0.5f) = 221 * 1.333 + 0.5 = 295

图片占用内存 = 220 * 295 * 4 = 259600

从上面知道,opts.inDensity和opts.inTargetDensity是影响图片最终创建出来的大小,那么如果我将这两个值设置为相同的,

不出意外的话,图片占用内存=图片宽 * 图片高 * Bitmap.Config

原图大小为165*221,图片放到drawable-hdpi目录下,手机分辨率为720*1280:

通过计算,Bitmap占用内存 = 165 * 221 * 4 = 145860

ImageView iv = (ImageView) findViewById(R.id.iv);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inDensity = 160;
options.inTargetDensity = 160;
Bitmap bitmap1 = BitmapFactory.decodeResource(getResources(), R.drawable.french_girl, options);
iv.setImageBitmap(bitmap1);
Log.d("MYTAG", "getByteCount " + bitmap1.getByteCount());
Log.d("MYTAG", "getRowBytes " + bitmap1.getRowBytes());
Log.d("MYTAG", "getHeight " + bitmap1.getHeight());
Log.d("MYTAG", "getHeight " + bitmap1.getWidth());

输出

MYTAG: getByteCount 145860
MYTAG: getRowBytes 660
MYTAG: getHeight 221
MYTAG: getHeight 165

Bitmap加载大图

一张分辨率为 5400 X 3600的图片,使用ARGB_8888的方式加载,那么这张图占用内存= 5400 * 3600 * 4 = 77760000(byte) = 74.15(MB)

毫无疑问,App只要加载这张74.15m的图片,肯定会抛出OOM错误的。

一般情况,我们会设置inSampleSize,inPreferredConfig等来降低图片占用的内存,但是这样的话,图片就变成有损显示了。

如果想要无损显示的话,那么就得使用BitmapRegionDecoder类。

BitmapRegionDecoder:是用来解码一张图片的某个矩形区域,可以通过BitmapRegionDecoder.newInstance方法创建一个BitmapRegionDecoder对象,

然后再通过BitmapRegionDecoder的decodeRegion方法获取图片某一区域的Bitmap。

Bitmap优化

在我看来,Bitmap的优化主要是加快图片的加载速度和降低图片占用内存的大小

加快Bitmap的加载速度

简略的说,图片的显示,无非就是将不同来源的图片文件,加载到Android系统内存中,然后创建Bitmap对象,最后将Bitmap渲染出来。

来源不同的文件,加载的速度是不同的,内存 > 硬盘(本地)> 网络。

因此,我们也应该,尽量将不同来源的图片保存到内存中,因为内存时最快由被系统使用。

这里,我们主要是使用优秀的图片加载框架(比如Picasso,Glide,Fresco等),管理图片,这里不做详细的探讨。

降低Bitmap占用内存的大小

Bitmap占用内存大小 = Bitmap最终的宽度 * Bitmap最终的高度 * Bitmap.Config的值

通过公式,可以看出,对上面3个值,只要任意减少一个值,都可以达到降低占用内存的大小

影响Bitmap.Config:

  • inPreferredConfig,该值默认为ARGB_8888,占用4个字节

影响Bitmap最终的宽高:

  • inSampleSize,inDensity,inTargetDensity,inScaled,
public Bitmap inBitmap;  //是否重用该Bitmap,注意使用条件,Bitmap的大小必须等于inBitmap,inMutable为true
public boolean inMutable;  //设置Bitmap是否可以更改
public boolean inJustDecodeBounds; // true时,decode不会创建Bitmap对象,但是可以获取图片的宽高
public int inSampleSize;  // 压缩比例,比如=4,代表宽高压缩成原来的1/4,注意该值必须>=1
public Bitmap.Config inPreferredConfig = Bitmap.Config.ARGB_8888;  //Bitmap.Config,默认为ARGB_8888
public boolean inPremultiplied; //默认为true,一般不需要修改,如果想要修改图片原始编码数据,那么需要修改
public boolean inDither; //是否抖动,默认为false
public int inDensity; //Bitmap的像素密度
public int inTargetDensity; //Bitmap最终的像素密度(注意,inDensity,inTargetDensity影响图片的缩放度)
public int inScreenDensity; //当前屏幕的像素密度
public boolean inScaled; //是否支持缩放,默认为true,当设置了这个,Bitmap将会以inTargetDensity的值进行缩放
public boolean inPurgeable; //当存储Pixel的内存空间在系统内存不足时是否可以被回收
public boolean inInputShareable; //inPurgeable为true情况下才生效,是否可以共享一个InputStream
public boolean inPreferQualityOverSpeed; //为true则优先保证Bitmap质量其次是解码速度
public int outWidth; //Bitmap最终的宽
public int outHeight;  //Bitmap最终的高
public String outMimeType; //
public byte[] inTempStorage; //解码时的临时空间,建议16*1024

inJustDecodeBounds

inJustDecodeBounds属性,设置为true时,decode不会创建Bitmap对象。

如果想要获取Bitmap的宽高,但又不想将Bitmap加载到内存中(比如将一张分辨率非常高的图片,只要加载到内存中,就会抛出OOM),

那么我们必须得inJustDecodeBounds设置为true

使用BitmapFactory创建Bitmap,最终是调用jni中BitmapFactory.cpp中的doDecode方法的。

doDecode

static jobject doDecode(JNIEnv* env, SkStreamRewindable* stream, jobject padding,
        jobject options, bool allowPurgeable, bool forcePurgeable = false) {

    // mode默认为SkImageDecoder::kDecodePixels_Mode;
    SkImageDecoder::Mode mode = SkImageDecoder::kDecodePixels_Mode;

    // ...省略

    if (options != NULL) {
        sampleSize = env->GetIntField(options, gOptions_sampleSizeFieldID);
        // 获取inJustDecodeBounds的值,如果是true的话,mode设置为SkImageDecoder::kDecodeBounds_Mode;
        if (optionsJustBounds(env, options)) {
            mode = SkImageDecoder::kDecodeBounds_Mode;
        }
        // ...省略
    }

    // ...省略 中间计算出Bitmap的宽度和高度,并设置到options中
    // inJustDecodeBounds为true时,返回null
    if (mode == SkImageDecoder::kDecodeBounds_Mode) {
        return NULL;
    }

    // ...省略
    return GraphicsJNI::createBitmap(env, outputBitmap, javaAllocator.getStorageObj(),
            bitmapCreateFlags, ninePatchChunk, layoutBounds, -1);
}

inSampleSize

inSampleSize,是调整Bitmap压缩比例的,该值必须>=1,比如inSampleSize = 2,那么Bitmap的宽和高都变为原来的1/2

Bitmap.compress方法压缩图片

除了调整inSampleSize,inDensity,inTargetDensity对图片进行压缩外,Bitmap.compress()方法同样也可以对Bitmap进行压缩。

public boolean compress(CompressFormat format, int quality, OutputStream stream) 
  • CompressFormat format:压缩格式,三种类型:JPEG,PNG,WEBP
  • int quality: 压缩品质,该值必须在[0, 100]区间内,值越大,品质越高
  • OutputStream stream:压缩成功后,Bitmap输出流
public boolean compress(CompressFormat format, int quality, OutputStream stream) {
    checkRecycled("Can‘t compress a recycled bitmap");
    if (stream == null) {
        throw new NullPointerException();
    }
    if (quality < 0 || quality > 100) {
        throw new IllegalArgumentException("quality must be 0..100");
    }
    Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "Bitmap.compress");
    boolean result = nativeCompress(mFinalizer.mNativeBitmap, format.nativeInt,
            quality, stream, new byte[WORKING_COMPRESS_STORAGE]);
    Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
    return result;
}

compress,首先会进行参数检测,然后调用jni中nativeCompress的方法进行压缩

例子

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    iv = (ImageView) findViewById(R.id.iv);

    Bitmap bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.french_girl);
    ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
    bitmap.compress(Bitmap.CompressFormat.JPEG, 10, outputStream);
    byte[] bytes = outputStream.toByteArray();
    bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.length);
    iv.setImageBitmap(bitmap);
}

inBitmap 和 inPurgeable

  • inBitmap:主要是重用该Bitmap的内存区域,避免多次重复向dvm申请开辟新的内存区域。
  • inPurgeable:设置为True,则使用BitmapFactory创建的Bitmap用于存储Pixel的内存空间,在系统内存不足时可以被回收,当应用需要再次访问该Bitmap的Pixel时,系统会再次调用BitmapFactory 的decode方法重新生成Bitmap的Pixel数组。 设置为False时,表示不能被回收

为了更好的理解这两个参数,我们需要理解下Android管理Bitmap内存的过程:

“stop the world”是指发生GC时,除了GC所需要的线程,其他的线程都会处于等待状态,直到GC完毕。

在Android 2.2(API 8)以及之前,DVM发生GC的时候,会引发”stop the world”,这样会导致应用停滞。而在Android 2.3上,Android引入并发GC机制,并发GC机制是不会引发”stop the world”。

在Android2.3.3(API 10)以及之前,Bitmap的像素数据是分配在Native堆上的,想要回收Bitmap,那么必须得调用bitmap.recyle()方法;而之后,Bitmap的像素数据和Bitmap对象一起分配到DVM堆上,由DVM管理,bitmap的回收只需要置为null,不需要调用recyle()方法。

还有另外一点,上面我们说过Android中对象的内存除了可以在DVM堆和Native堆上分配外,还可以在匿名共享内存中分配。

Ashmem上,一般在应用中是无法直接访问的,但是可以通过设置BitmapFactory.Optinons.inPurgeable = true,创建一个Purgeable(可擦除的) Bitmap,

这样的decode出来的bitmap,其像素数据是分配在Ashmem内存中的。Ashmem内存上的对象有两种状态:pinunpin,当一个对象状态处于pin状态,可以通过设置

unpin,这样系统就可以回收对象的内存。

但是存在一个问题,当一个unpin的bitmap已经被回收,如果再次使用这个bitmap的时候,系统会对它进行重新decode,而decode方法是发生在主线程上的,

这样就有可能产生掉帧现象,因此该做法被Google废弃掉了,建议使用inBitmap

但是使用inBitmap属性,需要主要注意几点:

  • inBitmap只能在3.0以后使用,在这之前Bitmap的像素数据是分配在Native堆上的。
  • 在SDK 11 - 18之间,创建Bitmap大小必须和重用Bitmap大小一致,比如重用Bitmap的大小为100 * 100,那么创建Bitmap的大小同样也要100 * 100
  • 在SDK 19 上以及之后,创建Bitmap大小必须等于或者小于重用Bitmap大小。
  • Bitmap的格式必须一样,比如重用Bitmap的格式为ARGB_8888,那么创建的Bitmap格式同样也得是ARGB_8888

参考:

Android Bitmap 优化(1) - 图片压缩

Android中Bitmap和Drawable

Android 开发绕不过的坑:你的 Bitmap 究竟占多大内存?

Android 高清加载巨图方案 拒绝压缩图片

Android内存优化之OOM

Fresco的内存机制

Fresco学习

Android性能优化:谈谈Bitmap的内存管理与优化

Android性能优化之Bitmap的内存优化

BitmapFactory和Bitmap中Density的作用

Bitmap基本概念及在Android4.4系统上使用BitmapFactory的注意事项

Android Bitmap.setDensity(int density) 和 BitmapDrawable.setTargetDensity()

inDensity,inTargetDensity,inScreenDensity关系详解

那些值得你去细细研究的Drawable适配

Android Training - 高效地显示Bitmap(Lesson 4 - 优化Bitmap的内存使用)

时间: 2024-08-01 22:18:42

Bitmap的深入理解的相关文章

阿里巴巴、百度Android实习生,面试之旅(下)

上一篇说到笔试结束,这一篇就从面试开始说.阿里巴巴是4月2号笔试的,百度笔试是在4月19号,然后阿里巴巴一周就会给一个结果,不管你过不过,百度就不会了,尤其是简历赛选环节,根本不会给你通知,都不知道是还在筛选还是没过,非常坑-我去年投的的一个实习生,现在简历还在筛选中,我一个同学和我一起投的,只是岗位不一样,到现在百度都还没给通知,都不知道是什么问题. 说一个题外话,我的情况可能和各位要去实习的不一样,我是大四的,今年九月份是要上研究生的,想趁毕业到开学这段时间去实习,所以我是不符合公司招聘的条

手把手教你画一个 逼格满满圆形水波纹loadingview Android

才没有完结呢o( ̄︶ ̄)n .大家好,这里是番外篇. 拜读了爱哥的博客,又学到不少东西.爱哥曾经说过: 要站在巨人的丁丁上. 那么今天,我们就站在爱哥的丁丁上来学习制作一款自定义view(开个玩笑,爱哥看到别打我). 转载请注明出处:http://blog.csdn.net/wingichoy/article/details/50523713 上一篇 带领大家做了一款炫酷的loading动画view 手把手带你做一个超炫酷loading成功动画view  不知道大家跟着做了一遍没有呢? 在开始之

Android 开发面试 “68” 问

如何才能通过一线互联网公司面试?相信这是很多人的疑惑,希望看完本篇文章能给大家一些启发.下面的截图就是我第一次的面试题记录,当天面试完晚上回到家写下的几个问题.现在从上面的几个问题,发展成了6K star的项目,以下问题是我整理的最新的一线公司面试记录,文章最后有我多年面试的经验分享给大家. 基础问题相关(问题答案在下文): 1.接口的意义-百度2.抽象类的意义-百度3.内部类的作用-乐视4.Java 虚拟机的特性-百度-乐视5.哪些情况下的对象会被垃圾回收机制处理掉-美团-小米6.进程和线程的

[干货]2020将来,最全面试总结——这些大厂Android “108” 问面试题你一定需要

作为一名即将求职的程序员,面对一个可能跟近些年非常不同的 2019 年,你的就业机会和风口会出现在哪里?在这种新环境下,工作应该选择大厂还是小公司?已有几年工作经验的老兵,又应该如何保持和提升自身竞争力,转被动为主动? 就目前大环境来看,跳槽成功的难度比往年高很多.一个明显的感受:今年的面试,无论一面还是二面,都很考验Android程序员的技术功底. 最近搜集了一些基础问题以及阿里.腾讯2019年一些精选的面试题,最后还把把技术点梳理成一份大而全的"Android高级工程师"面试xmi

Bitmap类getPixels()方法中参数stride理解

转载自:http://blog.csdn.net/jie_qing/article/details/7259520 在学习Graphics中遇到位图(Bitmap)中getPixels()方法,对该方法的用法大体理解,但对其中的stride参数却不明白具体的用法以及用意,经过一番折腾后,有些明了,现记述过程如下: 行文有些详细,请赶时间的同学直接跳到红字总结处查看!!  getPixels()方法的用处为获取位图(Bitmap)中的根据方法参数所决定的像素值(颜色值),存入类型为int的pixe

【Android自学日记】关于Bitmap的理解和使用-不完整版

最近的Android自学刚好学习到异步线程的使用,对于开启异步线程加载网络图片中用到的Bitmap有点小蒙逼,这到底是个啥???所以我就自信的打开了百度!!以下就是我学习到的知识! 百度定义: 位图文件(Bitmap),扩展名可以是.bmp或者.dib.位图是Windows标准格式图形文件,它将图像定义为由点(像素)组成,每个点可以由多种色彩表示,包括2.4.8.16.24和32位色彩.例如,一幅1024×768分辨率的32位真彩图片,其所占存储字节数为:1024×768×32/(8*1024)

位图 bitmap 理解

在数据库学习与试用当中会遇到一个概念"位图索引",这是位图在索引检索中的一个应用案例.现在对位图的基本原来进行下学习.原理其实很简单,主要搞清楚一些基本概念. 先说一下基本的概念:bit,byte,word. bit  位 byte  字节 word  字 字长是指字的长度 关系如下: 1字=2字节(1 word = 2 byte) 1字节=8位(1 byte = 8bit) 1 Byte = 8 Bits 1 KB = 1024 Bytes 1 MB = 1024 KB 1 GB =

BitMap位图与海量数据的理解

1. Bit Map算法简介 来自于<编程珠玑>.所谓的Bit-map就是用一个bit位来标记某个元素对应的Value, 而Key即是该元素.由于采用了Bit为单位来存储数据,因此在存储空间方面,可以大大节省. 2. Bit Map的基本思想 我们先来看一个具体的例子,假设我们要对0-7内的5个元素(4,7,2,5,3)排序(这里假设这些元素没有重复).那么我们就可以采用Bit-map的方法来达到排序的目的.要表示8个数,我们就只需要8个Bit(1Bytes),首先我们开辟1Byte的空间,将

(转)根据ImageView的大小来压缩Bitmap,避免OOM

本文转载于:http://www.cnblogs.com/tianzhijiexian/p/4254110.html Bitmap是引起OOM的罪魁祸首之一,当我们从网络上下载图片的时候无法知道网络图片的准确大小,所以为了节约内存,一般会在服务器上缓存一个缩略图,提升下载速度.除此之外,我们还可以在本地显示图片前将图片进行压缩,使其完全符合imageview的大小,这样就不会浪费内存了. 一.思路 思路:计算出要显示bitmap的imageview大小,根据imageview的大小压缩bitma