I've searched a lot but I did not understand where to is my error.
First in my app I am getting images from the web if there is no net I am getting them from created database.
I am going to post my ImageLoader class then the memory class then the utils class if there is something wrong please I need some help Thanks in advance.
public class ClassImageLoader {
ClassMemoryCache memoryCache=new ClassMemoryCache();
ClassFileCache fileCache;
private Map<ImageView, String> imageViews=Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
ExecutorService executorService;
public ClassImageLoader(Context context){
fileCache=new ClassFileCache(context);
executorService=Executors.newFixedThreadPool(5);
}
final int stub_id=R.drawable.restlogobutton;
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);
ClassUtils.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;
}
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 ClassMemoryCache {
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 ClassMemoryCache(){
//use 25% of available heap size
setLimit(Runtime.getRuntime().maxMemory()/4);
}
public void setLimit(long new_limit){
limit=new_limit;
}
public Bitmap get(String id){
if(!cache.containsKey(id))
return null;
return cache.get(id);
}
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() {
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;
}
}
}
public void clear() {
cache.clear();
}
long getSizeInBytes(Bitmap bitmap) {
if(bitmap==null)
return 0;
return bitmap.getRowBytes() * bitmap.getHeight();
}
}
public class ClassUtils {
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){}
}
}
memory management is a pretty extensive and advanced topic but I'll post a very important tip all in capital letters:
DO NOT USE MAP<k,v> !!!
the map is keeping references to the imageview (which keeps the activity context) and the bitmaps for ever and it's one of the main reasons you have those memory losses. Further on the reference to context is keep your whole activity in memory, for ever. All very bad ideas.
You'll use a LruCache (available on the compatibility library) to cache the bitmaps, and let only the activity keep reference to the imageviews (either static from the XML or dynamically using an adapter)
here is a Google IO video http://www.youtube.com/watch?v=gbQb1PVjfqM where the guys from Google themselves are showing some best practices around this area, on the 4min mark they show the usage of the LruCache.
// replace this methods in your code and try I am not sure it will solve your error but once you can try.
private Bitmap getBitmap(String url)
{
//I identify images by hashcode. Not a perfect solution, good for the demo.
String filename=String.valueOf(url.hashCode());
File f=new File(cacheDir, filename);
//from SD cache
Bitmap b = decodeFile(f);
if(b!=null)
return b;
//from web
try {
Bitmap bitmap=null;
InputStream is=new URL(url).openStream();
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.inTempStorage = new byte[32*1024];
o2.inSampleSize=scale;
return BitmapFactory.decodeStream(new FileInputStream(f), null, o2);
} catch (FileNotFoundException e) {}
return null;
}
check this link for the ImageLoaderClass:
http://code.google.com/p/vimeoid/source/browse/apk/src/com/fedorvlasov/lazylist/ImageLoader.java
OOM issue check this link:
Strange out of memory issue while loading an image to a Bitmap object
And if you still get an error then check this one link that I have found after many search and has solved my Problem:
https://groups.google.com/forum/?fromgroups=#!topic/android-developers/vYWKY1Y6bUo
Related
I'm downloading the images from server and store into External storage using ImageLoader.But in my real device the images stored into generating hex dump and the file is opened in read only mode and file name is also changed.Why not images are stored in .jpg and .png format.Here is my Screen Shot.Can someone help me for how to resolve this issue.Thanks.
FileCache class
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(),"classnkk_images");
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();
}
}
ImageUrlLoader class
public class ImageUrlLoader {
int fixedHeight = 230;
MemoryCache memoryCache=new MemoryCache();
FileCache fileCache;
private Map<ImageView, String> imageViews= Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
ExecutorService executorService;
Handler handler=new Handler();//handler to display images in UI thread
public ImageUrlLoader(Context context){
fileCache=new FileCache(context);
executorService= Executors.newFixedThreadPool(5);
}
final int stub_id= R.drawable.img_placeholder;
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();
conn.disconnect();
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;
FileInputStream stream1=new FileInputStream(f);
BitmapFactory.decodeStream(stream1,null,o);
stream1.close();
//Find the correct scale value. It should be the power of 2.
final int REQUIRED_SIZE=470;
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;
FileInputStream stream2=new FileInputStream(f);
Bitmap bitmap=BitmapFactory.decodeStream(stream2, null, o2);
stream2.close();
return bitmap;
} catch (FileNotFoundException e) {
}
catch (IOException e) {
e.printStackTrace();
}
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() {
try{
if(imageViewReused(photoToLoad))
return;
Bitmap bmp=getBitmap(photoToLoad.url);
memoryCache.put(photoToLoad.url, bmp);
if(imageViewReused(photoToLoad))
return;
BitmapDisplayer bd=new BitmapDisplayer(bmp, photoToLoad);
handler.post(bd);
}catch(Throwable th){
th.printStackTrace();
}
}
}
boolean imageViewReused(PhotoToLoad photoToLoad){
String tag=imageViews.get(photoToLoad.imageView);
if(tag==null || !tag.equals(photoToLoad.url))
return true;
return false;
}
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);
Log.e(" In Image Loader ", " 33333333333333333333333");
}
}
}
public void clearCache() {
memoryCache.clear();
fileCache.clear();
}}
MemoryCache class
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();
}
}
Util class
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){}
}
}
And here is my code line in Adapter class
String str_DownLoadUrl = namespace + "/DownloadFile/FilePathMobile/ATTACHMENT/FileName/"+value;
imageUrl_Loader.DisplayImage(str_DownLoadUrl , imageView);
I am using universal-image-loader library to load images, but when I call copy() on a loaded bitmap file in some cases I get OutOfMemoryError.
Here is my code:
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
I need the second Bitmap not to be mutable so I can draw on it.
First of all try to find a little time to read good official documentation about bitmaps: Displaying Bitmaps Efficiently
It will give you understanding why and when java.lang.OutofMemoryError happens. And how to avoid it.
What about your question: see this article: Android: convert Immutable Bitmap into Mutable
But from API Level 11 only options.inMutable available to load the
file into a mutable bitmap.
So, if we are building application with API level less than 11, then
we have to find some other alternatives.
One alternative is creating another bitmap by copying the source
bitmap. mBitmap = mBitmap.copy(ARGB_8888 ,true);
But the will throw OutOfMemoryException if the source file is big.
Actually incase if we want to edit an original file, then we will face
this issue. We should be able to load at-least image into memory, but
most we can not allocate another copy into memory.
So, we have to save the decoded bytes into some where and clear
existing bitmap, then create a new mutable bitmap and load back the
saved bytes into bitmap again. Even to copy bytes we cannot create
another ByteBuffer inside the memory. In that case need to use
MappedByteBuffer that will allocate bytes inside a disk file.
Following code would explain clearly:
//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();
And here is sample code.
Be thankful that it happens on your device, and not only on your user's devices.
1) That's something you have to cope with, and react to appropriately. Display error message, or load lower resolution of the bitmap. Your app will run on many kinds of devices, each has different amount of memory.
2) Use important function Bitmap.recycle after each operation which makes your old bitmap redundant. This will immediately free memory for next work without waiting for GC to run, and possible out of memory errors.
You cant do much about the bitmap outofmemory error except ensuring that the bitmap you are copying or displaying is not much large. Fortunately universal imageloader has a feature to compress bitmap by changing the config. So give Bitmap.Config.RGG_565 a try. Its supposed to half the memory footprint of the bitmap. You can also request for large heap size. Another thing you can do is copy the scaled version of the bitmap.
As Illegel Argument said, you need to make sure that the Bitmap is not TOO large. Also, make sure that you are only loading one Bitmap at a time into memory.
You can dynamically scale the bitmap using BitmapFactory
Bitmap b = BitmapFactory.decodeByteArray(imageAsBytes, 0, imageAsBytes.length)
image.setImageBitmap(Bitmap.createScaledBitmap(b, 300, 300, false));
Download this code from the site
http://www.androidhive.info/2012/02/android-custom-listview-with-image-and-text/
extract its ImageLoader , file cache , memory cache classes use them in your bitmap to do things wont create out of memory exception at all and will cache images and increase performance
Use this Code to fullfill your purpose
Make the following classes in your code and in last use imageloader to load url pass it url , imageview and drawable to show incase url is not returning any image
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();
}
}
call this code where you want to cache or download or manage images
imageLoader.DisplayImage(song.get(CustomizedListView.KEY_THUMB_URL), thumb_image);
My class should return a default image (while downloading an image or failed download), and then returns the downloaded image (image from url).
But it always returns the default image.
How to solve that?
public class ImageLoader {
MemoryCache memoryCache=new MemoryCache();
FileCache fileCache;
ExecutorService executorService;
Handler handler=new Handler();//handler to display images in UI thread
Context context;
public Bitmap returnbitmap;
public ImageLoader(Context context){
this.context=context;
fileCache=new FileCache(context);
executorService=Executors.newFixedThreadPool(5);
}
final int stub_id=R.drawable.stub;
public Bitmap DisplayBitmap(String url)
{
Bitmap bitmap=memoryCache.get(url);
if(bitmap!=null)
return bitmap;
else
{
queueBitmap(url);
return BitmapFactory.decodeResource(context.getResources(), stub_id);
}
}
private void queueBitmap(String url)
{
BitmapToLoad p=new BitmapToLoad(url);
executorService.submit(new BitmapsLoader(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();
conn.disconnect();
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;
FileInputStream stream1=new FileInputStream(f);
BitmapFactory.decodeStream(stream1,null,o);
stream1.close();
//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;
FileInputStream stream2=new FileInputStream(f);
Bitmap bitmap=BitmapFactory.decodeStream(stream2, null, o2);
stream2.close();
return bitmap;
} catch (FileNotFoundException e) {
}
catch (IOException e) {
e.printStackTrace();
}
return null;
}
private class BitmapToLoad
{
public String url;
public BitmapToLoad(String u){
url=u;
}
}
class BitmapsLoader implements Runnable {
BitmapToLoad bitmapToLoad;
BitmapsLoader(BitmapToLoad bitmapToLoad){
this.bitmapToLoad=bitmapToLoad;
}
#Override
public void run() {
try{
Bitmap bmp=getBitmap(bitmapToLoad.url);
memoryCache.put(bitmapToLoad.url, bmp);
BitmapDisplay bd=new BitmapDisplay(bmp, bitmapToLoad);
handler.post(bd);
}catch(Throwable th){
th.printStackTrace();
}
}
}
class BitmapDisplay implements Runnable
{
Bitmap bitmap;
BitmapToLoad bitmapToLoad;
public BitmapDisplay(Bitmap b, BitmapToLoad p){bitmap=b;bitmapToLoad=p;}
public void run()
{
if(bitmap!=null)
returnbitmap=bitmap;
else
returnbitmap=BitmapFactory.decodeResource(context.getResources(), stub_id);
}
}
}
And to use my class imageLoader.DisplayBitmap("URL image");
How to fix it?
Make the DisplayBitmap method statically such as
public static DisplayBitmap(MemoryCache cache, String url);
Hi am creating an application which pulls resources from Foursquare and displays it on the android phone and am having problems with loading images. The app runs but for some reason it does not load on the phone it only shows me the loader image which I defined
My code are as follows:
public class PicAdapter extends BaseAdapter {
//use the default gallery background image
int defaultItemBackground;
//gallery context
private Context galleryContext;
//array to store bitmaps to display
private Bitmap[] imageBitmaps;
//placeholder bitmap for empty spaces in gallery
Bitmap placeholder;
//constructor
public PicAdapter(Context c) {
//instantiate context
galleryContext = c;
//create bitmap array
//imageBitmaps = new Bitmap[10];
//decode the placeholder image
//placeholder = BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher);
}
//BaseAdapter methods
//return number of data items i.e. bitmap images
public int getCount() {
return PicturesURLlist.size();
}
//return item at specified position
public Object getItem(int position) {
return position;
}
//return item ID at specified position
public long getItemId(int position) {
return position;
}
//get view specifies layout and display options for each thumbnail in the gallery
public View getView(int position, View convertView, ViewGroup parent) {
//create the view
ImageView imageView = new ImageView(galleryContext);
//specify the bitmap at this position in the array
//imageView.setImageBitmap(imageBitmaps[position]);
ImageLoader imgloader = new ImageLoader(getApplicationContext());
int loader = R.drawable.ic_launcher;
HashMap<String, String> song = new HashMap<String, String>();
song = PicturesURLlist.get(position);
//Log.d("Links", song.get(picurl));
imgloader.DisplayImage(song.get(picurl), loader, imageView );
//imageView.setImageBitmap((imgloader.DisplayImage(song.get(picurl), loader, imageView)));
//set layout options
imageView.setLayoutParams(new Gallery.LayoutParams(400, 600));
//scale type within view area
imageView.setScaleType(ImageView.ScaleType.FIT_CENTER);
//set default gallery item background
imageView.setBackgroundResource(defaultItemBackground);
//return the view
return imageView;
}
//custom methods for this app
//helper method to add a bitmap to the gallery when the user chooses one
}
My imagloader class
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);
}
int stub_id = R.drawable.ic_launcher;
public String DisplayImage(String url, int loader, ImageView imageView)
{
stub_id = loader;
imageViews.put(imageView, url);
Bitmap bitmap=memoryCache.get(url);
Log.d("Image loader succes", url);
if(bitmap!=null){
imageView.setImageBitmap(bitmap);
Log.d("Image loader succes", "true");
}
else
{
queuePhoto(url, imageView);
imageView.setImageResource(loader);
Log.d("Image loader succes", "false");
}
return null;
}
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;
}
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();
}
}
I am using lazy loading (fedorvlasov/lazylist) approach to download the image from the server but my problem is that as soon as i got the image from the server i want to save that in database but some of the images only save in the database.Please let me know the proper approach for this.
if i implemented the queue does the problem solve.
public class ImageLoader {
private Map<ImageView, String> imageViews=Collections.synchronizedMap(new WeakHashMap<ImageView, String>());
ExecutorService executorService;
public ImageLoader(Context context){
// fileCache=new FileCache(context);
executorService=Executors.newFixedThreadPool(0);
}
// final int stub_id=R.drawable.stub;
public void DisplayImage(String url, ImageView imageView)
{
imageViews.put(imageView, url);
Bitmap bitmap=null;//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);*/
DefaultHttpClient mHttpClient = new DefaultHttpClient();
HttpGet mHttpGet = new HttpGet(url);
HttpResponse mHttpResponse = mHttpClient.execute(mHttpGet);
// if (mHttpResponse.getStatusLine().getStatusCode() == HttpStatus.SC_OK)
{
HttpEntity entity = mHttpResponse.getEntity();
if ( entity != null)
{
// String String=EntityUtils.toByteArray(entity).toString();
// String=convertResizedImage(String);
InputStream inputStream = null;
inputStream = entity.getContent();
// byte[] imgarrbyte = new byte[inputStream.available()];
//inputStream.read(imgarrbyte);
bitmap = BitmapFactory.decodeStream(inputStream);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(CompressFormat.PNG, 100, bos);
String cardimage = Base64.encodeToString(bos.toByteArray(),
Base64.DEFAULT);
byte[] imgarrbyte = null;
try {
if (cardimage!= null) {
// Utils.writetoFile(, String.valueOf(position));
byte[] tempByArr = cardimage.getBytes();
imgarrbyte = Base64.decode(tempByArr,Base64.DEFAULT);
}
if (imgarrbyte != null && imgarrbyte.length > 0) {
bitmap = BitmapFactory.decodeByteArray(imgarrbyte, 0,
imgarrbyte.length);
}
}catch(OutOfMemoryError oome)
{
oome.printStackTrace();
}
}
}
return bitmap;
} catch (Exception ex){
ex.printStackTrace();
return null;
}
}
public String convertResizedImage(String imagedata) {
try {
// Step 1 : Image decoded
byte[] imageAsBytes = new byte[imagedata.length()];
imageAsBytes = Base64.decode(imagedata.getBytes("UTF8"),
Base64.DEFAULT);
BitmapFactory.Options opts = new BitmapFactory.Options();
int IMAGE_MAX_SIZE = 240, scale = 1;
if (opts.outHeight > IMAGE_MAX_SIZE
|| opts.outWidth > IMAGE_MAX_SIZE) {
scale = (int) Math.pow(2, (int) Math.round(Math
.log(IMAGE_MAX_SIZE
/ (double) Math.max(opts.outHeight,
opts.outWidth))
/ Math.log(0.5)));
}
// Step 2 : Compress the BITMAP
opts.inSampleSize = scale;
opts.inPurgeable = true;
opts.inPreferredConfig = Bitmap.Config.ARGB_4444;
// Decode with inSampleSize
opts.inJustDecodeBounds = false;
opts.inDither = false;
opts.inScaled = false;
// STEP 3 :
Bitmap bitMapimage = BitmapFactory.decodeByteArray(imageAsBytes, 0,
imageAsBytes.length, opts);
String tempstr = new String();
if (bitMapimage != null) {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitMapimage.compress(CompressFormat.JPEG, 100, bos);
tempstr = Base64.encodeToString(bos.toByteArray(),
Base64.DEFAULT);
}
return tempstr;
} catch (Exception e) {
// TODO Auto-generated catch block
e.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;
}
}
public void getImageSize(byte[] imgarrbyte, String fileName) {
File file = new File("/mnt/sdcard/", fileName);
FileOutputStream fos;
try {
fos = new FileOutputStream(file);
fos.write(imgarrbyte);
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
}
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);
if(imageViewReused(photoToLoad))
return;
addBitmapTodb(photoToLoad.url,bmp); //saving in database works sometimes.
BitmapDisplayer bd=new BitmapDisplayer(bmp, photoToLoad);
Activity a=(Activity)photoToLoad.imageView.getContext();
a.runOnUiThread(bd);
}
}
private void addBitmapTodb(String url, Bitmap bitmap) {
if (bitmap != null) {
Log.i("Bitmap", "addBitmapTodb==========");
Dao updateimage=new Dao();
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(CompressFormat.PNG, 100, bos);
String cardimage = Base64.encodeToString(bos.toByteArray(),
Base64.DEFAULT);
updateimage.updateimageindb(url,cardimage);
}
}
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);
}
}
}
thanks for reply again :) yes i m currently doing the same if you check function addBitmapTodb in above code.problem is here that i have used cursoradapater and calling imageloader from getview function by passing the imageurl,I have observed some isssue as like 1.if i do scrolling on listview,the same image url request is sent to imageloader for downloading the image 2.some of the images only saved in the database(maybe becouse of synchronization issue),I want to avoid such issue so i need some help on this.