学习笔记-图片处理技术

            图片处理是APP里面一个重要的环节,内存优化,卡顿现象,图片压缩处理关系到APP的性能和用户体验,这方面的博客文章,网上有很多,这里博主主要把最近的这方面学习心得分享一下;

一,高效加载大图

们可以通过下面的代码看出每个应用程序最高可用内存是多少:

int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);  
先获取图片的宽高大小,与自己期望的大小比对,进行操作

    public static Bitmap decodeSampledBitmapFromResource(Resources res, int resId,  
            int reqWidth, int reqHeight) {  
        // 第一次解析将inJustDecodeBounds设置为true,来获取图片大小  
        final BitmapFactory.Options options = new BitmapFactory.Options();  
        options.inJustDecodeBounds = true;  
        BitmapFactory.decodeResource(res, resId, options);  
        // 调用上面定义的方法计算inSampleSize值  
        options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);  
        // 使用获取到的inSampleSize值再次解析图片  
        options.inJustDecodeBounds = false;  
        return BitmapFactory.decodeResource(res, resId, options);  
    }  

计算图片的 inSampleSize

    public static int calculateInSampleSize(BitmapFactory.Options options,  
            int reqWidth, int reqHeight) {  
        // 源图片的高度和宽度  
        final int height = options.outHeight;  
        final int width = options.outWidth;  
        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;  
    }  
最好,就可以用imagivew.setbitmapResouce();来设置处理后的图片;

二,大量图片加载及图片的缓存处理技术

        内存缓存技术对那些大量占用应用程序宝贵内存的图片提供了快速访问的方法。其中最核心的类是LruCache (此类在android-support-v4的包中提供) 。这个类非常适合用来缓存图片,它的主要算法原理是把最近使用的对象用强引用存储在 LinkedHashMap 中,并且把最近最少使用的对象在缓存值达到预设定值之前从内存中移除。在过去,我们经常会使用一种非常流行的内存缓存技术的实现,即软引用或弱引用 (SoftReference or WeakReference)。但是现在已经不再推荐使用这种方式了,因为从 Android 2.3 (API Level 9)开始,垃圾回收器会更倾向于回收持有软引用或弱引用的对象,这让软引用和弱引用变得不再可靠。另外,Android 3.0 (API Level 11)中,图片的数据会存储在本地的内存当中,因而无法用一种可预见的方式将其释放,这就有潜在的风险造成应用程序的内存溢出并崩溃。

代码如下:

    private LruCache mMemoryCache;  
      
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        // 获取到可用内存的最大值,使用内存超出这个值会引起OutOfMemory异常。  
        // LruCache通过构造函数传入缓存值,以KB为单位。  
        int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);  
        // 使用最大可用内存值的1/8作为缓存的大小。  
        int cacheSize = maxMemory / 8;  
        mMemoryCache = new LruCache(cacheSize) {  
            @Override  
            protected int sizeOf(String key, Bitmap bitmap) {  
                // 重写此方法来衡量每张图片的大小,默认返回图片数量。  
                return bitmap.getByteCount() / 1024;  
            }  
        };  
    }  
      
    public void addBitmapToMemoryCache(String key, Bitmap bitmap) {  
        if (getBitmapFromMemCache(key) == null) {  
            mMemoryCache.put(key, bitmap);  
        }  
    }  
      
    public Bitmap getBitmapFromMemCache(String key) {  
        return mMemoryCache.get(key);  
    }  
    public void loadBitmap(int resId, ImageView imageView) {  
        final String imageKey = String.valueOf(resId);  
        final Bitmap bitmap = getBitmapFromMemCache(imageKey);  
        if (bitmap != null) {  
            imageView.setImageBitmap(bitmap);  
        } else {  
            imageView.setImageResource(R.drawable.image_placeholder);  
            BitmapWorkerTask task = new BitmapWorkerTask(imageView);  
            task.execute(resId);  
        }  
    }  

BitmapWorkerTask 还要把新加载的图片的键值对放到缓存中。

    class BitmapWorkerTask extends AsyncTask {  
        // 在后台加载图片。  
        @Override  
        protected Bitmap doInBackground(Integer... params) {  
            final Bitmap bitmap = decodeSampledBitmapFromResource(  
                    getResources(), params[0], 100, 100);  
            addBitmapToMemoryCache(String.valueOf(params[0]), bitmap);  
            return bitmap;  
        }  
    }  

三,图片压缩的两个库

luban压缩

Luban,也称鲁班。该库作者一针见血的提出当前图片压缩处理的一些问题:单纯对图片进行裁切,压缩已经有很多文章介绍。但是裁切成多少,压缩成多少却很难控制好,裁切过头图片太小,质量压缩过头则显示效果太差。所以,他通过微信朋友圈发送近100张不同分辨率图片,对比原图与微信压缩后的图片逆向推算出来的压缩算法,具体的算法实现在项目中有详细说明介绍。使用上,支持普通调用方式外,也支持RxJava!

用法如下:

学习笔记-图片处理技术_第1张图片

结合rxjava用法:

学习笔记-图片处理技术_第2张图片

compressor压缩

API调用上和Luban一样,支持普通方式也支持RxJava。也可以自定义压缩效果;

用法如下:

学习笔记-图片处理技术_第3张图片

好了,本文里面的文本代码和图片代码都是直接copy的原博主的,链接如下:

参考资料:

Android高效加载大图、多图解决方案,有效避免程序OOM


你可能感兴趣的:(Android)