How to handle out of memory error? - android

I am using following code to display bitmap in my ImageView.
When I try to load image of size for example bigger than 1.5MB it give me error.
Any one suggest me solution?
try {
URL aURL = new URL(myRemoteImages[val]);
URLConnection conn = aURL.openConnection();
conn.connect();
InputStream is = null;
try
{
is= conn.getInputStream();
}catch(IOException e)
{
return 0;
}
int a= conn.getConnectTimeout();
BufferedInputStream bis = new BufferedInputStream(is);
Bitmap bm;
try
{
bm = BitmapFactory.decodeStream(bis);
}catch(Exception ex)
{
bis.close();
is.close();
return 0;
}
bis.close();
is.close();
img.setImageBitmap(bm);
} catch (IOException e) {
return 0;
}
return 1;
Log cat:
06-14 12:03:11.701: ERROR/AndroidRuntime(443): Uncaught handler: thread main exiting due to uncaught exception
06-14 12:03:11.861: ERROR/AndroidRuntime(443): java.lang.OutOfMemoryError: bitmap size exceeds VM budget
06-14 12:03:11.861: ERROR/AndroidRuntime(443): at android.graphics.BitmapFactory.nativeDecodeStream(Native Method)

You should decode with inSampleSize option to reduce memory consumption. Strange out of memory issue while loading an image to a Bitmap object
Another option inJustDecodeBounds can help you to find correct inSampleSize value http://groups.google.com/group/android-developers/browse_thread/thread/bd858a63563a6d4a

In general I think this blog covers the best practices on how to watch memory allocation/ how to use Weak/Soft References to avoid overflows.
Hope this helps.

try {
Bitmap bitmap=null;
byte[] profileImageInBytes;
String url="http://photo.net/learn/collage/complete-full-size.jpg";
HttpGet httpRequest = null;
httpRequest = new HttpGet(url);
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response = (HttpResponse) httpclient.execute(httpRequest);
HttpEntity entity = response.getEntity();
BufferedHttpEntity bufHttpEntity = new BufferedHttpEntity(entity);
InputStream instream = bufHttpEntity.getContent();
System.gc();
Runtime.getRuntime().gc();
BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
bmpFactoryOptions.inJustDecodeBounds = true;
bmpFactoryOptions.inTempStorage = new byte[32 * 1024];
bmpFactoryOptions.inSampleSize = 4;
bmpFactoryOptions.outWidth = 640;
bmpFactoryOptions.outHeight = 480;
bmpFactoryOptions.inDither=false;
bmpFactoryOptions.inInputShareable=true;
bitmap = BitmapFactory.decodeStream(instream, new Rect(), bmpFactoryOptions);
System.out.println("hi " +bitmap);
Bitmap map = Bitmap.createScaledBitmap(bitmap, 200, 200, true);
System.out.println("23");
System.out.println("hihi hi " +map);
BitmapDrawable bmd = new BitmapDrawable(map);
System.out.println("24");
System.out.println("hihi hi " +bmd);
ByteArrayOutputStream stream = new ByteArrayOutputStream();
System.out.println(stream);
map.compress(Bitmap.CompressFormat.JPEG, 100, stream);
int heightRatio = (int) Math.ceil(bmpFactoryOptions.outHeight
/ (float) 400);
int widthRatio = (int) Math.ceil(bmpFactoryOptions.outWidth
/ (float) 400);
if (heightRatio > 1 || widthRatio > 1) {
if (heightRatio > widthRatio) {
bmpFactoryOptions.inSampleSize = heightRatio;
} else {
bmpFactoryOptions.inSampleSize = widthRatio;
}
}
Bundle params=new Bundle();
params.putString("method", "photos.upload");
profileImageInBytes = stream.toByteArray();
System.out.println(profileImageInBytes);
System.out.println(" profile image bytes ");
System.out.println("Bytes : " + profileImageInBytes);
params.putByteArray("picture", profileImageInBytes);
System.out.println("My Picture : " + params);
mAsyncRunner.request(null, params, "POST",
new SampleUploadListener(), null);
System.out.println("Uploading");
}
catch (IOException e) {
e.printStackTrace();
}

Related

unable to post base64 converted image to rest service

I've written a code that selects image from gallery and convert it into a BASE64 string. as the selected images was too large the string is too big to be posted.
I have compressed the image so that the length of the string could be reduced. but still the length of the string is still large.
The code that i used is as follows,
This function sets the selected image in an imageView and
if (requestCode == RESULT_LOAD_IMAGE && resultCode == RESULT_OK && null != data) {
selectedImage = data.getData();
String[] filePathColumn = {MediaStore.Images.Media.DATA};
Cursor cursor = getContentResolver().query(selectedImage,
filePathColumn, null, null, null);
cursor.moveToFirst();
int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
sPicturePath = cursor.getString(columnIndex);
cursor.close();
imageView = (ImageView) findViewById(R.id.imageView);
Bitmap bm = ShrinkBitmap(sPicturePath, 300, 300);
imageView.setImageBitmap(bm);
/**
* Compute size of the image selected image
*/
File file = new File(sPicturePath);
if (file.exists()) {
double bytes = file.length();
double kilobytes = (bytes / 1024);
double megabytes = (kilobytes / 1024);
System.out.println("megabytes : " + megabytes);
Log.d("size", String.valueOf(megabytes));
}
imageView.setImageBitmap(BitmapFactory.decodeFile(sPicturePath));
Bitmap bm1 = BitmapFactory.decodeFile(sPicturePath);
//CropImage();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm1.compress(Bitmap.CompressFormat.JPEG, 100, baos); //bm is the bitmap object
byte[] byteArrayImage = baos.toByteArray();
encodedString = Base64.encodeToString(byteArrayImage, Base64.DEFAULT);
//Toast.makeText(getApplicationContext(), encodedString, Toast.LENGTH_SHORT).show();
String length = String.valueOf(encodedString.length());
//Toast.makeText(getApplicationContext(),lenght,Toast.LENGTH_SHORT).show();
Log.d("encodedString", encodedString);
Log.d("length", length);
ShrinkBitmap.java
Bitmap ShrinkBitmap(String file, int width, int height) {
BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
bmpFactoryOptions.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeFile(file, bmpFactoryOptions);
int heightRatio = (int) Math.ceil(bmpFactoryOptions.outHeight / (float) height);
int widthRatio = (int) Math.ceil(bmpFactoryOptions.outWidth / (float) width);
if (heightRatio > 1 || widthRatio > 1) {
if (heightRatio > widthRatio) {
bmpFactoryOptions.inSampleSize = heightRatio;
} else {
bmpFactoryOptions.inSampleSize = widthRatio;
}
}
bmpFactoryOptions.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeFile(file, bmpFactoryOptions);
return bitmap;
}
What i want to achieve is to select an image from gallery convert it into a BASE64 string and post it through a REST service.
A GET request has URL length restrictions. You need to send the file using MultipartEntity using HttpURLConnection. You need to create a post request.
If your filename is image.jpg.
Bitmap bitmap = ...;
String filename = "image.jpg";
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.PNG, 100, bos);
ContentBody contentPart = new ByteArrayBody(bos.toByteArray(), filename);
MultipartEntity reqEntity = new MultipartEntity(HttpMultipartMode.BROWSER_COMPATIBLE);
reqEntity.addPart("picture", contentPart);
String response = multipost("http://server.com", reqEntity);
And this is the multipost function.
private static String multipost(String urlString, MultipartEntity reqEntity) {
try {
URL url = new URL(urlString);
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setReadTimeout(10000);
conn.setConnectTimeout(15000);
conn.setRequestMethod("POST");
conn.setUseCaches(false);
conn.setDoInput(true);
conn.setDoOutput(true);
conn.setRequestProperty("Connection", "Keep-Alive");
conn.addRequestProperty("Content-length", reqEntity.getContentLength()+"");
conn.addRequestProperty(reqEntity.getContentType().getName(), reqEntity.getContentType().getValue());
OutputStream os = conn.getOutputStream();
reqEntity.writeTo(conn.getOutputStream());
os.close();
conn.connect();
if (conn.getResponseCode() == HttpURLConnection.HTTP_OK) {
return readStream(conn.getInputStream());
}
} catch (Exception e) {
Log.e(TAG, "multipart post error " + e + "(" + urlString + ")");
}
return null;
}
private static String readStream(InputStream in) {
BufferedReader reader = null;
StringBuilder builder = new StringBuilder();
try {
reader = new BufferedReader(new InputStreamReader(in));
String line = "";
while ((line = reader.readLine()) != null) {
builder.append(line);
}
} catch (IOException e) {
e.printStackTrace();
} finally {
if (reader != null) {
try {
reader.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return builder.toString();
}
More info at this SO thread.

How to resolve OutOfMemoryError on Bitmap in Android?

I want to set an image in ImageView, I am retrieving the image path in my first activity and I am passing it via Intent as a String to second activity. In the second activity I set the path to an ImageView. It's working properly, and I need to upload that picture to a server. So I decoded the path to a bitmap. It throws an OutOfMemoryError. How to resolve this issue?
And when I use front camera, there is no issues. Image is uploaded successfully. The problem is with the images taken by front camera of the device. What is the solution for this problem? Can anyone help?
Here is the code to convert the image path to a string and passing it via Intent:
if (requestCode == CAMERA_REQUEST && resultCode == RESULT_OK) {
Cursor cursor = getContentResolver().query(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, new String[]{MediaStore.Images.Media.DATA, MediaStore.Images.Media.DATE_ADDED, MediaStore.Images.ImageColumns.ORIENTATION}, MediaStore.Images.Media.DATE_ADDED, null, "date_added ASC");
if(cursor != null && cursor.moveToFirst())
{
do {
Uri uri = Uri.parse(cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)));
photoPath = uri.toString();
}while(cursor.moveToNext());
cursor.close();
try {
Intent intent = new Intent(MainActivity.this, ImageUploadActivity.class);
intent.putExtra("ImagePath", photoPath);
MainActivity.this.startActivity(intent);
}
catch (Exception e)
{
Toast.makeText(MainActivity.this, "Method invoked"+photoPath, Toast.LENGTH_SHORT).show();
}
}
Receiving Intent in Second Activity:
Intent camIntent = getIntent();
camPicPath = camIntent.getExtras().getString("ImagePath");
imageView = (ImageView) findViewById(R.id.imgView);
imageView.setImageBitmap(BitmapFactory.decodeFile(camPicPath));
Toast.makeText(getApplicationContext(), "PATHe"+camPicPath, Toast.LENGTH_SHORT).show();
bitmap = (BitmapFactory.decodeFile(camPicPath));
Method to Upload the file:
class ImageUploadTask extends AsyncTask<Void, Void, String> {
#Override
protected String doInBackground(Void... unsued) {
try {
HttpClient httpClient = new DefaultHttpClient();
HttpContext localContext = new BasicHttpContext();
HttpPost httpPost = new HttpPost("http://11.10.11.15/test/upload.php");
MultipartEntity entity = new MultipartEntity(
HttpMultipartMode.BROWSER_COMPATIBLE);
ByteArrayOutputStream bos = new ByteArrayOutputStream();
bitmap.compress(Bitmap.CompressFormat.JPEG, 100, bos);
byte[] data = bos.toByteArray();
/* entity.addPart("uploaded_file", new ByteArrayBody(data,
"myImage.jpg"));*/
// String newFilename= filename.concat("file");
// newFilename=filename+newFilename;
entity.addPart("uploaded_file", new ByteArrayBody(data,
filename));
// Log.e(TAG, "Method invoked");
httpPost.setEntity(entity);
HttpResponse response = httpClient.execute(httpPost,
localContext);
BufferedReader reader = new BufferedReader(
new InputStreamReader(
response.getEntity().getContent(), "UTF-8"));
StringBuilder builder = new StringBuilder();
String aux = "";
while ((aux = reader.readLine()) != null) {
builder.append(aux);
}
String sResponse = builder.toString();
return sResponse;
} catch (Exception e) {
if (dialog.isShowing())
dialog.dismiss();
Toast.makeText(getApplicationContext(), "Exception Message 1", Toast.LENGTH_LONG).show();
Log.e(e.getClass().getName(), e.getMessage(), e);
return null;
}
Use the following method:
Bitmap bm = ShrinkBitmap(imagefile, 300, 300);
image.setImageBitmap(bm);
Bitmap ShrinkBitmap(String file, int width, int height) {
BitmapFactory.Options bmpFactoryOptions = new BitmapFactory.Options();
bmpFactoryOptions.inJustDecodeBounds = true;
Bitmap bitmap = BitmapFactory.decodeFile(file, bmpFactoryOptions);
int heightRatio = (int) Math.ceil(bmpFactoryOptions.outHeight / (float) height);
int widthRatio = (int) Math.ceil(bmpFactoryOptions.outWidth / (float) width);
if (heightRatio > 1 || widthRatio > 1) {
if (heightRatio > widthRatio) {
bmpFactoryOptions.inSampleSize = heightRatio;
} else {
bmpFactoryOptions.inSampleSize = widthRatio;
}
}
bmpFactoryOptions.inJustDecodeBounds = false;
bitmap = BitmapFactory.decodeFile(file, bmpFactoryOptions);
return bitmap;
}
Or use inSampleSize when setting the image bitmap like this:
BitmapFactory.Options options = new BitmapFactory.Options();
options.inSampleSize = 4;
imageView.setImageBitmap(BitmapFactory.decodeFile(path, options));
you can add below property to application tag of manifiest file for high memory.
android:largeHeap="true"

Setting tab icon image from url

I have an application that has a set of tabs with images set as the TabIndecator. I want to take an image from a URL and set the TabIndecator image as the URL that is specified for that particular tab. Is there a way to do so? Can I take a ImageView and set it as the TabIndecator?
I want to take an image from a URL and set the TabIndecator image as the URL that is specified for that particular tab. Is there a way to do so?
Not directly, you have to download the image to the device as a Bitmap, wrap it in a BitmapDrawable, and set it with TabSpect.setIndicator()
Can I take a ImageView and set it as the TabIndecator?
Sure, TabSpec.setIndicator() can take a View as an argument if you so choose.
This method will allow you to get a local Bitmap from image's URL. My comments are in Spanish but I hope this example will be useful anyway. Make sure to run it in a AsyncTask or similar (not on UI Thread):
private static final int IO_BUFFER_SIZE = 8 * 1024;
private static final int MINIMO_TAM = 10;
public static final int MAXIMO_TAM = 640;
public static Bitmap loadRemoteImage(CharSequence urlImagen) {
if (null == urlImagen) {
return null;
}
Bitmap bm = null;
InputStream is = null;
BufferedInputStream bis = null;
DefaultHttpClient httpclient = new DefaultHttpClient();
httpclient.addRequestInterceptor(new GzipHttpRequestInterceptor());
httpclient.addResponseInterceptor(new GzipHttpResponseInterceptor());
try {
String urlSinEspacios = urlImagen.toString().replace(" ", "+");
// Hacer la llamada
HttpGet httpget = new HttpGet(urlSinEspacios);
HttpEntity entity = httpclient.execute(httpget).getEntity();
is = entity.getContent();
bis = new BufferedInputStream(is, IO_BUFFER_SIZE);
//Obtener solo el tamaƱo
BitmapFactory.Options o = new BitmapFactory.Options();
o.inJustDecodeBounds = true;
BitmapFactory.decodeStream(bis, null, o);
try {
bis.close();
is.close();
} catch (Exception e) {
}
//Calcular mejor escala
int scale = 1;
if (o.outHeight > MAXIMO_TAM || o.outWidth > MAXIMO_TAM) {
scale = (int) Math.pow(2, (int) Math.round(Math.log(MAXIMO_TAM / (double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5)));
}
//Descargar el real
entity = httpclient.execute(httpget).getEntity();
is = entity.getContent();
bis = new BufferedInputStream(is, IO_BUFFER_SIZE);
BitmapFactory.Options options = new BitmapFactory.Options();
options.inTempStorage = new byte[16 * 1024];
options.inSampleSize = scale;
bm = BitmapFactory.decodeStream(bis, null, options);
// Finalizado
httpclient.getConnectionManager().shutdown();
} catch (Exception e) {
bm = null;
} finally {
try {
bis.close();
is.close();
// Finalizado
httpclient.getConnectionManager().shutdown();
} catch (Exception e) {
}
}
return bm;
}
Then, you can use a BitmapDrawable to wrap this Bitmap and use with:
tabHost.newTabSpec("TODO").setIndicator("TODO", TODO).setContent(TODO);

How can I resize the image that was retrieved via URL and save it?

I am getting an image via URL from the Internet and trying to resize (to a smaller size) before saving it. I managed to save it, but I'm unable to resize it. How could I do that? Here is the code:
URL url = new URL(LogoURL);
InputStream input = url.openStream();
try {
OutputStream output = new FileOutputStream("data/data/com.android.mylogo/logo.jpg");
try {
//byte[] buffer = new byte[aReasonableSize];
int bytesRead = 0;
System.out.println("Buffer Length is \t:-" + buffer.length);
while ((bytesRead = input.read(buffer, 0, buffer.length)) >= 0) {
System.out.println("inside while");
output.write(buffer, 0, bytesRead);
}
} finally {
output.close();
System.out.println("saved image");
}
} finally {
input.close();
}
If you want to downscale the image to particular dimensions, you can use the following code:
HttpClient client = new DefaultHttpClient();
HttpGet request = new HttpGet(LogoURL);
try {
HttpResponse response = client.execute(request);
final int statusCode = response.getStatusLine().getStatusCode();
if (statusCode != HttpStatus.SC_OK) {
Log.w(LOG_TAG, "Error " + statusCode + " while retrieving bitmap from " + url);
return null;
}
HttpEntity entity = response.getEntity();
if (entity != null) {
InputStream is = null;
BufferedInputStream bis = null;
try {
is = url.openStream();
bis = new BufferedInputStream(is);
int sampleSize = 1;
bis.mark(Integer.MAX_VALUE);
Options bounds = new Options();
bounds.inJustDecodeBounds = true;
BitmapFactory.decodeStream(bis, null, bounds);
if (bounds.outWidth != -1) {
int width = bounds.outWidth;
int height = bounds.outHeight;
boolean withinBounds = width <= YOUR_DESIRED_WIDTH && height <= YOUR_DESIRED_HEIGHT;
int newWidth = width;
int newHeight = height;
while (!withinBounds) {
newWidth /= 2;
newHeight /= 2;
sampleSize *= 2;
withinBounds = newWidth <= YOUR_DESIRED_WIDTH && newHeight <= YOUR_DESIRED_HEIGHT;
}
} else {
Log.w(LOG_TAG, "Can't open bitmap at " + url);
return null;
}
try {
bis.reset();
} catch (IOException e) {
if(is != null){
is.close();
}
if(bis != null){
bis.close();
}
if(!entity.isRepeatable()){
entity.consumeContent();
response = client.execute(request);
entity = response.getEntity();
}
is = entity.getContent();
bis = new BufferedInputStream(is);
}
Options opts = new Options();
opts.inSampleSize = sampleSize;
Bitmap bm = BitmapFactory.decodeStream(bis, null, opts);
return bm;
} finally {
if (is != null) {
is.close();
}
if (bis != null) {
bis.close();
}
entity.consumeContent();
}
}
} catch (IOException e) {
request.abort();
Log.w(LOG_TAG, "I/O error while retrieving bitmap from " + url, e);
} catch (IllegalStateException e) {
request.abort();
Log.w(LOG_TAG, "Incorrect URL: " + url);
} catch (Exception e) {
request.abort();
Log.w(LOG_TAG, "Error while retrieving bitmap from " + url, e);
}
When you open the image with Options bounds = new Options(); bounds.inJustDecodeBounds = true;, then the image data won't be downloaded, only the size of the image. I use this size to calculate the new scale ratio to get the desired width and height.
With the option Options opts = new Options(); opts.inSampleSize = sampleSize; the BitmapFactory will download an already resized image. You save memory, and bandwidth this way.
Note, that the sampleSize values should be powers of 2. It works with different numbers as well, but this is much more efficient.
JPGs are compressed anyway, so there's no need to try to compress them any further.
In general, to compress something, have a look at the classes of java.util.zip package.

BitmapFactory.decodeStream returns null without exception

I try to load a remote image from a server and thanks to a lot of code examples on stackoverflow I have a solution which works in 2 out of 3 images. I don't really know what the problem is with the third picture and sometimes when letting the code run in the debugger the picture is loading. Also if I load the problem picture first the other two pictures are sometimes not loaded.
Here is the code:
public static Drawable getPictureFromURL(Context ctx, String url, final int REQUIRED_SIZE) throws NullPointerException {
//Decode image size
BitmapFactory.Options o = new BitmapFactory.Options();
int scale = 1;
if (o.outWidth > REQUIRED_SIZE) {
scale = (int) Math.pow(2, (int) Math.round(Math.log(REQUIRED_SIZE / (double) Math.max(o.outHeight, o.outWidth)) / Math.log(0.5)));
}
Log.i(Prototype.TAG, "scale: "+scale);
//Decode with inSampleSize
BitmapFactory.Options o2 = new BitmapFactory.Options();
o2.inSampleSize = scale;
Bitmap bmp;
try {
bmp = BitmapFactory.decodeStream((InputStream) Tools.fetch(url), null, o2);
if(bmp!=null)
return new BitmapDrawable(ctx.getResources(), bmp);
else
return null;
} catch (Exception e) {
Log.e(Prototype.TAG, "Exception while decoding stream", e);
return null;
}
}
During debugging I found out that o.outWidth is -1 which indicates an error, but no Exception is thrown, so I can't really tell what went wrong. The InputStream always returned a valid value, and I know that the picture exists on the server.
Best wishes,
Daniel
I found the answer here and updated the fetch method to:
private static InputStream fetch(String address) throws MalformedURLException,IOException {
HttpGet httpRequest = new HttpGet(URI.create(address) );
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response = (HttpResponse) httpclient.execute(httpRequest);
HttpEntity entity = response.getEntity();
BufferedHttpEntity bufHttpEntity = new BufferedHttpEntity(entity);
InputStream instream = bufHttpEntity.getContent();
return instream;
}

Categories

Resources