问题描述
8月四日至25号:19:10.111二四三一年至2603年/ com.example.francesco.guidedautorewithtabs E /艺术:投掷的OutOfMemoryError未能分配与1983651免费字节一个字节4194316分配和1937KB直到OOM
8月4号至25日:19:10.114 2431年至2603年/ com.example.francesco.guidedautorewithtabs E / AndroidRuntime:致命异常:GLThread 285
工艺:com.example.francesco.guidedautorewithtabs,PID:2431
java.lang.OutOfMemoryError:无法分配4194316字节分配与1983651免费字节,1937KB,直到OOM
在dalvik.system.VMRuntime.newNonMovableArray(本机方法)
在android.graphics.Bitmap.nativeCreate(本机方法)
在android.graphics.Bitmap.createBitmap(Bitmap.java:817)
在android.graphics.Bitmap.createBitmap(Bitmap.java:794)
在android.graphics.Bitmap.createBitmap(Bitmap.java:761)
在com.google.maps.api.android.lib6.gmm6.ocla(来源不明)
在com.google.maps.api.android.lib6.gmm6.ocoa(来源不明)
在com.google.maps.api.android.lib6.gmm6.ocoa(来源不明)
在com.google.maps.api.android.lib6.gmm6.ocob(来源不明)
在com.google.maps.api.android.lib6.gmm6.ocbak.a(来源不明)
在com.google.maps.api.android.lib6.gmm6.ocbas.a(来源不明)
在com.google.maps.api.android.lib6.gmm6.oxa(来源不明)
在com.google.maps.api.android.lib6.gmm6.ola(来源不明)
在com.google.maps.api.android.lib6.gmm6.olb(来源不明)
在com.google.maps.api.android.lib6.gmm6.o.cj.g(来源不明)
在com.google.maps.api.android.lib6.gmm6.o.cj.run(来源不明)
在我的Android $ C $词有很多都有被显示成不同片段的图像。几个这种存储在资产文件夹,其他拿起从HTTP请求。出于这个原因,我实现了图像的缓存,以不违背java.lang.OutOfMemoryError,但不过这个错误似乎仍然存在。我该如何解决这个问题呢?下面我实现的图像缓存。
ImageLoader的
公共类ImageLoader的{
的MemoryCache的MemoryCache =新的MemoryCache();
FileCache fileCache;
私人地图< ImageView的,字符串> imageViews = Collections.synchronizedMap(新的WeakHashMap< ImageView的,字符串>());
ExecutorService的ExecutorService的;
私人上下文的背景下;
公共ImageLoader的(上下文的背景下){
this.context =背景;
fileCache =新FileCache(上下文);
ExecutorService的= Executors.newFixedThreadPool(5);
}
最终诠释stub_id = R.drawable.no_image;
公共无效DisplayImage(字符串URL,ImageView的ImageView的)
{
imageViews.put(ImageView的,URL);
点阵位图= memoryCache.get(URL);
如果(位图!= NULL)
imageView.setImageBitmap(位);
其他
{
queuePhoto(URL,ImageView的);
imageView.setImageResource(stub_id);
}
}
私人无效queuePhoto(字符串URL,ImageView的ImageView的)
{
PhotoToLoad P =新PhotoToLoad(URL,ImageView的);
executorService.submit(新PhotosLoader(对));
}
私人位图getBitmapFromAsset(字符串则strName)
{
AssetManager assetManager = context.getAssets();
InputStream的ISTR = NULL;
尝试 {
ISTR = assetManager.open(则strName);
}赶上(IOException异常E){
e.printStackTrace();
}
点阵位图= BitmapFactory.de codeStream(ISTR);
返回的位图;
}
私人位图getBitmap(字符串URL)
{
文件F = fileCache.getFile(URL);
//从SD高速缓存
位图B =去codeFILE(F);
如果(B!= NULL)
返回b;
//从资产
位图BM = getBitmapFromAsset(URL);
如果(BM!= NULL)
返回BM;
//从网页
尝试 {
点阵位图= NULL;
URL IMAGEURL =新的网址(URL);
HttpURLConnection的康恩=(HttpURLConnection类)imageUrl.openConnection();
conn.setConnectTimeout(30000);
conn.setReadTimeout(30000);
conn.setInstanceFollowRedirects(真正的);
InputStream的是= conn.getInputStream();
的OutputStream OS =新的FileOutputStream(F);
Utils.CopyStream(是,OS);
os.close();
位=去codeFILE(F);
返回的位图;
}赶上(的Throwable前){
ex.printStackTrace();
如果(前的instanceof的OutOfMemoryError)
memoryCache.clear();
返回null;
}
}
//德$ C $连拍影像和扩展它来减少内存消耗
私人位图德codeFILE(文件f){
尝试 {
//德code图像尺寸
BitmapFactory.Options O =新BitmapFactory.Options();
o.inJustDe codeBounds = TRUE;
BitmapFactory.de codeStream(新的FileInputStream(f)项,空,O);
//找到正确的比例值。它应该是2的幂。
最终诠释REQUIRED_SIZE = 70;
INT width_tmp = o.outWidth,height_tmp = o.outHeight;
int标= 1;
而(真){
如果(width_tmp / 2'; REQUIRED_SIZE || height_tmp / 2'; REQUIRED_SIZE)
打破;
width_tmp / = 2;
height_tmp / = 2;
规模* = 2;
}
//德code与inSampleSize
BitmapFactory.Options O2 =新BitmapFactory.Options();
o2.inSampleSize =规模;
返回BitmapFactory.de codeStream(新的FileInputStream(f)项,空,O2);
}赶上(FileNotFoundException异常E){}
返回null;
}
//任务队列
私有类PhotoToLoad
{
公共字符串URL;
公众的ImageView ImageView的;
公共PhotoToLoad(字符串U,ImageView的我){
URL = U;
ImageView的=我;
}
}
类PhotosLoader实现Runnable {
PhotoToLoad photoToLoad;
PhotosLoader(PhotoToLoad photoToLoad){
this.photoToLoad = photoToLoad;
}
@覆盖
公共无效的run(){
如果(imageViewReused(photoToLoad))
返回;
BMP位= getBitmap(photoToLoad.url);
memoryCache.put(photoToLoad.url,BMP);
如果(imageViewReused(photoToLoad))
返回;
BitmapDisplayer BD =新BitmapDisplayer(BMP,photoToLoad);
活动一=(活动)photoToLoad.imageView.getContext();
a.runOnUiThread(BD);
}
}
布尔imageViewReused(PhotoToLoad photoToLoad){
字符串变量= imageViews.get(photoToLoad.imageView);
如果(标记== NULL ||!tag.equals(photoToLoad.url))
返回true;
返回false;
}
//用于在UI线程中显示位图
类BitmapDisplayer实现Runnable
{
点阵位图;
PhotoToLoad photoToLoad;
公共BitmapDisplayer(位图B,PhotoToLoad P){位= B,photoToLoad = P;}
公共无效的run()
{
如果(imageViewReused(photoToLoad))
返回;
如果(位图!= NULL)
photoToLoad.imageView.setImageBitmap(位);
其他
photoToLoad.imageView.setImageResource(stub_id);
}
}
公共无效clearCache(){
memoryCache.clear();
fileCache.clear();
}
}
FileCache
公共类FileCache {
私人文件cacheDir;
公共FileCache(上下文的背景下){
//查找目录保存缓存图像
如果(android.os.Environment.getExternalStorageState()。等于(android.os.Environment.MEDIA_MOUNTED))
cacheDir =新的文件(android.os.Environment.getExternalStorageDirectory(),TTImages_cache);
其他
cacheDir = context.getCacheDir();
如果(!cacheDir.exists())
cacheDir.mkdirs();
}
公共文件的getFile(字符串URL){
//我通过散列code识别图像。没有一个完美的解决方案,很好的演示。
字符串文件名=将String.valueOf(url.hash code());
//另一种可能的解决方案(感谢grantland)
//字符串文件名= URLEn coder.en code(URL);
文件F =新的文件(cacheDir,文件名);
返回F;
}
公共无效清除(){
文件[]文件= cacheDir.listFiles();
如果(文件== NULL)
返回;
对于(F文件:文件)
f.delete();
}
}
的MemoryCache
公共类的MemoryCache {
私有静态最后字符串变量=的MemoryCache;
私人地图<字符串,位图>缓存= Collections.synchronizedMap(
新的LinkedHashMap<字符串,位图>(10,1.5f,真)); //最后一个参数适用于LRU排序
私人长大小= 0; //当前分配的大小
专用长限制= 1000000; //最大内存字节
公众的MemoryCache(){
//利用现有堆大小25%
setLimit(调用Runtime.getRuntime()maxMemory()/ 4);
}
公共无效setLimit(长new_limit){
极限= new_limit;
Log.i(TAG的MemoryCache将最多使用+极限/ 1024/1024 +MB。);
}
公共位图获取(字符串ID){
尝试{
如果(!cache.containsKey(ID))
返回null;
// NullPointerException异常有时会发生在这里的http://$c$c.google.com/p/osmdroid/issues/detail ID = 78
返回cache.get(ID);
}赶上(NullPointerException异常前){
ex.printStackTrace();
返回null;
}
}
公共无效认沽(字符型,点阵位图){
尝试{
如果(cache.containsKey(ID))
大小 - = getSizeInBytes(cache.get(ID));
cache.put(ID,位图);
大小+ = getSizeInBytes(位);
checkSize();
}赶上(的Throwable日){
th.printStackTrace();
}
}
私人无效checkSize(){
Log.i(TAG,高速缓存大小=+尺寸+长度=+ cache.size());
如果(大小与GT;限制){
迭代器<进入<字符串,位图>> ITER = cache.entrySet()迭代(); //最近最少访问的项目将是第一个迭代
而(iter.hasNext()){
进入<字符串,位图>条目= iter.next();
大小 - = getSizeInBytes(entry.getValue());
iter.remove();
如果(大小与LT =限制)
打破;
}
Log.i(TAG,清洁缓存新的大小。+ cache.size());
}
}
公共无效清除(){
尝试{
// NullPointerException异常有时会发生在这里的http://$c$c.google.com/p/osmdroid/issues/detail ID = 78
cache.clear();
大小= 0;
}赶上(NullPointerException异常前){
ex.printStackTrace();
}
}
长getSizeInBytes(位图位图){
如果(位图== NULL)
返回0;
返回bitmap.getRowBytes()* bitmap.getHeight();
}
}
utils的
公共类utils的{
公共静态无效CopyStream(InputStream的是,OutputStream的OS)
{
最终诠释的buffer_size = 1024;
尝试
{
字节[]字节=新字节[BUFFER_SIZE];
对于(;;)
{
诠释计数= is.read(字节,0,BUFFER_SIZE);
如果(计数== - 1)
打破;
os.write(字节,0,计数);
}
}
赶上(例外前){}
}
}
试试这可能会帮助你在你的manifest文件添加此标记。
安卓largeHeap =真
这将分配一大堆你的应用程序
04-25 08:19:10.111 2431-2603/com.example.francesco.guidedautorewithtabs E/art﹕ Throwing OutOfMemoryError "Failed to allocate a 4194316 byte allocation with 1983651 free bytes and 1937KB until OOM"
04-25 08:19:10.114 2431-2603/com.example.francesco.guidedautorewithtabs E/AndroidRuntime﹕ FATAL EXCEPTION: GLThread 285
Process: com.example.francesco.guidedautorewithtabs, PID: 2431
java.lang.OutOfMemoryError: Failed to allocate a 4194316 byte allocation with 1983651 free bytes and 1937KB until OOM
at dalvik.system.VMRuntime.newNonMovableArray(Native Method)
at android.graphics.Bitmap.nativeCreate(Native Method)
at android.graphics.Bitmap.createBitmap(Bitmap.java:817)
at android.graphics.Bitmap.createBitmap(Bitmap.java:794)
at android.graphics.Bitmap.createBitmap(Bitmap.java:761)
at com.google.maps.api.android.lib6.gmm6.o.c.l.a(Unknown Source)
at com.google.maps.api.android.lib6.gmm6.o.c.o.a(Unknown Source)
at com.google.maps.api.android.lib6.gmm6.o.c.o.a(Unknown Source)
at com.google.maps.api.android.lib6.gmm6.o.c.o.b(Unknown Source)
at com.google.maps.api.android.lib6.gmm6.o.c.b.ak.a(Unknown Source)
at com.google.maps.api.android.lib6.gmm6.o.c.b.as.a(Unknown Source)
at com.google.maps.api.android.lib6.gmm6.o.x.a(Unknown Source)
at com.google.maps.api.android.lib6.gmm6.o.l.a(Unknown Source)
at com.google.maps.api.android.lib6.gmm6.o.l.b(Unknown Source)
at com.google.maps.api.android.lib6.gmm6.o.cj.g(Unknown Source)
at com.google.maps.api.android.lib6.gmm6.o.cj.run(Unknown Source)
In my Android code i have a lot of images that have to be displayed into different fragment. Several of this are stored in the assets folder, other picked up from an http request. For this reason i implement image caching in order to do not go against the java.lang.OutOfMemoryError, but nevertheless this error seems to persist. How can i resolve this problem? Below my implementation of image caching.
ImageLoader
public class ImageLoader {
MemoryCache memoryCache=new MemoryCache();
FileCache fileCache;
private Map<ImageView, String> imageViews=Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
ExecutorService executorService;
private Context context;
public ImageLoader(Context context){
this.context=context;
fileCache=new FileCache(context);
executorService=Executors.newFixedThreadPool(5);
}
final int stub_id= R.drawable.no_image;
public void DisplayImage(String url, ImageView imageView)
{
imageViews.put(imageView, url);
Bitmap bitmap=memoryCache.get(url);
if(bitmap!=null)
imageView.setImageBitmap(bitmap);
else
{
queuePhoto(url, imageView);
imageView.setImageResource(stub_id);
}
}
private void queuePhoto(String url, ImageView imageView)
{
PhotoToLoad p=new PhotoToLoad(url, imageView);
executorService.submit(new PhotosLoader(p));
}
private Bitmap getBitmapFromAsset(String strName)
{
AssetManager assetManager = context.getAssets();
InputStream istr = null;
try {
istr = assetManager.open(strName);
} catch (IOException e) {
e.printStackTrace();
}
Bitmap bitmap = BitmapFactory.decodeStream(istr);
return bitmap;
}
private Bitmap getBitmap(String url)
{
File f=fileCache.getFile(url);
//from SD cache
Bitmap b = decodeFile(f);
if(b!=null)
return b;
//from assets
Bitmap bm = getBitmapFromAsset(url);
if(bm!=null)
return bm;
//from web
try {
Bitmap bitmap=null;
URL imageUrl = new URL(url);
HttpURLConnection conn = (HttpURLConnection)imageUrl.openConnection();
conn.setConnectTimeout(30000);
conn.setReadTimeout(30000);
conn.setInstanceFollowRedirects(true);
InputStream is=conn.getInputStream();
OutputStream os = new FileOutputStream(f);
Utils.CopyStream(is, os);
os.close();
bitmap = decodeFile(f);
return bitmap;
} catch (Throwable ex){
ex.printStackTrace();
if(ex instanceof OutOfMemoryError)
memoryCache.clear();
return null;
}
}
//decodes image and scales it to reduce memory consumption
private Bitmap decodeFile(File f){
try {
//decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(new FileInputStream(f),null,o);
//Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE=70;
int width_tmp=o.outWidth, height_tmp=o.outHeight;
int scale=1;
while(true){
if(width_tmp/2<REQUIRED_SIZE || height_tmp/2<REQUIRED_SIZE)
break;
width_tmp/=2;
height_tmp/=2;
scale*=2;
}
//decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize=scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {}
return null;
}
//Task for the queue
private class PhotoToLoad
{
public String url;
public ImageView imageView;
public PhotoToLoad(String u, ImageView i){
url=u;
imageView=i;
}
}
class PhotosLoader implements Runnable {
PhotoToLoad photoToLoad;
PhotosLoader(PhotoToLoad photoToLoad){
this.photoToLoad=photoToLoad;
}
@Override
public void run() {
if(imageViewReused(photoToLoad))
return;
Bitmap bmp=getBitmap(photoToLoad.url);
memoryCache.put(photoToLoad.url, bmp);
if(imageViewReused(photoToLoad))
return;
BitmapDisplayer bd=new BitmapDisplayer(bmp, photoToLoad);
Activity a=(Activity)photoToLoad.imageView.getContext();
a.runOnUiThread(bd);
}
}
boolean imageViewReused(PhotoToLoad photoToLoad){
String tag=imageViews.get(photoToLoad.imageView);
if(tag==null || !tag.equals(photoToLoad.url))
return true;
return false;
}
//Used to display bitmap in the UI thread
class BitmapDisplayer implements Runnable
{
Bitmap bitmap;
PhotoToLoad photoToLoad;
public BitmapDisplayer(Bitmap b, PhotoToLoad p){bitmap=b;photoToLoad=p;}
public void run()
{
if(imageViewReused(photoToLoad))
return;
if(bitmap!=null)
photoToLoad.imageView.setImageBitmap(bitmap);
else
photoToLoad.imageView.setImageResource(stub_id);
}
}
public void clearCache() {
memoryCache.clear();
fileCache.clear();
}
}
FileCache
public class FileCache {
private File cacheDir;
public FileCache(Context context){
//Find the dir to save cached images
if (android.os.Environment.getExternalStorageState().equals(android.os.Environment.MEDIA_MOUNTED))
cacheDir=new File(android.os.Environment.getExternalStorageDirectory(),"TTImages_cache");
else
cacheDir=context.getCacheDir();
if(!cacheDir.exists())
cacheDir.mkdirs();
}
public File getFile(String url){
//I identify images by hashcode. Not a perfect solution, good for the demo.
String filename=String.valueOf(url.hashCode());
//Another possible solution (thanks to grantland)
//String filename = URLEncoder.encode(url);
File f = new File(cacheDir, filename);
return f;
}
public void clear(){
File[] files=cacheDir.listFiles();
if(files==null)
return;
for(File f:files)
f.delete();
}
}
MemoryCache
public class MemoryCache {
private static final String TAG = "MemoryCache";
private Map<String, Bitmap> cache=Collections.synchronizedMap(
new LinkedHashMap<String, Bitmap>(10,1.5f,true));//Last argument true for LRU ordering
private long size=0;//current allocated size
private long limit=1000000;//max memory in bytes
public MemoryCache(){
//use 25% of available heap size
setLimit(Runtime.getRuntime().maxMemory()/4);
}
public 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;
//NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78
return cache.get(id);
}catch(NullPointerException ex){
ex.printStackTrace();
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 void checkSize() {
Log.i(TAG, "cache size="+size+" length="+cache.size());
if(size>limit){
Iterator<Entry<String, Bitmap>> iter=cache.entrySet().iterator();//least recently accessed item will be the first one iterated
while(iter.hasNext()){
Entry<String, Bitmap> entry=iter.next();
size-=getSizeInBytes(entry.getValue());
iter.remove();
if(size<=limit)
break;
}
Log.i(TAG, "Clean cache. New size "+cache.size());
}
}
public void clear() {
try{
//NullPointerException sometimes happen here http://code.google.com/p/osmdroid/issues/detail?id=78
cache.clear();
size=0;
}catch(NullPointerException ex){
ex.printStackTrace();
}
}
long getSizeInBytes(Bitmap bitmap) {
if(bitmap==null)
return 0;
return bitmap.getRowBytes() * bitmap.getHeight();
}
}
Utils
public class Utils {
public static void CopyStream(InputStream is, OutputStream os)
{
final int buffer_size=1024;
try
{
byte[] bytes=new byte[buffer_size];
for(;;)
{
int count=is.read(bytes, 0, buffer_size);
if(count==-1)
break;
os.write(bytes, 0, count);
}
}
catch(Exception ex){}
}
}
Try this may help youadd this tag in your manifest file.
android:largeHeap="true"
it will allocate large heap for your app
这篇关于java.lang.OutOfMemoryError的Android的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!