2012-01-05 46 views
0

我读过几十个帖子关于这个,并试图尽可能多的解决方案,下载图像的数组,但我似乎无法得到任何工作。我从JSON响应中填充listview,其中包括许多(有时超过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

我认为这将是如果你想将第二个片段中的图像下载到一个线程中,那么最好。

用于穿线详见http://developer.android.com/resources/articles/painless-threading.html,但基本上你会创建一个类似的方法“私人位图downloadImage(URL){...}”里面这将是这样的:

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

这是一个需要加载图像的列表视图的经典问题。接受的模式是“延迟加载”图像,这基本上意味着在getView中(在您的适配器中)启动一个加载图像的AsyncTask。视图返回并且UI线程继续,所以你没有性能问题。稍后,AsyncTask完成,并将下载的图像添加到之前返回的视图。

谷歌搜索“懒加载列表视图”将返回大量的结果。

这也是一个更好的解决方案,因为所有的图像都没有立即加载,从而导致了内存不足的问题时,您的列表变得过大。

额外的性能增益可以通过使图像的缓存,这样就不需要重新加载图像,如果它在高速缓存来实现。这可能是矫枉过正的,但imagename => SoftReference(位图)的HashMap可以提供此功能。如果密钥存在于缓存中,并且SoftReference仍然有效,请在那里使用Bitmap;否则使用异步任务重新加载图像(并将其保存到缓存中...)

最后 - 所有这一切都有一个有趣的皱纹。正如你所看到的,getView()有时会回收一个视图 - 也就是说,当一个特定的列表项滚动显示出来时,它有时会被重用(以避免重新创建新视图的代价)。因此,异步任务可能正在运行,它引用了当前正在用于某个其他新对象的视图。惰性加载模式通常在视图上设置标签,并且如果该标签在异步任务返回时保持不变,它将继续并将图像添加到视图中。否则,暗示是图像不再需要。