大家好,这是我的第一篇CSDN博客,以后有时间会给大家不断写关于Android技术的博客,希望大家喜欢。
加载图片时发生oom想必是每一位Android工程师都会遇到的并且很头疼的问题,那么今天我就来和大家聊聊如何高效加载本地图片并且怎么保证不出现oom。
实现界面如图:
首先介绍几个知识点:
1.LruCache :LruCache 通过key--value 键值对的形式存储数据,通过指定一个最大值来限制其内容的数量(LruCache<key,value>(int maxSize)),每当一个value值被访问时移动到队列的头部,当LruCache中的value值达到上限时,再加入一个新的value,队尾的value将会被回收。LruCache核心原理是如果一个value长时间没有被使用那么这个value以后被使用的几率就会变小,即可以回收该value。
2.ExecutorService:线程池,同时有指定数量的线程在执行。
3.Semaphore:信号量机制,它负责协调各个线程, 以保证它们能够正确、合理的使用公共资源。在该项目中主要是保证在线程池中有正在执行的任务+准备执行的任务之和是一定的值。
4.异步加载图片以及图片的裁剪和旋转。
5.listview的优化。
好,下面咱们来看一下重要代码实现:
1.初始化LruCache:
//得到当前应用<span style="color:#0820;">最大可用内存</span>
int maxMemory = (int) Runtime.getRuntime().maxMemory();
//<font color="#0820">取其<font color="#0820">1/8作为<font color="#0820"><font color="#0820"><font color="#0820"><font color="#0820"><font color="#0820"><font color="#0820"><font color="#0820"><font color="#0820"><font color="#0820"><font color="#0820"><font color="#0820"><font color="#0820"><font color="#0820"><font color="#0820"><font color="#0820"><font color="#0820"><font color="#0820"><font color="#0820"><font color="#0820"><font color="#0820"><font color="#0820"><font color="#0820"><font color="#0820"><font color="#0820"><font color="#0820"><font color="#0820"><font color="#0820"><font color="#0820"><font color="#0820"><span style="color:#0820;"><span style="color:#0820;"><span style="color:#0820;">LruCache</span></span></span></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font></font>的最大值</font></font>
int cacheMemory = maxMemory / 8;
mLruCache = new LruCache<String, Bitmap>(cacheMemory) {
@Override
protected int sizeOf(String key, Bitmap value) {
//<span style="color:#0820;">当前bitmap<span style="color:#0820;">纵横字节乘积即是该对象<span style="color:#0820;">所占的内存空间</span></span></span>
return value.getRowBytes() * value.getHeight();
}
};
2.加载bitmap:
//通过控件的长度获取bitmap缩放比例
prviate ImageSize getImageViewSize(ImageView imageView) {
ImageSize imageSize = new ImageSize();
LayoutParams mParams = imageView.getLayoutParams();
int width = imageView.getWidth();
if (width <= 0) {
width = mParams.width;
}
if (width <= 0) {
width = getImageViewFieldValue(imageView, "mMaxWidth");
}
if (width <= 0) {
width = imageView.getContext().getResources().getDisplayMetrics().widthPixels;
}
int height = imageView.getHeight();
if (height <= 0) {
height = mParams.height;
}
if (height <= 0) {
height = getImageViewFieldValue(imageView, "mMaxHeight");
}
if (height <= 0) {
height = imageView.getContext().getResources().getDisplayMetrics().heightPixels;
}
imageSize.width = width;
imageSize.height = height;
return imageSize;
}
/**
* 根据图盘需要显示的宽和高对图片进行压缩
*/
protected Bitmap decodeSampledBitmap(String path, int width, int height, int flag) {
// 获取图片的宽和高,不把图片加载到内存中
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(path, options);
if (flag == 1) {
options.inSampleSize = 1;
} else {
options.inSampleSize = caculateInSampleSize(options, width, height);
}
// 使用insampleSize再次解析图片
options.inJustDecodeBounds = false;
Bitmap bitmap = BitmapFactory.decodeFile(path, options);
int angle = readPictureDegree(path);
return rotaingImageView(angle, bitmap);
}
3.获取图片角度及其旋转图片:
/** 得到图片旋转角度 */
private int readPictureDegree(String path) {
int degree = 0;
try {
ExifInterface exifInterface = new ExifInterface(path);
int orientation = exifInterface.getAttributeInt(ExifInterface.TAG_ORIENTATION, ExifInterface.ORIENTATION_NORMAL);
switch (orientation) {
case ExifInterface.ORIENTATION_ROTATE_90:
degree = 90;
break;
case ExifInterface.ORIENTATION_ROTATE_180:
degree = 180;
break;
case ExifInterface.ORIENTATION_ROTATE_270:
degree = 270;
break;
}
} catch (IOException e) {
e.printStackTrace();
}
return degree;
}
/** 旋转图片 */
private Bitmap rotaingImageView(int angle, Bitmap bitmap) {
// 旋转图片 动作
Matrix matrix = new Matrix();
matrix.postRotate(angle);
// 创建新的图片
Bitmap resizedBitmap = null;
try {
resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, false);
} catch (Exception e) {
// TODO: handle exception
}
bitmap = null;
return resizedBitmap;
}
4.优化listview:
重写OnScrollListener,在listview滚动时不加载图片,当其停止时加载可见项图片。
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
currentScrollState = scrollState;
if (currentScrollState == SCROLL_STATE_IDLE) {
int visible = currentFirstVisibleItem;
while (visible <= currentLastVisibleItem) {
if (invisibleItem.contains(visible)) {
if (null != mLisener)
mLisener.loadItem(visible, visible - currentFirstVisibleItem);
}
visible++;
}
resetData();
}
if (null != mLisener) {
mLisener.onScrollStateChanged(view, scrollState);
}
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (currentScrollState == SCROLL_STATE_FLING) {
Speed isHigh = isHighSpeed(firstVisibleItem);
if (isHigh == Speed.HIGHSPEED) {
isCanLoadData = false;
} else if (isHigh == Speed.LOWSPEED) {
isCanLoadData = true;
}
}
currentFirstVisibleItem = firstVisibleItem;
currentLastVisibleItem = firstVisibleItem + visibleItemCount - 1;
if (null != mLisener) {
mLisener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount);
}
}
好的,今天就介绍到这里,项目地址下载地址: 源码下载地址
望各位同行加入 Android高级开发交流群 群号: 474440973 以便深入探讨