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

来源:互联网 发布:汉密尔顿 知乎 喜剧 编辑:程序博客网 时间:2024/05/21 06:40

导读

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

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

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

配合软引用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();    }}

总结:

  • 如果觉得文章对您有用,点击一个关注憋
0 0
原创粉丝点击