Im reading image url from a Array list in doInBackground using for loop , but loop is not incrementing only 1st url is loading and saving image . here is code :
class DownloadImageTask extends AsyncTask<Void, Void, Bitmap> {
// This class definition states that DownloadImageTask will take String
// parameters, publish Integer progress updates, and return a Bitmap
#SuppressWarnings("unused")
protected Bitmap doInBackground(Void... paths) {
//URL url;
try {
for(int j=0; j<List.size();j++)
{
reviewImageLink =List.get(j).get(TAG_Image);
URL url = new URL(reviewImageLink);
// URL reviewImageURL;
String name = reviewImageLink.substring(reviewImageLink .lastIndexOf("/") + 1,reviewImageLink.length());
//try {
if (!hasExternalStoragePublicPicture(name)) {
isImage = false;
//new DownloadImageTask().execute();
Log.v("log_tag", "if");
isImage = true;
File sdImageMainDirectory = new File(Environment.getExternalStorageDirectory(), getResources().getString(R.string.directory));
//if(!sdImageMainDirectory.exists()){
sdImageMainDirectory.mkdirs();
File file = new File(sdImageMainDirectory, name);
Log.v("log_tag", "Directory created");}
//}
// catch (MalformedURLException e) {
// Log.v(TAG, e.toString()); }
// }
// }//try
// catch (Exception e) {
// e.printStackTrace();}
//url = new URL(List.get(j).get(TAG_Image));
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
int length = connection.getContentLength();
InputStream is = (InputStream) url.getContent();
byte[] imageData = new byte[length];
int buffersize = (int) Math.ceil(length / (double) 100);
int downloaded = 0;
int read;
while (downloaded < length) {
if (length < buffersize) {
read = is.read(imageData, downloaded, length);
} else if ((length - downloaded) <= buffersize) {
read = is.read(imageData, downloaded, length- downloaded);
} else {
read = is.read(imageData, downloaded, buffersize);
}
downloaded += read;
setProgress((downloaded * 100) / length);
}
Bitmap bitmap = BitmapFactory.decodeByteArray(imageData, 0,length);
if (bitmap != null) {
Log.i(TAG, "Bitmap created");
} else {
Log.i(TAG, "Bitmap not created");
}
is.close();
return bitmap;
}
}catch (MalformedURLException e) {
Log.e(TAG, "Malformed exception: " + e.toString());
} catch (IOException e) {
Log.e(TAG, "IOException: " + e.toString());
} catch (Exception e) {
Log.e(TAG, "Exception: " + e.toString());
}
return null;
}
protected void onPostExecute(Bitmap result) {
String name = reviewImageLink.substring(reviewImageLink.lastIndexOf("/") + 1,reviewImageLink.length());
if (result != null) {
hasExternalStoragePublicPicture(name);
saveToSDCard(result, name);
isImage = true;
} else {
isImage = false;
}
}
}
List is an interface, you can't use like List.size().Define one List subtype like ArrayList or something.There is no wrong with for loop.For ex:
List<Integer> li = new ArrayList<Integer>();
li.add(10);
li.add(20)';
for(int i = 0; i <= li.size(); ++i) {
//your stuff
}
Related
I have a for loop that will download image on a server and here is what it looks
for (int i = 0; i < sync_data.length(); i++) {
String main_link = "LINK" + folder + "/" + file_name;
FilePathname = sdCardDirectory + "/" + file_name;
DownloadFilesname(FilePathname, main_link);
index++;
p = (float) index / (float) sync_data.length();
p = p * (float) 100;
runOnUiThread(new Runnable() {
#Override
public void run() {
publishProgress((int) p);
}
});
}
/* Function Image Download */
public void DownloadFilesname(String filanme, String Urlname) {
try {
URL u = new URL(Urlname);
InputStream is = u.openStream();
DataInputStream dis = new DataInputStream(is);
byte[] buffer = new byte[1024];
int length;
FileOutputStream fos = new FileOutputStream(new File(filanme));
while ((length = dis.read(buffer)) > 0) {
fos.write(buffer, 0, length);
}
} catch (MalformedURLException mue) {
Log.e("SYNC getUpdate", "malformed url error", mue);
} catch (IOException ioe) {
Log.e("SYNC getUpdate", "io error", ioe);
} catch (SecurityException se) {
Log.e("SYNC getUpdate", "security error", se);
}
}
my problem is the publishProgress already updated even the image is not yet downloaded. This will cause the asynctask to be done but the image is still downloading..
How can I make that the image must be downloaded before increment?
You only have to call "publishProgress()" in your "doInBackground()" and then implement/override
protected void onProgressUpdate(Integer... progress) {
...
}
When you call "publishProgress()" the "onProgressUpdate()" event is called in the Ui/MainThread (it means you can use all the UI components inside it)
In an app I am making people can download a PDF file. On my Nexus 5 there is on problem when downloading the PDF but on an HTC One X I get an Out of Memory error. How can I avoid this? The code I am using is:
#Override
protected Boolean doInBackground(String... params) {
String fileUrl = params[0];
mFileName = params[1];
mFolder = new File(mContext.getFilesDir(), "pdfs");
mFolder.mkdir();
Random r = new Random();
int i1 = r.nextInt(99 - 10) + 99;
mFile = new File(mFolder, mFileName + "." + i1);
try {
mFile.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
try {
System.gc();
URL url = new URL(fileUrl);
HttpURLConnection urlConnection = (HttpURLConnection)url.openConnection();
urlConnection.connect();
InputStream inputStream = urlConnection.getInputStream();
FileOutputStream fileOutputStream = new FileOutputStream(mFile);
int totalSize = urlConnection.getContentLength();
byte[] buffer = new byte[MEGABYTE];
int bufferLength = 0;
long total = 0;
while((bufferLength = inputStream.read(buffer))>0 ){
total += bufferLength;
int progress = (int)((total * 100) / totalSize);
publishProgress(progress, (int)total, totalSize);
fileOutputStream.write(buffer, 0, bufferLength);
}
fileOutputStream.close();
return true;
} catch (FileNotFoundException e) {
mFile.delete();
e.printStackTrace();
} catch (MalformedURLException e) {
mFile.delete();
e.printStackTrace();
} catch (IOException e) {
mFile.delete();
e.printStackTrace();
}
return false;
}
#Override
protected void onPostExecute(Boolean success) {
if(mOnDownloadListener != null) {
File to = new File(mFolder, mFileName);
mFile.renameTo(to);
mOnDownloadListener.onDownloaded(success);
}
super.onPostExecute(success);
}
I am loading 10 Images from URL's that are stored in array . only last index url is loading and saving image in SD card . here is my code :
for(int j=0; j<List.size();j++)
{
reviewImageLink =List.get(j).get(TAG_Image).toString();
URL reviewImageURL;
String name = reviewImageLink;//.substring(reviewImageLink .lastIndexOf("/") + 1,reviewImageLink.length());
try {
reviewImageURL = new URL(reviewImageLink);
if (!hasExternalStoragePublicPicture(name)) {
isImage = false;
new DownloadImageTask().execute(reviewImageURL);
Log.v("log_tag", "if");
isImage = true;
File sdImageMainDirectory = new File(Environment.getExternalStorageDirectory(), getResources().getString(R.string.directory));
//if(!sdImageMainDirectory.exists()){
sdImageMainDirectory.mkdirs();
File file = new File(sdImageMainDirectory, name);
Log.v("log_tag", "Directory created");}
}
catch (MalformedURLException e) {
Log.v(TAG, e.toString()); }
}
}//try
catch (Exception e) {
e.printStackTrace();}
DownloaderTask:
class DownloadImageTask extends AsyncTask<URL, Integer, Bitmap> {
// This class definition states that DownloadImageTask will take String
// parameters, publish Integer progress updates, and return a Bitmap
protected Bitmap doInBackground(URL... paths) {
URL url;
try {
url = paths[0];
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
int length = connection.getContentLength();
InputStream is = (InputStream) url.getContent();
byte[] imageData = new byte[length];
int buffersize = (int) Math.ceil(length / (double) 100);
int downloaded = 0;
int read;
while (downloaded < length) {
if (length < buffersize) {
read = is.read(imageData, downloaded, length);
} else if ((length - downloaded) <= buffersize) {
read = is.read(imageData, downloaded, length- downloaded);
} else {
read = is.read(imageData, downloaded, buffersize);
}
downloaded += read;
publishProgress((downloaded * 100) / length);
}
Bitmap bitmap = BitmapFactory.decodeByteArray(imageData, 0,length);
if (bitmap != null) {
Log.i(TAG, "Bitmap created");
} else {
Log.i(TAG, "Bitmap not created");
}
is.close();
return bitmap;
} catch (MalformedURLException e) {
Log.e(TAG, "Malformed exception: " + e.toString());
} catch (IOException e) {
Log.e(TAG, "IOException: " + e.toString());
} catch (Exception e) {
Log.e(TAG, "Exception: " + e.toString());
}
return null;
}
protected void onPostExecute(Bitmap result) {
String name = reviewImageLink.substring(reviewImageLink.lastIndexOf("/") + 1,reviewImageLink.length());
if (result != null) {
hasExternalStoragePublicPicture(name);
saveToSDCard(result, name);
isImage = true;
} else {
isImage = false;
}
}
}
public void saveToSDCard(Bitmap bitmap, String name) {
boolean mExternalStorageAvailable = false;
boolean mExternalStorageWriteable = false;
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
mExternalStorageAvailable = mExternalStorageWriteable = true;
Log.v(TAG, "SD Card is available for read and write "+ mExternalStorageAvailable + mExternalStorageWriteable);
saveFile(bitmap, name);
} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
mExternalStorageAvailable = true;
mExternalStorageWriteable = false;
Log.v(TAG, "SD Card is available for read "+ mExternalStorageAvailable);
} else {
mExternalStorageAvailable = mExternalStorageWriteable = false;
Log.v(TAG, "Please insert a SD Card to save your Video "+ mExternalStorageAvailable + mExternalStorageWriteable);
}
}
private void saveFile(Bitmap bitmap, String name)
{
String filename = name;
ContentValues values = new ContentValues();
File sdImageMainDirectory = new File(Environment.getExternalStorageDirectory(), getResources().getString(R.string.directory));
sdImageMainDirectory.mkdirs();
File outputFile = new File(sdImageMainDirectory, filename);
values.put(MediaStore.MediaColumns.DATA, outputFile.toString());
values.put(MediaStore.MediaColumns.TITLE, filename);
values.put(MediaStore.MediaColumns.DATE_ADDED, System.currentTimeMillis());
values.put(MediaStore.MediaColumns.MIME_TYPE, "output.jpeg");
Uri uri = this.getContentResolver().insert(android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,values);
//Uri result = context.getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, image);
sendBroadcast(new Intent(Intent.ACTION_MEDIA_MOUNTED, Uri.parse("file://"+ Environment.getExternalStorageDirectory())));
try
{
OutputStream outStream = this.getContentResolver().openOutputStream(uri);
bitmap.compress(Bitmap.CompressFormat.JPEG, 95, outStream);
outStream.flush();
outStream.close();
}
catch (FileNotFoundException e)
{
e.printStackTrace();
} catch (IOException e)
{
e.printStackTrace();
}
}
private boolean hasExternalStoragePublicPicture(String name) {
File sdImageMainDirectory = new File(Environment.getExternalStorageDirectory(), getResources().getString(R.string.directory));
File file = new File(sdImageMainDirectory, name);
if (file != null)
{
file.delete();
}
return file.exists();
}
Pass the list to DownloadImageTask instead of URL then put a for loop in doInBackground,
I'm developing an android app. Now I'm parsing bbcode to html and display it inside a textview, the textview is inside a custom listview. I use Html.ImageGetter() to display the images downloaded from AsyncTask.
It works great for a low number of pictures. But if the app is asked to download 40-50 pictures, 40-50 tasks are created and it becomes a mess. Each task opens a stream to download the images. After that it decodes the bytes into bitmaps, resize them, save them to the sdcard and recycles the bitmaps.
Now if the app is loading all this images at the same time it uses a huge amount of ram. I managed to make it pass 48 mb. There is a big gap between 16 and 48 :(. I searched on how to solve this. I downloaded AsyncTask code from google:
http://google.com/codesearch/p?hl=en&sa=N&cd=2&ct=rc#uX1GffpyOZk/core/java/android/os/AsyncTask.java&q=lang:java%20AsyncTask
And set the pool size to 3. But this didn't helped. I really can't figure out where I'm loosing ram. As soon as I put a big task queue my ram goes crazy. After a few images are received it gets worst. I don't think it is the images since I can get to 30 mb before any image is displayed. The app itself including the view, information and its service uses 13 mb, all the rest is leaked here.
Does the queue itself make big ram allocations? Or is the Html.ImageGetter() leaking a huge amount of memory somehow? Is there a better way to do this?
Here I load the images:
public void LoadImages(String source) {
myurl = null;
try {
myurl = new URL(source);
} catch (MalformedURLException e) {
e.printStackTrace();
}
new DownloadImageFromPost().execute(myurl);
}
private class DownloadImageFromPost extends AsyncTask<URL, Integer, Bitmap> {
#Override
protected Bitmap doInBackground(URL... params) {
URL url;
Log.d(TAG, "Starting new image download");
try {
url = params[0];
HttpURLConnection connection = (HttpURLConnection) url
.openConnection();
int length = connection.getContentLength();
InputStream is = (InputStream) url.getContent();
byte[] imageData = new byte[length];
int buffersize = (int) Math.ceil(length / (double) 100);
int downloaded = 0;
int read;
while (downloaded < length) {
if (length < buffersize) {
read = is.read(imageData, downloaded, length);
} else if ((length - downloaded) <= buffersize) {
read = is.read(imageData, downloaded, length
- downloaded);
} else {
read = is.read(imageData, downloaded, buffersize);
}
downloaded += read;
publishProgress((downloaded * 100) / length);
}
Bitmap bitmap = BitmapFactory.decodeByteArray(imageData, 0,
length);
if (bitmap != null) {
Log.i(TAG, "Bitmap created");
} else {
Log.i(TAG, "Bitmap not created");
}
is.close();
return bitmap;
} catch (MalformedURLException e) {
Log.e(TAG, "Malformed exception: " + e.toString());
} catch (IOException e) {
Log.e(TAG, "IOException: " + e.toString());
} catch (Exception e) {
}
return null;
}
protected void onPostExecute(Bitmap result) {
String name = Environment.getExternalStorageDirectory() + "/tempthumbs/" + myurl.toString().hashCode() +".jpg";
String rname = Environment.getExternalStorageDirectory() + "/tempthumbs/" + myurl.toString().hashCode() +"-t.jpg";
try {
if (result != null) {
hasExternalStoragePublicPicture(name);
ImageManager manager = new ImageManager(context);
Bitmap rezised = manager.resizeBitmap(result, 300, 300);
saveToSDCard(result, name, myurl.toString().hashCode() +".jpg");
saveToSDCard(rezised, rname, myurl.toString().hashCode() +"-t.jpg");
result.recycle();
rezised.recycle();
} else {
}
} catch(NullPointerException e) {
}
Log.d(TAG, "Sending images loaded announcement");
Intent i = new Intent(IMAGE_LOADED);
i.putExtra("image", name);
i.putExtra("source", myurl.toString());
i.putExtra("class", true);
context.sendBroadcast(i);
}
}
private boolean hasExternalStoragePublicPicture(String name) {
File file = new File(name);
if (file != null) {
file.delete();
}
try {
file.createNewFile();
} catch (IOException e) {
e.printStackTrace();
}
return file.exists();
}
public void saveToSDCard(Bitmap bitmap, String name, String nam) {
boolean mExternalStorageAvailable = false;
boolean mExternalStorageWriteable = false;
String state = Environment.getExternalStorageState();
if (Environment.MEDIA_MOUNTED.equals(state)) {
mExternalStorageAvailable = mExternalStorageWriteable = true;
Log.v(TAG, "SD Card is available for read and write "
+ mExternalStorageAvailable + mExternalStorageWriteable);
saveFile(bitmap, name, nam);
} else if (Environment.MEDIA_MOUNTED_READ_ONLY.equals(state)) {
mExternalStorageAvailable = true;
mExternalStorageWriteable = false;
Log.v(TAG, "SD Card is available for read "
+ mExternalStorageAvailable);
} else {
mExternalStorageAvailable = mExternalStorageWriteable = false;
Log.v(TAG, "Please insert a SD Card to save your Video "
+ mExternalStorageAvailable + mExternalStorageWriteable);
}
}
private void saveFile(Bitmap bitmap, String fullname, String nam) {
ContentValues values = new ContentValues();
File outputFile = new File(fullname);
values.put(MediaStore.MediaColumns.DATA, outputFile.toString());
values.put(MediaStore.MediaColumns.TITLE, nam);
values.put(MediaStore.MediaColumns.DATE_ADDED, System
.currentTimeMillis());
values.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpg");
Uri uri = context.getContentResolver().insert(
android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
values);;
try {
OutputStream outStream = context.getContentResolver()
.openOutputStream(uri);
bitmap.compress(Bitmap.CompressFormat.JPEG, 95, outStream);
outStream.flush();
outStream.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
bitmap.recycle();
}
And here i call Html.ImageGetter(), this is inside a list getView:
holder.content.setText(Html.fromHtml(
processor.preparePostText(posts.get(position).post_content),
new Html.ImageGetter() {
#Override public Drawable getDrawable(String source) {
Log.d("Forum Service", "image source: " + source);
if (imageSources.contains(source)) {
for (int x = 0; x < imageSources.size(); x++) {
if (source.equals(imageSources.get(x))) {
String tmp = oImages.get(x);
tmp = tmp.substring(0, tmp.length() - 4);
tmp = tmp + "-t.jpg";
Drawable d = Drawable.createFromPath(tmp);
try {
d.setBounds(0, 0, d.getIntrinsicWidth(),
d.getIntrinsicHeight());
} catch (NullPointerException e) {
}
Log.d("Forum Service", "Loaded image froms sdcard");
return d;
}
}
} else if (notLoadedImages.contains(source)) {
Log.d("Forum Service", "Waiting for image");
return null;
} else {
notLoadedImages.add(source);
LoadAllIcons loader = new LoadAllIcons(context);
loader.LoadImages(source);
Log.d("Forum Service", "Asked for image");
return null;
}
return null;
}
}, null));
Thanks!
Finally the problem was that all Tasks loaded at the same time. Therefor 40 images where allocated in ram while downloading. I managed to limit the amount of running tasks by doing this modifications on AsyncTask:
private static final int CORE_POOL_SIZE = 2;
private static final int MAXIMUM_POOL_SIZE = 2;
private static final int KEEP_ALIVE = 1;
private static final BlockingQueue<Runnable> sWorkQueue =
new LinkedBlockingQueue<Runnable>(100);
Mateo there goes your answer http://android-developers.blogspot.com/2010/07/multithreading-for-performance.html
And you're done!
My app downloads .png files to the sd card for later use. I kept getting OutOfMemoryErrors (if anyone could explain this too, that'd be great!) and so I took a look at the sizes of the images saved to the sd card, and they seem to be roughly double what they are on the server. Why is this, and how can I make them smaller?
public void onCreate(Bundle saved) {
setContentView(R.layout.namedrxnscreen);
TextView t1 = (TextView)findViewById(R.id.rxn_text1);
TextView t2 = (TextView)findViewById(R.id.rxn_text2);
TextView t3 = (TextView)findViewById(R.id.rxn_text3);
TextView t4 = (TextView)findViewById(R.id.rxn_text4);
iv = (ImageView) findViewById(R.id.rxn_image);
pb = (ProgressBar) findViewById(R.id.rxn_loading);
vs = (ViewSwitcher) findViewById(R.id.rxn_switch);
try {
super.onCreate(saved);
[ boring stuff here ]
BitmapDrawable image = getImage(c.getString(5));
if (image != null) {
iv.setImageDrawable(getImage(c.getString(5)));
iv.setBackgroundColor(Color.WHITE);
vs.setDisplayedChild(1);
}
else {
new DownloadTask().execute(c.getString(5));
}
}
catch (ArrayIndexOutOfBoundsException ea) {
error = "bah!";
showDialog(1);
}
catch (Exception ex) {
error = ex.getMessage();
showDialog(1);
}
}
protected class DownloadTask extends AsyncTask<String, Integer, Bitmap> {
#Override
protected Bitmap doInBackground(String... string) {
Bitmap d = null;
try {
DefaultHttpClient dhc = new DefaultHttpClient();
HttpGet request = new HttpGet(HTTP_BASE + string[0] + ".png");
HttpResponse response = dhc.execute(request);
BufferedInputStream webstream = new BufferedInputStream(response.getEntity().getContent());
d = writeToSd(string[0], webstream, d);
}
catch (Exception ex) { errorCatch(ex.getMessage()); }
return d;
}
private Bitmap writeToSd(String string, BufferedInputStream webstream, Bitmap d) {
try {
webstream.mark(3);
webstream.reset();
File f = new File(Environment.getExternalStorageDirectory() + SD_DIR);
f.mkdirs();
File f2 = new File(f, string + ".png");
f2.createNewFile();
BufferedOutputStream fos = new BufferedOutputStream(new FileOutputStream(f2));
int len;
byte[] buffer = new byte[1024];
while ((len = webstream.read(buffer)) > 0) {
fos.write(buffer, 0, len);
}
webstream.close();
//fos.flush();
fos.close();
FileInputStream fis = new FileInputStream(new File(f, string + ".png"));
d = BitmapFactory.decodeStream(fis);
return d;
}
catch (Exception ex) {
errorCatch(ex.getMessage());
return null;
}
}
protected void onPostExecute(Bitmap result) {
if (result != null) {
iv.setImageBitmap(result);
iv.setBackgroundColor(Color.WHITE);
vs.setDisplayedChild(1);
}
}
}
protected BitmapDrawable getImage(String name) {
if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
try {
//Gets the SD card file, whacks it in a stream
File f = new File(Environment.getExternalStorageDirectory() + SD_DIR, name + ".png");
if (f.exists()) {
InputStream s = new FileInputStream(f);
try {
//Return the decoded bitmap
BitmapDrawable d = new BitmapDrawable(getResources(),
BitmapFactory.decodeStream(s)); //gives an OutOfMemoryError if png > ~30KB
return d;
} catch (OutOfMemoryError ex) {
Toast.makeText(this, "An OutOfMemoryError occured and" +
" the image was loaded at a lower quality.", Toast.LENGTH_SHORT).show();
BitmapFactory.Options mOptions = new BitmapFactory.Options();
mOptions.inSampleSize = 4;
BitmapDrawable d = new BitmapDrawable(getResources(),
BitmapFactory.decodeStream(s, null, mOptions));
return d;
}
}
else return null;
}
catch (Exception ex) {
return null;
}
}
else {
Toast.makeText(this, "External storage not available. Downloading from internet.",
Toast.LENGTH_SHORT).show();
return null;
}
}
The picture downloaded from the server is done byte per byte and cannot be double sized magically...