La gestion de plusieurs asynctask pour télécharger plusieurs images à partir de code html, de fuite de ram, des idées?

Je voudrais développer une application android. Maintenant, je suis d'analyse bbcode en html et de les afficher à l'intérieur d'un textview, le textview est à l'intérieur d'une coutume listview. Je utiliser de l'Html.ImageGetter() pour afficher les images téléchargées à partir AsyncTask.

Il fonctionne très bien pour un faible nombre de photos. Mais si l'application est invité à télécharger 40-50 photos, de 40 à 50 tâches sont créées et il devient un gâchis. Chaque tâche ouvre un flux de télécharger les images. Après cela, il décode les octets dans les bitmaps, les redimensionner, de les enregistrer sur la carte sd et recycle les images.

Maintenant, si le chargement de l'application de toutes ces images dans le même temps, il utilise une énorme quantité de ram. J'ai réussi à le faire passer de 48 mo. Il y a un grand écart entre 16 et 48 :(. J'ai cherché sur la façon de résoudre ce problème. J'ai téléchargé AsyncTask code de 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

Et de définir la taille du pool de 3. Mais cela n'a pas aidé. Je ne peux vraiment pas comprendre où je veux en perdre la mémoire ram. Dès que j'ai mis une grosse tâche de la file d'attente de ma ram est en délire. Après quelques images sont reçues il devient pire. Je ne pense pas que c'est l'image car je peux obtenir à 30 mo avant tout l'image est affichée. L'application elle-même, y compris la vue, de l'information et de son service utilise 13 mo, tout le reste est divulgué ici.

Ne la file d'attente pour faire de grandes ram allocations? Ou est le Html.ImageGetter() la fuite d'un énorme quantité de mémoire en quelque sorte? Est-il une meilleure façon de le faire?

Ici, je charge les 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();
}

Et ici je call Html.ImageGetter(), c'est à l'intérieur d'une liste de 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));

Merci!

Enfin le problème est que toutes les Tâches chargé en même temps. À cet effet 40 images où alloué dans la mémoire vive pendant le téléchargement. J'ai réussi à limiter la quantité de tâches en cours d'exécution en faisant cela, les modifications sur les 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);
Pour info, le code ci-dessus encore bloque le thread d'INTERFACE utilisateur lors du chargement de la carte SD (non recommandé comportement). En outre, il semble comme si vous n'attendez pas jusqu'à ce que toutes les images sont chargées avant l'affichage de la liste, la liste ne sera pas mis à jour, même après les images sont prêtes jusqu'à ce que l'utilisateur fait défiler à l'écran et les lignes sont recréés. Voir mes question.

OriginalL'auteur Mateo | 2011-02-07