Android面试系列文章2018之内存管理之Bitmap的加载篇

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/ClAndEllen/article/details/79382123

Android面试系列文章2018之内存管理之Bitmap的加载篇

1.recycle方法

  Bitmap在Android中内存存储位置有两块:

  1.native区(C区):必须调用Bitmap对象的recycle()方法才能对该Bitmap对象C区的内存进行回收。注意的是recycle执行是不可逆的,注意谨慎调用。

  2.Java区(自动回收)。

2.LRU(最近最少使用算法)

  它是怎么实现的?你可以这么回答:它是一个泛型类,它内部是有一个LinkedHashMap集合,内部提供了一个get和put方法来完成缓存的添加和获取操作,当缓存满的时候,你再往里面添加新的缓存对象的时候,它就会调用trimToSize这个方法把旧的并且使用次数少的缓存对象移除掉,然后再添加新的缓存对象。

3.计算inSampleSize

  加载图片时应该加载合适尺寸,分辨率大小等的图片,不可能每个位置都去加载原图,所以我们需要计算出某些显示图片的地方最合适尺寸,分辨率等大小的图片,这需要对inSampleSize进行计算,才能让图片做出合适的调整。当然也为了避免OOM异常。https://www.jianshu.com/p/f15cd2ed6ec0

public static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
    final int width = options.outWidth;
    final int height = options.outHeight;
    int inSampleSize = 1;

    if (height > reqHeight || width > reqWidth) {
        //计算图片高度和我们需要高度的最接近比例值
        final int heightRatio = Math.round((float) height / (float) reqHeight);
        //宽度比例值
        final int widthRatio = Math.round((float) width / (float) reqWidth);
        //取比例值中的较大值作为inSampleSize
        inSampleSize = heightRatio > widthRatio ? heightRatio : widthRatio;
    }

    return inSampleSize;
}

  inSampleSize的默认值和最小值为1(当小于1时,解码器将该值当做1来处理),且在大于1时,该值只能为2的幂(当不为2的幂时,解码器会取与该值最接近的2的幂)。例如,当inSampleSize为2时,一个20001000的图片,将被缩小为1000500,相应地,它的像素数和内存占用都被缩小为了原来的1/4:

4.缩略图

public static Bitmap getThumbnail(Uri uri,int size, Context context) throws Exception {
    InputStream input = context.getContentResolver().openInputStream(uri);

    //配置BitmapFactory.Options,inJustDecodeBounds设为true,以获取图片的宽高
    BitmapFactory.Options onlyBoundsOptions = new BitmapFactory.Options();
    onlyBoundsOptions.inJustDecodeBounds = true;
    onlyBoundsOptions.inDither=true;//optional
    onlyBoundsOptions.inPreferredConfig=Bitmap.Config.ARGB_8888;//optional

    //计算inSampleSize缩放比例
    BitmapFactory.decodeStream(input, null, onlyBoundsOptions);
    input.close();
    if ((onlyBoundsOptions.outWidth == -1) || (onlyBoundsOptions.outHeight == -1))
        return null;
    int originalSize = (onlyBoundsOptions.outHeight > onlyBoundsOptions.outWidth) ? onlyBoundsOptions.outHeight : onlyBoundsOptions.outWidth;
    double ratio = (originalSize > size) ? (originalSize / size) : 1.0;
    //获取到缩放比例后,再次设置BitmapFactory.Options,获取图片缩略图
    BitmapFactory.Options bitmapOptions = new BitmapFactory.Options();
    bitmapOptions.inSampleSize = getPowerOfTwoForSampleRatio(ratio);
    bitmapOptions.inDither=true;//optional
    bitmapOptions.inPreferredConfig=Bitmap.Config.ARGB_8888;//optional
    input = context.getContentResolver().openInputStream(uri);
    Bitmap bitmap = BitmapFactory.decodeStream(input, null, bitmapOptions);
    input.close();
    return bitmap;
}

/**
 * 将double的比例采用近似值的方式转为int
 * @param ratio
 * @return
 */
private static int getPowerOfTwoForSampleRatio(double ratio){
    int k = Integer.highestOneBit((int)Math.floor(ratio));
    if(k==0) return 1;
    else return k;
}

总体思想是通过设置BitmapFactory.Options.inJustDecodeBounds设为true,先获取到图片的宽高而并不会生产Bitmap;再通过所需图片的最长边size来获取缩放比例inSampleSize的值;
然后获所需尺寸的图片。

https://www.jianshu.com/p/d30c5e7d266d

5.三级缓存

a.网路
b.内存
c.本地

  总体思想就是为用户节约流量,当你在加载一张图片时,首先先判断本地是否已经缓存了该图片,如果没有,那么就通过网络进行加载,从网络加载的图片首先会存在与内存当中,为了节约用户的流量,可以将这张图片保存至本地,当用户退出程序或者某个操作导致这张图片被回收了,当用户某个操作又再试图加载这张图片的时候,此时由于本地已经缓存下来了,所以直接从本地把图片加载到内存当中并显示给用户即可。具体如何实现请看以下链接:

http://blog.csdn.net/u012325403/article/details/50388889

没有更多推荐了,返回首页