int width = metric.widthPixels; // 屏幕寬度(像素)
int height = metric.heightPixels; // 屏幕高度(像素)
float density = metric.density; // 屏幕密度(0.75 / 1.0 / 1.5)
int densityDpi = metric.densityDpi; // 屏幕密度DPI(120 / 160 / 240)
int screenHeight =display.getHeight(); // 屏幕高(像素,如:800p)
dm = new DisplayMetrics();
screenWidth = (int)(dm.widthPixels * density + 0.5f); // 屏幕寬(px,如:480px)
screenHeight = (int)(dm.heightPixels * density + 0.5f); // 屏幕高(px,如:800px)
int imageWidth = options.outWidth;
final BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(path, options);
// 設置 縮放比例inSampleSize值到options內
options.inSampleSize = calculateInSampleSize(options, reqWidth, reqHeight);
// 取消預加載
options.inJustDecodeBounds = false;
Bitmap b=BitmapFactory.decodeResource(path, options);
private
LruCache<string,
bitmap
> 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<string,
bitmap=
""
>(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);
}
}
Android 圖片 OOM問題總結
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中配置相應的圖片資源,否則在不同分辨率機器上都是同樣大小(像素點數量),顯示出來的大小就不對了。
Android異步加載圖片,解決圖片過大OOM問題
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<String, SoftReference<Bitmap>> imageCache;// 軟引用集合 public AsyncImageLoaderCore(Context context) { this.context = context; this.imageCache = new HashMap<String, SoftReference<Bitmap>>(); } public Bitmap loadBitmap(final String imageUrl, final ImageView imageView, final ImageCallback imageCallback) { if (imageCache.containsKey(imageUrl)) { SoftReference<Bitmap> 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>(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); } }