导读
本篇承接 内存泄漏与内存溢出总结
图片处理(防止内存溢出)
三要素(缩放比例、解码格式、局部加载)
配合软引用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();
}
}
总结:
- 如果觉得文章对您有用,点击一个关注憋