一直以来加载图片oom都是android开发常见问题,很多加载图片也使用了类似imageloader这样的开源来做,但是如果没有合理使用照样会出oom情况。
那么一般在listview使用时候在下拉时候加载大量图片。
那么怎么才是合理使用?
应该要使用listview的回收原理来用是最合适的。
在下拉停止时候加载图片,不要使用多余图片加载,再配合缓存使用。
这里写一个适配器可以配合listview、gridview等来使用通用适配器。
代码:
public class NoOOMAdapter<T> extends BaseAdapter implements OnScrollListener {
List<T> listinfo = new ArrayList<T>();
List<Map<String, String>> listimg = new ArrayList<Map<String, String>>();
Set<LoadTask> loadTasks = new HashSet<LoadTask>();
ListView listView;
Context context;
int R_layout_id;
LruCache<String, Bitmap> mCache;
int firstVisible;
int visibleNums;
boolean isLoaded = true;
LayoutInflater layoutInflater;
public NoOOMAdapter(List<T> listinfo, List<Map<String, String>> arr,
ListView listView, Context context, int r_layout_id) {
super();
this.listimg = arr;
this.listinfo = listinfo;
this.listView = listView;
this.context = context;
this.R_layout_id = r_layout_id;
this.layoutInflater = LayoutInflater.from(context);
// 初始化缓存函数
int maxM = (int) Runtime.getRuntime().maxMemory();
int cSize = maxM / 8;
mCache = new LruCache<String, Bitmap>(cSize) {
@Override
protected int sizeOf(String key, Bitmap value) {
// 获取全部字节数
return value.getByteCount();
}
};
// 绑定滑动监听
listView.setOnScrollListener(this);
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return listinfo.size();
}
@Override
public T getItem(int arg0) {
// TODO Auto-generated method stub
return (T)listinfo.get(arg0);
}
@Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return arg0;
}
@Override
public View getView(int arg0, View arg1, ViewGroup arg2) {
// TODO Auto-generated method stub
ViewHolder viewHolder=new ViewHolder(context, arg2, R_layout_id, arg0);
InitView(viewHolder, arg0);
return viewHolder.getConvertView();
}
public void InitView(ViewHolder viewHolder,int pos){
// 处理数据绑定逻辑
}
//获取数据集合
public List<T> getListInfo() {
return listinfo;
}
//获取图片集合
public List<Map<String, String>> getImgList(){
return listimg;
}
@Override
public void onScroll(AbsListView arg0, int arg1, int arg2, int arg3) {
// TODO Auto-generated method stub
firstVisible = arg1;
visibleNums = arg2;
if (isLoaded && visibleNums > 0) {
// 执行下载
isLoaded = false;
DownLoadAllTask(firstVisible, visibleNums);
}
}
@Override
public void onScrollStateChanged(AbsListView arg0, int arg1) {
// TODO Auto-generated method stub
if (arg1 == SCROLL_STATE_IDLE) {// 停止滑动
DownLoadAllTask(firstVisible, visibleNums);
} else {
cancelAllTasks();
}
}
// 清空缓存
public void cancelAllTasks() {
if (loadTasks != null) {
for (LoadTask task : loadTasks) {
task.cancel(false);// 取消下载任务
}
}
}
// 下载任务 有序加载
class LoadTask extends AsyncTask<String, Void, Bitmap> {
String imgurlString;// 图片地址
int pos;//位置
public LoadTask(int pos) {
super();
this.pos = pos;
}
@Override
protected Bitmap doInBackground(String... arg0) {
// TODO Auto-generated method stub
imgurlString = arg0[0];
Bitmap bitmap = downloadBitmap(imgurlString);
if (bitmap != null) {
// 下载完毕添加到缓存中
addBitmapToMemoryCache(imgurlString, bitmap);
}
return bitmap;
}
@Override
protected void onPostExecute(Bitmap result) {
// TODO Auto-generated method stub
super.onPostExecute(result);
ImageView imageView = (ImageView) listView
.findViewWithTag(imgurlString+"_"+pos);
if (imageView != null && result != null) {
imageView.setImageBitmap(result);
}
// 消灭自身任务
loadTasks.remove(this);
}
// 图片下载
Bitmap downloadBitmap(String imageUrl) {
Bitmap bitmap = null;
HttpURLConnection con = null;
try {
URL url = new URL(imageUrl);
con = (HttpURLConnection) url.openConnection();
con.setConnectTimeout(5 * 1000);
con.setReadTimeout(10 * 1000);
con.setDoInput(true);
con.setDoOutput(true);
bitmap = BitmapFactory.decodeStream(con.getInputStream());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (con != null) {
con.disconnect();
}
}
return bitmap;
}
}
static public class ViewHolder {
private final SparseArray<View> mViews;
private View mConvertView;
private ViewHolder(Context context, ViewGroup parent, int layoutId,
int position) {
this.mViews = new SparseArray<View>();
mConvertView = LayoutInflater.from(context).inflate(layoutId,
parent, false);
// setTag
mConvertView.setTag(this);
}
public static ViewHolder get(Context context, View convertView,
ViewGroup parent, int layoutId, int position) {
if (convertView == null) {
return new ViewHolder(context, parent, layoutId, position);
}
return (ViewHolder) convertView.getTag();
}
/**
* 通过控件的Id获取对于的控件,如果没有则加入views
*
* @param viewId
* @return
*/
@SuppressWarnings("unchecked")
public <T extends View> T getView(int viewId) {
View view = mViews.get(viewId);
if (view == null) {
view = mConvertView.findViewById(viewId);
mViews.put(viewId, view);
}
return (T) view;
}
public View getConvertView() {
return mConvertView;
}
}
// 添加缓存中
public void addBitmapToMemoryCache(String key, Bitmap bitmap) {
if (getBitmapFromMemoryCache(key) == null) {
mCache.put(key, bitmap);
}
}
// 获取缓存
public Bitmap getBitmapFromMemoryCache(String key) {
return mCache.get(key);
}
// 开始任务
void DownLoadAllTask(int firstV, int visibleN) {
try {
for (int i = firstV; i < (firstV + visibleN); i++) {
if (i<listimg.size()) {
Map<String, String> imgItem = listimg.get(i);
// 迭代器
Set<String> mKeys = imgItem.keySet();
for (String string : mKeys) {
String imgurlString = imgItem.get(string);
Bitmap bitmap = getBitmapFromMemoryCache(imgurlString);
if (bitmap == null) {
LoadTask loadTask = new LoadTask(i);
loadTask.execute(imgurlString);
loadTasks.add(loadTask);
} else {
// 直接填充
ImageView imageView = (ImageView) listView
.findViewWithTag(imgurlString);
if (imageView != null && bitmap != null) {
imageView.setImageBitmap(bitmap);
}
}
}
}
}
} catch (Exception e) {
// TODO: handle exception
e.printStackTrace();
}
}
// 设置图片
protected void setImageView(String imageUrl, ImageView imageView, int imgId, int pos) {
imageView.setImageResource(imgId);
imageView.setTag(imageUrl+"_"+pos);
Bitmap bitmap = getBitmapFromMemoryCache(imageUrl);
if (bitmap != null) {
imageView.setImageBitmap(bitmap);
} else {
imageView.setImageResource(imgId);// 如果没有内容为空图片
}
}
// 工具函数 图片尺寸压缩函数
public static int calculateInSampleSize(BitmapFactory.Options options,
int reqWidth) {
// 源图片的宽度
final int width = options.outWidth;
int inSampleSize = 1;
if (width > reqWidth) {
// 计算出实际宽度和目标宽度的比率
final int widthRatio = Math.round((float) width / (float) reqWidth);
inSampleSize = widthRatio;
}
return inSampleSize;
}
// 压缩图片质量
public static Bitmap decodeSampledBitmapFromResource(String pathName,
int reqWidth) {
// 第一次解析将inJustDecodeBounds设置为true,来获取图片大小
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(pathName, options);
// 调用上面定义的方法计算inSampleSize值
options.inSampleSize = calculateInSampleSize(options, reqWidth);
// 使用获取到的inSampleSize值再次解析图片
options.inJustDecodeBounds = false;
return BitmapFactory.decodeFile(pathName, options);
}
}
有待完善