Intereting Posts

Bitmap.copy () выдает ошибку из памяти

Я использую universal-image-loader библиотеку universal-image-loader изображений для загрузки изображений, но когда я вызываю copy() в загруженном файле растрового изображения, в некоторых случаях я получаю OutOfMemoryError . Вот мой код:

  ImageLoader.getInstance().loadImage(path, new ImageLoadingListener() { @Override public void onLoadingStarted(String arg0, View arg1) { // TODO Auto-generated method stub } @Override public void onLoadingFailed(String arg0, View arg1, FailReason arg2) { // TODO Auto-generated method stub } @Override public void onLoadingComplete(String arg0, View arg1, Bitmap arg2) { bm = arg2; } @Override public void onLoadingCancelled(String arg0, View arg1) { // TODO Auto-generated method stub } }); Bitmap bm2= bm.copy(Bitmap.Config.ARGB_8888, true); //where the crash happens 

Мне нужно, чтобы второй Bitmap не изменялся, поэтому я могу рисовать его.

Solutions Collecting From Web of "Bitmap.copy () выдает ошибку из памяти"

Прежде всего, попробуйте найти немного времени, чтобы прочитать хорошую официальную документацию о растровых изображениях: эффективное отображение битмапов

Это даст вам понять, почему и когда происходит java.lang.OutofMemoryError . И как этого избежать.

Как насчет вашего вопроса: см. Эту статью: Android: конвертировать неизменяемый битмап в Mutable

Но из уровня API 11 только options.inMutable доступны для загрузки файла в изменчивое растровое изображение.

Итак, если мы создаем приложение с уровнем API менее 11, мы должны найти другие альтернативы.

Один из вариантов – создание другого растрового изображения путем копирования источника

bitmap. mBitmap = mBitmap.copy(ARGB_8888 ,true);

Но будет OutOfMemoryException если исходный файл большой. Фактически, если мы хотим отредактировать исходный файл, мы столкнемся с этой проблемой. Мы должны иметь возможность загружать по меньшей мере изображение в память, но большую часть мы не можем выделить другую копию в память.

Итак, мы должны сохранить декодированные байты в некоторых местах и ​​очистить существующее растровое изображение, а затем создать новую изменяемую растровую карту и снова загрузить сохраненные байты в растровое изображение. Даже для копирования байтов мы не можем создать еще один ByteBuffer внутри памяти. В этом случае необходимо использовать MappedByteBuffer который будет выделять байты внутри файла диска.

Следующий код объяснит ясно:

 //this is the file going to use temporally to save the bytes. File file = new File("/mnt/sdcard/sample/temp.txt"); file.getParentFile().mkdirs(); //Open an RandomAccessFile /*Make sure you have added uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" into AndroidManifest.xml file*/ RandomAccessFile randomAccessFile = new RandomAccessFile(file, "rw"); // get the width and height of the source bitmap. int width = bitmap.getWidth(); int height = bitmap.getHeight(); //Copy the byte to the file //Assume source bitmap loaded using options.inPreferredConfig = Config.ARGB_8888; FileChannel channel = randomAccessFile.getChannel(); MappedByteBuffer map = channel.map(MapMode.READ_WRITE, 0, width*height*4); bitmap.copyPixelsToBuffer(map); //recycle the source bitmap, this will be no longer used. bitmap.recycle(); //Create a new bitmap to load the bitmap again. bitmap = Bitmap.createBitmap(width, height, Config.ARGB_8888); map.position(0); //load it back from temporary bitmap.copyPixelsFromBuffer(map); //close the temporary file and channel , then delete that also channel.close(); randomAccessFile.close(); 

И вот пример кода.

Вы не можете много сделать с ошибкой outmememory bitmap, за исключением того, что растровое изображение, которое вы копируете или отображаете, не так велико. К счастью, универсальный imageloader имеет функцию сжатия растрового изображения путем изменения конфигурации. Поэтому дайте Bitmap.Config.RGG_565 попробовать. Предполагалось, что он будет половиной объема памяти растрового изображения. Вы также можете запросить размер большой кучи. Еще одна вещь, которую вы можете сделать, – скопировать масштабированную версию растрового изображения.

Как сказал Illegel Argument, вам нужно убедиться, что битмап не слишком большой. Кроме того, убедитесь, что вы загружаете только один битмап за раз в память.

Вы можете динамически масштабировать растровое изображение с помощью BitmapFactory

 Bitmap b = BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length) image.setImageBitmap(Bitmap.createScaledBitmap(b, 300, 300, false)); 

Будьте благодарны за то, что это происходит на вашем устройстве, а не только на устройствах вашего пользователя.

1) Это то, с чем вам приходится справляться, и реагировать соответствующим образом. Отобразите сообщение об ошибке или загрузите более низкое разрешение растрового изображения. Ваше приложение будет работать на многих устройствах, каждый из которых имеет разный объем памяти.

2) Используйте важную функцию Bitmap.recycle после каждой операции, которая делает ваш старый битмап избыточным. Это немедленно освободит память для следующей работы, не дожидаясь запуска GC и возможных ошибок в памяти.

Загрузите этот код с сайта

http://www.androidhive.info/2012/02/android-custom-listview-with-image-and-text/

Извлечение его ImageLoader, кэш файлов, классы кэша памяти используют их в вашем растровом изображении, чтобы вообще не создавать исключение из памяти и кэшировать изображения и повышать производительность

Используйте этот код для полной цели

Сделайте следующие классы в своем коде и в последнем использовании imageloader загрузите url, передайте его url, imageview и drawable, чтобы показать incase url не возвращает никакого изображения

FileCache.java

 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(),"LazyList"); 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.java

 public class MemoryCache { private Map<String, SoftReference<Bitmap>> cache=Collections.synchronizedMap(new HashMap<String, SoftReference<Bitmap>>()); public Bitmap get(String id){ if(!cache.containsKey(id)) return null; SoftReference<Bitmap> ref=cache.get(id); return ref.get(); } public void put(String id, Bitmap bitmap){ cache.put(id, new SoftReference<Bitmap>(bitmap)); } public void clear() { cache.clear(); } } 

Utils.java

 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){} } } 

ImageLoader.java

 public class ImageLoader { MemoryCache memoryCache=new MemoryCache(); FileCache fileCache; private Map<ImageView, String> imageViews=Collections.synchronizedMap(new WeakHashMap<ImageView, String>()); ExecutorService executorService; public ImageLoader(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 getBitmap(String url) { File f=fileCache.getFile(url); //from SD cache Bitmap b = decodeFile(f); if(b!=null) return b; //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 (Exception ex){ ex.printStackTrace(); 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(); } } в public class ImageLoader { MemoryCache memoryCache=new MemoryCache(); FileCache fileCache; private Map<ImageView, String> imageViews=Collections.synchronizedMap(new WeakHashMap<ImageView, String>()); ExecutorService executorService; public ImageLoader(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 getBitmap(String url) { File f=fileCache.getFile(url); //from SD cache Bitmap b = decodeFile(f); if(b!=null) return b; //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 (Exception ex){ ex.printStackTrace(); 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(); } } 

Вызовите этот код, где вы хотите кэшировать или загружать или управлять изображениями

  imageLoader.DisplayImage(song.get(CustomizedListView.KEY_THUMB_URL), thumb_image);