private
LruCache
> mMemoryCache;
@Override
protected
void
onCreate(Bundle savedInstanceState) {
// 获取到可用内存的最大值,使用内存超出这个值会引起OutOfMemory异常。
// LruCache通过构造函数传入缓存值,以KB为单位。
int
maxMemory = (
int
) (Runtime.getRuntime().maxMemory() /
1024
);
// 使用最大可用内存值的1/8作为缓存的大小。
int
cacheSize = maxMemory /
8
;
mMemoryCache =
new
LruCache
""
>(cacheSize) {
@Override
protected
int
sizeOf(String key, Bitmap bitmap) {
// 重写此方法来衡量每张图片的大小,默认返回图片数量。
return
bitmap.getByteCount() /
1024
;
}
};
}
public
void
addBitmapToMemoryCache(String key, Bitmap bitmap) {
if
(getBitmapFromMemCache(key) ==
null
) {
mMemoryCache.put(key, bitmap);
}
}
public
Bitmap getBitmapFromMemCache(String key) {
return
mMemoryCache.get(key);
}
}
XML布局中加载的图片是不用GC的,
他们是和View/Activity 绑定在一起,同生同死。
UI上加载的可以使用SoftReference让虚拟机进行快速回收。
如果迫切需要手动回收,严格控制内存开销,也许就该针对场景写Cache的管理了。
对于一般的场景,使用栈的结构就足够了,对于期望高效流畅又有着复杂item的ListView的话
可能需要预加载和手动回收。
--------------------------------------------------------------------------------------------------------
1.对图片进行预处理
主要是根据实际大小对对质量进行压缩
2.参考下android developer中的demo,里面有两点值得借鉴:一个是内存缓存,一个是disk缓存。可以很好的帮助你处理oom.
楼上所说的是LruCache,你好好研究下这个官方DEMO,研究明白了,你以后所有的项目都可以使用这个DEMO中的方式,绝对不会出现OOM。另外,在Gallery3D的源代码中,好像有另外一种cache方式。
--------------------------------------------------------------------------------------------------------
https://github.com/dodola/android_waterfall/tree/master/src/net 可以加载上万张图片的瀑布流
ImageView加载图片时,有时会出现OOM
imageView.setImageResource(imageId);
解决方法
/**
* 以最省内存的方式读取本地资源的图片
*
* @param context
* @param resId
* @return
*/
public static Bitmap readBitMap(Context context, int resId) {
BitmapFactory.Options opt = new BitmapFactory.Options();
opt.inPreferredConfig = Bitmap.Config.RGB_565;
opt.inPurgeable = true;
opt.inInputShareable = true;
// 获取资源图片
InputStream is = context.getResources().openRawResource(resId);
return BitmapFactory.decodeStream(is, null, opt);
}
Bitmap bitmap=readBitMap(LoginActivity.this,imageId);
imageView.setImageBitmap(bitmap);
那是为什么,会导致oom呢:
原来当使用像 imageView.setBackgroundResource,imageView.setImageResource, 或者 BitmapFactory.decodeResource 这样的方法来设置一张大图片的时候,这些函数在完成decode后,最终都是通过java层的createBitmap来完成的,需要消耗更多内存。
因此,改用先通过BitmapFactory.decodeStream方法,创建出一个bitmap,再将其设为ImageView的 source,decodeStream最大的秘密在于其直接调用JNI>>nativeDecodeAsset()来完成decode,无需再使用java层的createBitmap,从而节省了java层的空间。如果在读取时加上图片的Config参数,可以跟有效减少加载的内存,从而跟有效阻止抛out of Memory异常。
另外,需要特别注意:
decodeStream是直接读取图片资料的字节码了, 不会根据机器的各种分辨率来自动适应,使用了decodeStream之后,需要在hdpi和mdpi,ldpi中配置相应的图片资源,否则在不同分辨率机器上都是同样大小(像素点数量),显示出来的大小就不对了。
import java.io.ByteArrayOutputStream; import java.io.InputStream; import java.lang.ref.SoftReference; import java.net.HttpURLConnection; import java.net.URL; import java.net.URLConnection; import java.util.HashMap; import android.content.Context; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.os.Handler; import android.os.Handler.Callback; import android.os.Message; import android.widget.ImageView; /** * * 功能说明:异步加载图片 * * @author Jack.wang * */ public class AsyncImageLoaderCore { public Context context; // 做本地缓存时会用到 public HashMap> imageCache;// 软引用集合 public AsyncImageLoaderCore(Context context) { this.context = context; this.imageCache = new HashMap >(); } public Bitmap loadBitmap(final String imageUrl, final ImageView imageView, final ImageCallback imageCallback) { if (imageCache.containsKey(imageUrl)) { SoftReference softReference = imageCache.get(imageUrl); if (softReference.get() != null) return softReference.get(); } final Handler handler = new Handler(new Callback() { @Override public boolean handleMessage(Message msg) { imageCallback.imageLoaded((Bitmap) msg.obj, imageView, imageUrl); return false; } }); new Thread() { @Override public void run() { Bitmap bitmap = null; try { bitmap = getHttpBitmap(imageUrl); } catch (Exception e) { e.printStackTrace(); return; } if (null != bitmap) { imageCache.put(imageUrl, new SoftReference (bitmap)); handler.sendMessage(handler.obtainMessage(0, bitmap)); } } }.start(); return null; } private final int MAX_PIC_LENGTH = 200000;// 最大字节长度限制[可调,最好不要超过200000] private final int SAMPLE_SIZE = 14;// 裁剪图片比列(1/14)[可调] /** * 获取网络图片 */ private Bitmap getHttpBitmap(String imgUrl) throws Exception { URL htmlUrl = new URL(imgUrl); URLConnection connection = htmlUrl.openConnection(); HttpURLConnection conn = (HttpURLConnection) connection; if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) { InputStream inputStream = conn.getInputStream(); byte[] bytes = changeToBytes(inputStream); if(bytes.length < MAX_PIC_LENGTH) { return BitmapFactory.decodeByteArray(bytes, 0, bytes.length); } else if(bytes.length < MAX_PIC_LENGTH * SAMPLE_SIZE) { BitmapFactory.Options options = new BitmapFactory.Options(); options.inJustDecodeBounds = false; options.inSampleSize = SAMPLE_SIZE; return BitmapFactory.decodeByteArray(bytes, 0, bytes.length, options); } } return null; } /** * 将流转换成字节数组 */ public byte[] changeToBytes(InputStream inputStream) throws Exception { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); byte[] buffer = new byte[1024];// 每次读取的字节长度 int len = 0; while((len = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, len); } inputStream.close(); return outputStream.toByteArray(); } /** * 异步加载资源回调接口 */ public interface ImageCallback { public void imageLoaded(Bitmap bitmap, ImageView imageView, String imageUrl); } }