VM won't let us allocation... bytes while downloading images - android

I am building a news paper app for that I need to show news paper images(epaper) in gallary view... I need to download about 100 images. for that I use asyncTask and for every download image I create new AsyncTask object and,when I am trying to download image and set into gallary I have the error in middle "VM won't let us allocation... bytes" and crash the app.
new AsyncTask<String, Void, Bitmap> () {
#Override
protected Bitmap doInBackground(String... params) {
HttpGet httpRequest;
try {
httpRequest = new HttpGet(new URL(params[0]).toURI());
HttpClient httpClient = new DefaultHttpClient();
HttpResponse response = (HttpResponse) httpClient.execute(httpRequest);
HttpEntity entity = response.getEntity();
BufferedHttpEntity bufHttpEntity = new BufferedHttpEntity(entity);
InputStream is = bufHttpEntity.getContent();
return BitmapFactory.decodeStream(is);
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (URISyntaxException e) {
e.printStackTrace();
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}/* catch (Error e) {
e.printStackTrace();
}*/
return null;
}
#Override
protected void onPostExecute(Bitmap result) {
if(result != null) {
img.setImageBitmap(ePaperInfo.getImgJpg1());
notifyDataSetChanged();
}
}
}
show the error in logcat:
Please help me
Thanks in advance.

You should definetly not keep 100 Bitmaps on memory at the same time. You need to download only the Bitmaps needed and then call recycle() before downloading new Bitmaps.
Have a look at this exaple for the preferred way of doing what you want: ImageDownloader

Another option for image loading that I use is Prime, I use it in all of my projects and its pretty simple and efficient.

Related

How to implement long-running network uploads in Android not using AsyncTask and not using libraries

What is the native Android way to implement long running network operations (like uploading a bunch of photos) without having to use libraries like RoboSpice?
I've read numerous topics on stackoverflow suggesting that asynctask is not suitable for long running operations as it is closely tied to an activity's lifecycle, might lead to memory leaks and since android 3.2 there is only one thread for all asynctasks for an app. (not sure about this last one)
How do I replace my asynctask with something else?
Now, I've heard of handlers, executors, services and what not, but how exactly do I implement them in my code and which one to choose?
Here is an example of the asynctask I use
I have removed a lot of code, just so you can see the basic structure
public class UploadPhotosToServer extends AsyncTask<String, Void, Boolean> {
#Override
protected Boolean doInBackground(String... args) {
HashMap<String, String> params = new HashMap<String, String>();
try {
if(uploadImageToServer(id, path, params)) {
success = true;
} else {
success = false;
}
} catch (Exception e) {
e.printStackTrace();
success = false;
}
return success;
}
public boolean uploadImageToServer(int imageId, String imagePath, HashMap<String, String> params) throws Exception {
try {
JSONObject json = jsonParser.uploadImageToServer(imagePath, params);
JSONObject message = json.getJSONObject("message");
String serverResponse = message.getString("success");
if (serverResponse.contentEquals("true") {
return true;
} else {
return false;
}
} catch (JSONException e) {
e.printStackTrace();
return false;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
}
and here is jsonParser.uploadImageToServer
public JSONObject uploadImageToServer(String imagePath, HashMap<String, String> params) throws Exception {
HttpResponse response;
MultipartEntityBuilder multipartEntity;
HttpPost postRequest;
HttpContext localContext;
Bitmap bitmap;
try {
// Set the http handlers
httpClient = new DefaultHttpClient();
localContext = new BasicHttpContext();
postRequest = new HttpPost(SERVER + "images");
// Send the package
multipartEntity = MultipartEntityBuilder.create();
multipartEntity.setMode(HttpMultipartMode.BROWSER_COMPATIBLE);
multipartEntity.addPart("file", new FileBody(new File(imagePath)));
for (Map.Entry<String, String> entry : params.entrySet()) {
multipartEntity.addTextBody(entry.getKey(), entry.getValue());
}
postRequest.setEntity(multipartEntity.build());
// Get the response. we will deal with it in onPostExecute.
response = httpClient.execute(postRequest, localContext);
HttpEntity httpEntity = response.getEntity();
inputStream = httpEntity.getContent();
try {
BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream, "iso-8859-1"), 8);
StringBuilder sb = new StringBuilder();
String line = null;
while ((line = reader.readLine()) != null) {
sb.append(line + "\n");
}
json = sb.toString();
inputStream.close();
reader.close();
} catch (ClientProtocolException e1) {
e1.printStackTrace();
} catch (IOException e1) {
e1.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
// Try parsing the string to a JSON object
try {
jsonObject = new JSONObject(json);
} catch (JSONException e) {
e.printStackTrace();
}
// Return JSON String
return jsonObject;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
I think for a set of uploads I would consider implementing an IntentService. As explained at the link it will process a list of intents in a worker thread until that list is exhausted at which point the service will shutdown again.
The implementation of an IntentService is very simple. An example based on the example you give above;
public class ImageUploadIntentService extends IntentService {
public ImageUploadIntentService() {
super("ImageUploadIntentService");
}
#Override
public void onCreate() {
// Not a required implementation but you might want to setup any dependencies
// here that can be reused with each intent that the service is about to
// receive.
super.onCreate();
}
#Override
public void onHandleIntent(Intent intent) {
// Process your intent, this presumably will include data such as the local
// path of the image that you want to upload.
try {
uploadImageToServer(intent.getExtra("image_to_upload"), params);
} catch (Exception e) {
// Oh :( Consider updating any internal state here so we know the state
// of play for later
}
}
public JSONObject uploadImageToServer(String imagePath, HashMap<String, String> params) throws Exception {
// All of your upload code
}
}
Then to call the service it is as simple as;
Intent intent = new Intent(this, ImageUploadIntentService.class)
.putExtra("image_to_upload", mImagePath);
startService(intent);
This does leave us with the issue of indicating the progress of your upload queue. We can solve this by using a ResultReceiver. A result receiver is Parcelable so we can send it with the intent in order to listen out for results we might be interested in. You can handle the ResultReceiver with either an Activity and suitable piece of progress dialog, or if you want a persistent notification with a progress bar then you could use a Service to host the receiver.
It is a little more involved than using an AsyncTask, but it does give you a little more flexibility and is not as attached to the Activity lifecycle. Another gotcha with the IntentService it will still only make you one worker thread so image uploads could not happen concurrently. But I might consider breaking your Bitmap JPEG compression to it's own IntentService then you could have the compression happening on the next image in the queue while the first is being uploaded.

Set image to downloaded bitmap in a separate class

I am trying to pass an imageview to a non activity class that will handle looking up the image from online and then subsequently set the image. My error that I am receiving is that when trying to set the image, the bitmap is read as null even though it has been received.
my constructor
ImageView iview_image;
public ImageLoader(String url, Context newContext, ItemsDto items, ImageView imageView)
{
try
{
Log.e("IMGURL",url);
str_img=url;
context=newContext;
this.context=newContext;
itemsDto=items;
iview_image=imageView;
iview_image.findViewById(R.id.icon);
}
my async task
protected Void doInBackground(Void... arg0)
{
try
{
Log.e("Async Img Load", "Before the try");
//Sets image status to help other classes know when image is ready
//image lookups
URL url = new URL(str_img);
HttpGet httpRequest = null;
httpRequest = new HttpGet(url.toURI());
//http get
HttpClient httpclient = new DefaultHttpClient();
HttpResponse response = (HttpResponse) httpclient.execute(httpRequest);
HttpEntity entity = response.getEntity();
BufferedHttpEntity b_entity = new BufferedHttpEntity(entity);
InputStream input = b_entity.getContent();
bm_productImage = BitmapFactory.decodeStream(input);
setBm_productImage(bm_productImage);
str_imgStatus="Image recieved";
}
catch (Exception e)
{
Log.e("IMG_ERROR",e.toString());
}
try{iview_image.setImageBitmap(getBm_productImage());}
catch(Exception e){ Log.e("more errors wheee", e.toString());}
doPendingActivity();
return null;
}
#Override
protected void onPostExecute(Void result)
{
// TODO Auto-generated method stub
super.onPostExecute(result);
try
{
}
catch(Exception e)
{
Log.e("Post_ERROR", e.toString());
}
}
I've been where you are, and I'll give you a recommendation. However, first, I'll answer your question. The way I downloaded a stream from a URL and saved it into a Bitmap was:
try {
URL url_obj = new URL(url);
Bitmap imageToReturn = BitmapFactory.decodeStream(url_obj.openConnection().getInputStream());
return imageToReturn; // or do whatever you want
} catch (MalformedURLException e) {
return null;
} catch (SocketTimeoutException e) {
return null;
} catch (IOException e) {
return null;
}
However, this solution is far from ideal when dealing with a lot of images. Android does not handle Bitmaps in memory well, and after you allocate a lot of Bitmaps in memory, it's a matter of time before you get an OutOfMemoryError exception thrown in your face.
I'd recommend using an image downloading/caching library like Picasso (http://square.github.io/picasso/). You can download the JAR file and include it in your project (it's really just that simple!). The default usage scenario is:
Picasso.with(context).load("http://i.imgur.com/DvpvklR.png").into(imageView);
but that's not the only possibility. If you want to save the bitmap or do something else with it, you can do:
Picasso.with(context).load(url).into(new Target() {
#Override
public void onBitmapLoaded(Bitmap bitmap, Picasso.LoadedFrom loadedFrom) {
// do what you want to do with the bitmap
// if it has already been downloaded, it will be loaded from
// cache (memory or disk). The loaded bitmap is in the parameter
}
#Override
public void onBitmapFailed(Drawable drawable) {
// whatever you want to do if if could not load the image
}
#Override
public void onPrepareLoad(Drawable drawable) {
// do whatever you want to do right before your request is submitted
}
});
Any of the methods can be empty if you want, use it as needed (all of the methods need to be there though, or the interface implementation will give you a compilation error).
I think you'll find this solution to be better and it will save you headaches in the future when you start to run out of memory. I hope it was useful!

Android- Not getting full response from HttpResponse

I am trying to get an HttpResponse in xml but Im not getting the whole response, what is courious is that if I loop the request the response ends in different parts but is never full.
I use the same code to request things from different Urls but I only get problems with one.
Here is the code of the AsyncTask:
public class NetworkTask extends AsyncTask<String, Void, HttpResponse> {
private AsyncTaskListener listener;
#Override
protected HttpResponse doInBackground(String... params) {
String link = params[0];
HttpGet request = new HttpGet(link);
AndroidHttpClient client = AndroidHttpClient.newInstance("Android");
try {
HttpResponse httpResponse = client.execute(request).;
return httpResponse;
} catch (IOException e) {
e.printStackTrace();
return null;
} finally {
client.close();
}
}
#Override
protected void onPostExecute(HttpResponse result) {
if (result != null){
try {
String sRes = EntityUtils.toString(result.getEntity());
listener.onNTCompleted(sRes);
} catch (IllegalStateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public NetworkTask(AsyncTaskListener listener){
this.listener=listener;
}
}
I am not sure if this helps you but you have a problem because EntityUtils.toString() reads data from the network stream, which should not be done on UI thread (onPostExecute). Try moving EntityUtils.toString() to doInBackground() first. This may not help solve your problem, but it is the right thing to do.

Android - Post status update with media Twitter & Tumblr

I am trying to allow Android users to post images to Twitter/Tumblr using my app. I am able to authenticate and retrieve user and account info, but I am having trouble with the actual image upload. (Basically I'm ok with all of the HTTP GET api calls, but not the HTTP POST).
I am receiving the following errors (Twitter/Tumblr respectively):
"response":{"errors":[{"message":"Error creating status","code":189}]}
"response":{"errors":["Error uploading photo."]},"meta":{"msg":"Bad Request","status":400}
Does anyone know what this means? I don't believe it's an authentication error, because I am able to get user info, etc... It looks to me like the problem is with the parameters, presumably media.
I have tried a number of options, including using the image file/data/url, using HttpParams/MultipartEntity, and using "media"/"media[]" but haven't had much success. Below is the current code that I am using. Is there something wrong with my format? Is there something else Twitter/Tumblr is looking for? If anyone has any ideas, suggestions, or improvements, they would be much appreciated. Thanks!
private class TwitterShareTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... params) {
String result = "";
HttpClient httpclient = GlobalValues.getHttpClient();
HttpPost request = new HttpPost("https://api.twitter.com/1.1/statuses/update_with_media.json");
try {
MultipartEntity entity = new MultipartEntity();
entity.addPart("status", new StringBody(ETdescription.getText().toString()));
entity.addPart("media[]", new FileBody(new File(GlobalValues.getRealPathFromURI(
Camera_ShareActivity.this, imageUri))));
request.setEntity(entity);
TwitterUtils.getTwitterConsumer().sign(request);
HttpResponse response = httpclient.execute(request, GlobalValues.getLocalContext());
HttpEntity httpentity = response.getEntity();
InputStream instream = httpentity.getContent();
result = GlobalValues.convertStreamToString(instream);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (OAuthMessageSignerException e) {
e.printStackTrace();
} catch (OAuthExpectationFailedException e) {
e.printStackTrace();
} catch (OAuthCommunicationException e) {
e.printStackTrace();
}
return result;
}
public void onPostExecute(String result) {
try {
JSONObject jObject = new JSONObject(result.trim());
System.out.println(jObject);
} catch (JSONException e) {
e.printStackTrace();
}
}
}
~~~ Edit: As requested by YuDroid ~~~
private static class TwitterUploadTask extends AsyncTask<String, Void, String> {
private File image;
private String message;
private OAuthConsumer twitterConsumer;
public TwitterUploadTask(OAuthConsumer consumer, File file, String string) {
this.image = file;
this.message = string;
this.twitterConsumer = consumer;
}
#Override
protected String doInBackground(String... params) {
String result = "";
HttpClient httpclient = GlobalValues.getHttpClient();
HttpPost request = new HttpPost("https://api.twitter.com/1.1/statuses/update_with_media.json");
ByteArrayInputStream bais = null;
try {
FileInputStream fis = new FileInputStream(image);
BufferedInputStream bis = new BufferedInputStream(fis, 8192);
Bitmap bm = BitmapFactory.decodeStream(bis);
bis.close();
fis.close();
ByteArrayOutputStream baos = new ByteArrayOutputStream();
bm.compress(Bitmap.CompressFormat.PNG, 100, baos);
byte[] myTwitterByteArray = baos.toByteArray();
bais = new ByteArrayInputStream(myTwitterByteArray);
} catch (IOException e) {
e.printStackTrace();
}
try {
MultipartEntity entity = new MultipartEntity();
entity.addPart("status", new StringBody(message));
entity.addPart("media[]", new InputStreamBody(bais, image.getName()));
request.setEntity(entity);
twitterConsumer.sign(request);
HttpResponse response = httpclient.execute(request, GlobalValues.getLocalContext());
HttpEntity httpentity = response.getEntity();
InputStream instream = httpentity.getContent();
result = GlobalValues.convertStreamToString(instream);
Log.i("statuses/update_with_media", result);
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (OAuthMessageSignerException e) {
e.printStackTrace();
} catch (OAuthExpectationFailedException e) {
e.printStackTrace();
} catch (OAuthCommunicationException e) {
e.printStackTrace();
}
return result;
}
public void onPostExecute(String result) {
try {
JSONObject jObject = new JSONObject(result.trim());
System.out.println(jObject);
} catch (JSONException e) {
e.printStackTrace();
}
}
}

Android webservice GET request replies only a part of the XML response

I'm trying to connect to a webservice offered by my heating at home. Putting the request URL into Chrome results in a complete XML file.
Subsequently I tried to do the same programmatically with an Android application, which unfortunately only replies about the half of the XML file.
I already tried several attempts, amongst others a simple HttpConnection:
private void androidHttpConnect() {
HttpURLConnection urlConnection=null;
try {
URL url = new URL("http://10.0.0.140:8080/user/menu");
urlConnection = (HttpURLConnection) url.openConnection();
BufferedInputStream in = new BufferedInputStream(
urlConnection.getInputStream());
Log.i("myapp",convertStreamToString(in));
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
urlConnection.disconnect();
}
}
private String convertStreamToString(InputStream is) {
return new Scanner(is).useDelimiter("\\A").next();
}
and the Android Http Client ...
HttpClient httpclient = AndroidHttpClient.newInstance("Android");
HttpGet httpget = new HttpGet("http://10.0.0.140:8080/user/menu");
HttpResponse response;
try {
response = httpclient.execute(httpget);
HttpEntity entity = response.getEntity();
if (entity != null) {
long len = entity.getContentLength();
Log.d("myapp", "content length "+len);
if (len != -1) {
try {
Log.d("myapp", EntityUtils.toString(entity));
} catch (ParseException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
} else {
// Stream content out
}
}
} catch (ClientProtocolException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
Interestingly those attempts cut the result on different positions, even though they only differ in about 5 characters. At this position there is no special character and the XML is quite short.
Anyone any idea? I also tried to run it in a ASyncTask to ensure no interrupt by the UI thread, but without success.
Thanks for your help.
Finally found the solution by myself! The problem wasn't the request but the output in the LogCat. Logging every line separately obtained the desired full response!

Categories

Resources