2012-01-05 1 views
0

これについて何十件もの記事を読んで、多くの解決策を試しましたが、何もできないようです。 JSONレスポンスから多数の(時には100以上の)行を含むリストビューを作成しています。各行には関連する(そして異なる)画像があります。Android - インターネットから画像の配列をダウンロードするときに非同期スレッドを設定するときに問題が発生する

パフォーマンステストでは、イメージをダウンロード/表示しなかったときに、JSON応答から134行が処理され、2秒未満で表示されました。驚くばかり!しかし、私がイメージのダウンロード/表示をオンにしたとき、約10年かかりました。

バックグラウンドスレッドを使用してイメージをダウンロードする必要がありますが、私がオンラインで見つけたすべての解決策は失敗しています(この時点で何らかのエラーが発生したと仮定します)。

私はバックグラウンドで画像を処理する必要があると思っていますが、設定方法については正確にはわかりません。

今のところ、画像は(他のすべてのデータとともに)配列にロードされます。各画像は今すぐインラインでダウンロードされるため、驚異的なパフォーマンスの悪夢です。ここで

が私の主な活動クラスからいくつかのコードの抜粋である...ここで

InputStream is = null; 
     //http post 
     try{ 
      postQuery = "my api path"; 
      HttpClient httpclient = new DefaultHttpClient(); 
      HttpPost httppost = new HttpPost(postQuery); 
      HttpResponse response = httpclient.execute(httppost); 
      HttpEntity entity = response.getEntity(); 
      is = entity.getContent(); 
     }catch(Exception e){ 
      Log.e("log_tag", "Error in http connection "+e.toString()); 
     } 

     //convert response to string 
     try{ 
      BufferedReader reader = new BufferedReader(new InputStreamReader(is,"iso-8859-1"),8); 
      StringBuilder sb = new StringBuilder(); 
      String line = null; 
      while ((line = reader.readLine()) != null) { 
        sb.append(line + "\n"); 
     } 
     is.close(); 
     result=sb.toString(); 
     }catch(Exception e){ 
     Log.e("log_tag", "Error converting result "+e.toString()); 
     } 

     m_bottles = new ArrayList<Bottles>(); 
     this.m_adapter = new BottleAdapter(this, R.layout.bottlelistimagelayout, m_bottles); 
       setListAdapter(this.m_adapter); 

     viewBottles = new Runnable(){ 
      public void run() { 
       getBottles(); 
      } 
     }; 
    Thread thread = new Thread(null, viewBottles, "MagentoBackground"); 
     thread.start(); 
     m_ProgressDialog = ProgressDialog.show(SpiritsBottles.this,  
       "Please wait...", "Retrieving data ...", true); 
public class Bottle{ 
     public String name_abbrArray; 
    } 
    private void getBottles(){ 
     try{ 
      JSONObject row = new JSONObject(result); 
      array = row.getJSONArray("bottles"); 
      m_bottles = new ArrayList<Bottles>(); 
      for(int i=0;i<array.length();i++){ 
       row = array.getJSONObject(i); 
       bottleID = row.getInt("id"); 
       name_abbr = row.getString("name_abbr"); 
       bottlePicture = row.getString("image"); 
       Bottles o = new Bottles(); 
       o.setbottleID(bottleID); 
       o.setname_abbr(name_abbr); 
       o.setbottlePicture(bottlePicture); 
       m_bottles.add(o); 
       Log.i("ARRAY", "" + m_bottles.size() + " - " + i + "/" + array.length()+"m_bottles size = "+m_bottles.size()); 
      } 
      } catch (Exception e) { 
      Log.e("PROC - bottleid = "+bottleNamesMap.get("bottlePicture2"), e.getMessage()); 
      } 
      runOnUiThread(returnRes); 
     } 

    private Runnable returnRes = new Runnable() { 

    public void run() { 
     if(m_bottles != null && m_bottles.size() > 0){ 
      m_adapter.notifyDataSetChanged(); 
      for(int i=0;i<m_bottles.size();i++) 
      m_adapter.add(m_bottles.get(i)); 
     } 
     m_ProgressDialog.dismiss(); 
     m_adapter.notifyDataSetChanged(); 
     } 
     }; 
private class BottleAdapter extends ArrayAdapter<Bottles> { 

     private ArrayList<Bottles> items; 

     public BottleAdapter(Context context, int textViewResourceId, ArrayList<Bottles> items) { 
       super(context, textViewResourceId, items); 
       this.items = items; 
     } 

     @Override 
     public View getView(int position, View convertView, ViewGroup parent) { 
       View v = convertView; 
       if (v == null) { 
        LayoutInflater vi = (LayoutInflater)getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
        v = vi.inflate(R.layout.bottlelistimagelayout, null); 
       } 
       Bottles o = items.get(position); 
       if (o != null) { 
         final TextView bottlenametv = (TextView) v.findViewById(R.id.bottlename); 
         final ImageView iv = (ImageView) v.findViewById(R.id.icon); 
         if (bottlenametv != null) { 
          bottlenametv.setText(o.getname_abbr()); 
          bottlenametv.setOnClickListener(new View.OnClickListener() { 
           public void onClick(View v) { 
            Intent intent = new Intent(getApplicationContext(), SingleBottleDisplay.class); 
            intent.putExtra("name", bottlenametv.getText()); 
            startActivityForResult(intent,0); 
           } 
          }); 
         } 
         if(iv != null){ 
          iv.setImageBitmap(o.getbottlePicture()); 
          iv.setOnClickListener(new View.OnClickListener() { 
           public void onClick(View v) { 
            Intent intent = new Intent(getApplicationContext(), SingleBottleDisplay.class); 
            intent.putExtra("name", bottlenametv.getText()); 
            startActivityForResult(intent,0); 
           } 
          }); 
         } 
       } 
       return v; 
     } 
    } 

は、私は現在、(私のパフォーマンスの問題である)、各行の画像をインラインでダウンロードしています私のボトルクラスです。

import java.io.FileInputStream; 
import java.io.FileNotFoundException; 
import java.io.IOException; 
import java.io.InputStream; 
import java.net.MalformedURLException; 
import java.net.URL; 

import android.graphics.Bitmap; 
import android.graphics.BitmapFactory; 
import android.util.Log; 

public class Bottles { 

    private int bottleID; 
    private String name_abbr; 
    private Bitmap bottlePicture; 

    public int getbottleID() { 
     return bottleID; 
    } 
    public void setbottleID(Integer bottleID) { 
     this.bottleID = bottleID; 
    } 
    public String getname_abbr() { 
     return name_abbr; 
    } 
    public void setname_abbr(String name_abbr) { 
     this.name_abbr = name_abbr; 
    } 
    public void setbottlePicture(String bottlePicture) throws MalformedURLException, IOException { 
     BitmapFactory.Options options = new BitmapFactory.Options(); 
     options.inSampleSize=6; 
     Bitmap bitmap = BitmapFactory.decodeStream((InputStream)new URL(bottlePicture).getContent(), null, options); 
     this.bottlePicture = bitmap; 
    } 
    public Bitmap getbottlePicture() { 
     return bottlePicture; 
    } 
} 

私は本当に、本当に私は私のロープの終わりに、ほとんどのコーヒーの外だとして、誰かがこれで私を助けることができます願っています... :)

答えて

1

情報ToddとElijahに感謝します。私がやったことは、nostra13 hereによって提供されたUniversalImageLoaderライブラリを使用していることです。上記の最初のスニペットの

コードの私の実装では、getViewメソッド(であった)と、このように見てしまった...

final ImageView iv = (ImageView) v.findViewById(R.id.icon); 

if(iv != null){ 
     //iv.setImageBitmap(o.getbottlePicture()); 
     ImageLoader imageLoader = ImageLoader.getInstance(); 
     imageLoader.init(ImageLoaderConfiguration.createDefault(getContext())); 
     imageLoader.displayImage(o.getbottlePicture(), iv); 
     iv.setOnClickListener(new View.OnClickListener() { 
      public void onClick(View v) { 
       Intent intent = new Intent(getApplicationContext(), SingleBottleDisplay.class); 
       intent.putExtra("name", bottlenametv.getText()); 
       startActivityForResult(intent,0); 
      } 
     }); 
} 

それは完璧に動作します!素晴らしい図書館のためのnostra13に多くの感謝!!

2

私はそれが可能だと思います2番目のスニペットのイメージをダウンロードしてスレッドに入れるのが最も良い方法です。

その内側にこのようなものになるだろう「プライベートビットマップdownloadImage(URL){...}」スレッドの詳細についてはhttp://developer.android.com/resources/articles/painless-threading.htmlを参照してください、しかし、基本的に次のようなメソッドを作成します。このコード

new Thread(new Runnable() { 
public void run() { 
    final Bitmap b = BitmapFactory.decodeStream((InputStream)new URL(url).getContent()); 
    mImageView.post(new Runnable() { 
    public void run() { 
     return b; 
    } 
    }); 
} 
}).start(); 

テストされていませんが、それはうまくいくはずです:)

1

これはイメージをロードする必要があるlistviewsの古典的な問題です。受け入れられたパターンはイメージを「遅延読み込み」することです。これは、本質的にgetView(アダプタ内)でイメージをロードするAsyncTaskを開始することを意味します。ビューが返され、UIスレッドが続行されるため、パフォーマンスの問題は発生しません。その後、AsyncTaskが完了し、以前に返されたビューにダウンロードしたイメージが追加されます。

グーグル "遅延ロードリストビュー"は、1トンの結果を返します。

これは、すべての画像が一度に読み込まれないため、リストが大きすぎるとメモリ不足の問題が発生する可能性があるため、より良い解決策です。

イメージのキャッシュを作成することで、パフォーマンスをさらに向上させることができ、イメージがキャッシュにある場合にイメージをリロードする必要はありません。これは過剰ですが、imagename => SoftReference(Bitmap)のHashMapでこの機能を提供することができます。キーがキャッシュに存在し、SoftReferenceが有効な場合は、そこにビットマップを使用します。それ以外の場合は、非同期タスクを使用してイメージをリロードして、キャッシュに保存します。)

最後に、このすべてに興味深いシワがあります。ご覧のように、getView()は時々ビューをリサイクルします。つまり、特定のリスト項目がディスプレイからスクロールしたときに再利用されることがあります(新しいビューを再作成するコストを避けるためです)。したがって、他の新しいオブジェクトに現在使用されているビューを参照する非同期タスクが実行されている可能性があります。レイジーロードパターンは一般的にビューにタグを設定し、非同期タスクが戻るときにそのタグが変更されていない場合は先に進んでビューにイメージを追加します。それ以外の場合は、画像が不要になることを意味します。

関連する問題