图片处理(防止内存溢出)

导读

本篇承接 内存泄漏与内存溢出总结

图片处理(防止内存溢出)

三要素(缩放比例、解码格式、局部加载)

配合软引用BitmapCache类,或Lru算法 BitmapLruCache 优化效果更好

除此以外,还可以使用第三方图片压缩工具
TinyPNG

package zs.xmx.todo;
/*
 * @创建者     默小铭
 * @博客       http://blog.csdn.net/u012792686
 * @创建时间   2017/4/7
 * @本类描述      图片处理(防止内存溢出)
 * @内容说明 
 *            三要素:
 *            缩放比例、解码格式、局部加载
 *            配合软引用BitmapCache类,或Lru算法 BitmapLruCache 优化效果更好
 * @补充内容
 * //todo 这里总结归类到BitmapUtils
 */

public class BitmapHandleDemo extends Activity {
    private ImageView mImageView;
    private Bitmap mBitmap = null;
    private File   mFile   = null;
    private int SCREEN_WIDTH, SCREEN_HEIGHT;
    private int shiftpx = 0; //偏移量
    private Button mBtn_choosepic;
    private Button mBtn_change_option;
    private Button mBtn_change_rgb;
    private Button mBtn_partload;
    private Button mBtn_offset;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bitmap_handle);
        initView();
        initEvent();

    }

    private void initEvent() {
        DisplayMetrics dm = new DisplayMetrics();
        dm = getApplicationContext().getResources().getDisplayMetrics();
        //这里其实要转dp
        SCREEN_WIDTH = dm.widthPixels;
        SCREEN_HEIGHT = dm.heightPixels;
    }

    private void initView() {
        mImageView = (ImageView) findViewById(iv);
        mBtn_choosepic = (Button) findViewById(R.id.choosepic);
        mBtn_change_option = (Button) findViewById(R.id.change_option);
        mBtn_change_rgb = (Button) findViewById(R.id.change_rgb);
        mBtn_partload = (Button) findViewById(partload);
        mBtn_offset = (Button) findViewById(R.id.offset);
    }

    /**
     * URI方式打开相册获取图片
     */
    private void getPic() {
        Intent intent = new Intent(Intent.ACTION_PICK, null);
        intent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
        startActivityForResult(intent, 1);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {

        try {
            String path = getRealPathFromURL(data.getData());
            mFile = new File(path);
            if (mFile == null)
                return;
            if (mFile.length() == 0) {
                mFile.delete();
                return;
            }
            Log.i("xmx", "file:" + mFile.getName() + ",原图大小length:" + mFile.length());
            FileInputStream fis = new FileInputStream(mFile);
            mBitmap = BitmapFactory.decodeStream(fis);
            Log.i("xmx", "bitmap,Bitmap解析图片后大小length:" + mBitmap.getByteCount());
            mImageView.setImageBitmap(mBitmap);
        } catch (Exception e) {
            e.printStackTrace();
            Log.i("xmx", "bitmap,load error:" + e.getMessage());
        }
    }

    /**
     * 根据URI获得File文件路径
     *
     * @param contentUri
     * @return
     */
    private String getRealPathFromURL(Uri contentUri) {
        String res = null;
        String[] proj = {MediaStore.Images.Media.DATA};
        Cursor cursor = getApplicationContext().getContentResolver().query(contentUri, proj, null, null, null);
        if (cursor.moveToFirst()) {
            int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
            res = cursor.getString(column_index);
        }
        cursor.close();
        return res;
    }

    /**
     * 点击原图按钮
     *
     * @param view
     */
    public void choosepic(View view) {
        getPic();
    }

    /**
     * 点击缩放比例按钮
     *
     * @param view
     */
    public void change_option(View view) {
        if (mFile == null) {
            return;
        }
        try {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true; //只获取边界不加载
            BitmapFactory.decodeStream(new FileInputStream(mFile), null, options);
            int width_tmp = options.outWidth, height_tmp = options.outHeight;
            int scale = 2;
            while (true) {
                if (width_tmp / scale < SCREEN_WIDTH)
                    break;
                scale += 2;
            }
            scale /= 2;
            BitmapFactory.Options options2 = new BitmapFactory.Options();
            options2.inSampleSize = scale; //上述操作得到抽样比之后,在赋给inSampleSize
            Log.i("xmx", "bitmap,缩放比例scale:" + scale);
            FileInputStream fis = new FileInputStream(mFile);
            mBitmap = BitmapFactory.decodeStream(fis, null, options2);
            Log.i("xmx", "scale-bitmap,缩放比例后的图片大小legth:" + mBitmap.getByteCount());
            mImageView.setImageBitmap(mBitmap);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 点击更改解码格式按钮
     *
     * @param view
     */
    public void change_rgb(View view) {
        if (mFile == null) {
            return;
        }
        try {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inPreferredConfig = Bitmap.Config.RGB_565;
            FileInputStream fis = new FileInputStream(mFile);
            mBitmap = BitmapFactory.decodeStream(fis, null, options);
            Log.i("xmx", "RGB_565-bitmap,更换解码格式后的图片大小legth:" + mBitmap.getByteCount());
            mImageView.setImageBitmap(mBitmap);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 点击局部加载按钮
     *
     * @param view
     */
    public void partload(View view) {
        partload_offset();
    }

    private void partload_offset() {
        if (mFile == null) {
            return;
        }
        try {
            FileInputStream fis = new FileInputStream(mFile);
            //获取图片的宽高
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true; //只获取边界不加载
            BitmapFactory.decodeStream(new FileInputStream(mFile), null, options);
            int width = options.outWidth, height = options.outHeight;

            //设置显示图片的中心区域
            BitmapRegionDecoder bitmapRegionDecoder = BitmapRegionDecoder.newInstance(fis, false);//部分图片解析API
            BitmapFactory.Options options2 = new BitmapFactory.Options();
            mBitmap = bitmapRegionDecoder.decodeRegion(new Rect(width / 2 - SCREEN_WIDTH / 2 + shiftpx, height / 2 - SCREEN_HEIGHT / 2,
                    width / 2 + SCREEN_WIDTH / 2 + shiftpx, height / 2 + SCREEN_HEIGHT / 2), options2);
            mImageView.setImageBitmap(mBitmap);
            Log.i("xmx", "PartLoad-bitmap,局部加载图片的大小legth:" + mBitmap.getByteCount());
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public void offset(View view) {
        shiftpx += 10;
        partload_offset();
    }


}

BitmapCache 软应用管理多张图片


package zs.xmx.todo;
/*
 * @创建者     默小铭
 * @博客       http://blog.csdn.net/u012792686
 * @创建时间   2017/4/8
 * @本类描述      软引用方式管理多张图片
 * @内容说明   //TODO 归类到BitmapUtils
 * @补充内容
 *
 * ---------------------------------     
 * @更新时间   
 * @新增内容   
 *
 */

import android.graphics.Bitmap;
import android.os.Build;
import android.util.ArrayMap;

import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;

public class BitmapCache {
    static private BitmapCache cache;

    private ArrayMap<String, MySoftRef> hashRefs;
    //垃圾引用的队列(所引用的对象已经被回收,则将该引用存入队列)
    private ReferenceQueue<Bitmap>      mBitmapReferenceQueue;

    /**
     * 继承SoftReference,是的每一个实例都具有可识别的标识
     */
    private class MySoftRef extends SoftReference<Bitmap> {
        private String _key = "";

        public MySoftRef(Bitmap referent, ReferenceQueue<Bitmap> q, String key) {
            super(referent, q);
            _key = key;
        }
    }

    private BitmapCache() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            hashRefs = new ArrayMap<String, MySoftRef>();
        }
        mBitmapReferenceQueue = new ReferenceQueue<Bitmap>();
    }

    public static BitmapCache getInstance() {
        if (cache == null) {
            cache = new BitmapCache();
        }
        return cache;
    }

    /**
     * 以软引用的方式对一个Bitmap对象的实例进行引用并保存该引用
     */
    public void addCacheBitmap(Bitmap bmp, String key) {
        cleanCache();//清除垃圾引用
        MySoftRef ref = new MySoftRef(bmp, mBitmapReferenceQueue, key);
        hashRefs.put(key, ref);
    }

    /**
     * 依据所指定的drawable下的图片资源ID号,
     * (可以按需求从网络或本地获取),
     * 重新获取相应Bitmap对象的实例
     */
    //public Bitmap getBitmap(int resId, Context context)
    public Bitmap getBitmap(int resId) {
        Bitmap bmp = null;
        //缓存中是否有该Bitmap实例的引用,如果用,从软引用中取
        try {
            if (hashRefs.containsKey(resId)) {
                MySoftRef ref = (MySoftRef) hashRefs.get(resId);
                bmp = (Bitmap) ref.get();
            }
            return bmp;
        } catch (NullPointerException e) {
            return null;
        }
    }

    private void cleanCache() {
        MySoftRef ref = null;
        while ((ref = (MySoftRef) mBitmapReferenceQueue.poll()) != null) {
            hashRefs.remove(ref._key);
        }
    }

    /**
     * 清除Cache内的全部内容
     */
    public void clearCach() {
        cleanCache();
        hashRefs.clear();
        System.gc();
        System.runFinalization();
    }
}

BitmapLruCache Lru算法管理多张图片


package zs.xmx.todo;
/*
 * @创建者     默小铭
 * @博客       http://blog.csdn.net/u012792686
 * @创建时间   2017/4/8
 * @本类描述      Lru算法管理多张图片
 * @内容说明   //TODO 归类到BitmapUtils
 * @补充内容
 *
 * ---------------------------------     
 * @更新时间   
 * @新增内容   
 *
 */

import android.graphics.Bitmap;
import android.util.Log;

import java.util.Collections;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.Map;

public class BitmapLruCache {
    private static final String              TAG   = "xmx";
    //容量8bit,填充比0.75,true表示使用LRU算法
    //LinkedHashMap线程不安全,因此要在外部加个同步
    private              Map<String, Bitmap> cache = Collections.synchronizedMap(
            new LinkedHashMap<String, Bitmap>(8, 0.75f, true));
    private              long                size  = 0; //存 当前内存大小
    private              long                limit = 1000000; //限制最后内存 bytes

    public BitmapLruCache() {
        //使用App允许的 25% 可用内存大小
        setLimit(Runtime.getRuntime().maxMemory() / 4);
    }

    private void setLimit(long new_limit) {
        limit = new_limit;
        Log.i(TAG, "MemoryCache will use up to" + limit / 1024. / 1024. + "MB");
    }

    /**
     * 获取图片
     */
    public Bitmap get(String id) {
        try {
            if (!cache.containsKey(id))
                return null;
            return cache.get(id);
        } catch (NullPointerException e) {
            return null;
        }
    }

    public void put(String id, Bitmap bitmap) {
        try {
            if (cache.containsKey(id))
                size -= getSizeInBytes(cache.get(id));//- 就是将原来的图片删掉
            cache.put(id, bitmap);
            size += getSizeInBytes(bitmap);//+ 将新的图片输入
            checkSize();
        } catch (Throwable th) {
            th.printStackTrace();
        }
    }

    private long getSizeInBytes(Bitmap bitmap) {
        if (bitmap == null)
            return 0;
        //行子节*高度(低版本)
        //高版本 bitmap.getByteCount();
        return bitmap.getRowBytes() * bitmap.getHeight();
    }

    /**
     * 拿到使用最少的图片对象,然后remove掉
     */
    private void checkSize() {
        Log.i(TAG, "Cache size=" + size + "length=" + cache.size());
        if (size > limit) {
            Iterator<Map.Entry<String, Bitmap>> iterator = cache.entrySet().iterator();
            while (iterator.hasNext()) {
                Map.Entry<String, Bitmap> entry = iterator.next();
                size -= getSizeInBytes(entry.getValue());
                iterator.remove();
                if (size <= limit)
                    break;
            }
            Log.i(TAG, "Clean size,New size" + cache.size());
        }
    }

    public void clear() {
        cache.clear();

    }

}

总结:

  • 如果觉得文章对您有用,点击一个关注憋
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值