2011-02-07 1 views
8

私はアンドロイドアプリを開発しています。今私はhtmlにbbcodeを解析して、それをtextviewの中に表示しています。textviewはカスタムのlistviewの中にあります。 AsyncTaskからダウンロードしたイメージを表示するには、Html.ImageGetter()を使用します。複数のasynctaskを管理して、HTMLコードから複数のイメージをダウンロードし、RAMをリークさせますか?

これは、少ない枚数の写真に最適です。しかし、アプリが40〜50枚の写真をダウンロードするように求められれば、40〜50枚のタスクが作成され、混乱する。各タスクはストリームを開いて画像をダウンロードします。その後、バイトをビットマップにデコードし、サイズを変更し、sdcardに保存してビットマップをリサイクルします。

今、アプリが同時にこのすべての画像を読み込んでいる場合、膨大な量のRAMを使用します。私はそれが48メガバイトを通過させることができた。 。。私はこれを解決する方法で検索:(16と48の間には大きなギャップがあり、私はGoogleからのAsyncTaskコードダウンロード:

http://google.com/codesearch/p?hl=en&sa=N&cd=2&ct=rc#uX1GffpyOZk/core/java/android/os/AsyncTask.java&q=lang:java%20AsyncTask

をそして3にプールのサイズを設定するしかし、これは助けませんでした私はラムを失っている場所を見つけられません。大きな仕事の待ち行列を置くと、ラムは狂ってしまいます。イメージがいくつか受信されると、それは最悪になります。

キュー自体が大きなRAM割り当てをしているのですか、それともHtmlですか?また、画像が表示される前に30 MBに達することができます。 .ImageGetter()が大量に漏れるメモリの何とか?これを行うより良い方法はありますか?

ここで私はイメージのロード:

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(); 
} 

そして、ここで私はHtml.ImageGetter(コール)、これはリストの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)); 

ありがとう!

最後に、問題はすべてのタスクが同時にロードされたことでした。したがって、ダウンロード中にRAMに40個のイメージが割り当てられます。

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); 
+0

上記のコードでは、SDカードからの読み込み中にUIスレッドがロックされます(推奨されていません)。また、ListViewを表示する前にすべての画像が読み込まれるまで待たずに、ユーザーが画面をスクロールして行を再作成するまで、画像の準備ができてもListViewは更新されません。私の関連[質問](http://stackoverflow.com/q/11712130/403455)を参照してください。 –

答えて

9

マテオは、あなたの答えhttp://android-developers.blogspot.com/2010/07/multithreading-for-performance.html

そこに行くそして、あなたが行われている:私はAsyncTaskでこの変更を行うことにより、実行中のタスクの量を制限するために管理しました!

+0

ありがとう!!私は最後の日を見ている。私は、テキストビューのHTMLコードにロードされた画像に弱い参照を使用する方法を理解しようとしています。私のリークがある場合や、入力ストリームに何らかのオーバーフローがあり、これがラムを占有している場合にも発生します。私はそれを把握するとすぐ答えとしてあなたの答えをマークします:) – Mateo

+0

おかげさまで、それはダウンロード中にビットマップを解読するためにflushedinputstreamを使用するRAMが少ないので、助けてくれました。バイトをダウンロードしてビットマップにデコードするのではなく、ついに私の主な問題は、すべてのタスクが同時にダウンロードされ始めたことに気づいたのですが。タスク数を2ダウンロードに制限し、他のすべてのキューをキューに入れました。スレッドを更新して、AsyncTaskの変更をこのようにするようにします。 – Mateo

関連する問題