Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/image/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Android-设置异步线程从internet下载图像阵列时遇到问题_Android_Image_Background - Fatal编程技术网

Android-设置异步线程从internet下载图像阵列时遇到问题

Android-设置异步线程从internet下载图像阵列时遇到问题,android,image,background,Android,Image,Background,我已经读了几十篇关于这方面的帖子,并尝试了同样多的解决方案,但我似乎什么都做不到。我通过JSON响应填充listview,该响应包含许多(有时超过100)行。每一行都有一个关联(和不同)的图像 在性能测试中,当我没有下载/显示图像时,JSON响应中的134行在不到2秒钟的时间内被处理和显示。令人惊叹的!然而,当我重新打开图像下载/显示时,花了大约10年的时间 很明显,我需要使用后台线程来下载图像,但我在网上找到的每个解决方案都不成功(假设我在这一点上出现了一些错误) 我想我有一个想法,我需要在哪

我已经读了几十篇关于这方面的帖子,并尝试了同样多的解决方案,但我似乎什么都做不到。我通过JSON响应填充listview,该响应包含许多(有时超过100)行。每一行都有一个关联(和不同)的图像

在性能测试中,当我没有下载/显示图像时,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;
        }
    }

我真的,真的希望有人能帮我解决这个问题,因为我已经筋疲力尽,几乎没有咖啡了……:)

我认为最好是将第二个片段中的图像下载放到一个线程中

有关线程的更多详细信息,请参见,但基本上您将创建一个类似“private Bitmap 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();

该代码未经测试,但应该可以工作:)

我认为最好是将第二个代码段中的图像下载放到一个线程中

有关线程的更多详细信息,请参见,但基本上您将创建一个类似“private Bitmap 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();

该代码未经测试,但应该可以工作:)

这是需要加载图像的ListView的经典问题。接受的模式是“延迟加载”映像,这本质上意味着在getView(在适配器中)中启动一个加载映像的异步任务。视图将返回,UI线程将继续,因此不会出现性能问题。稍后,AsyncTask完成,并将下载的映像添加到先前返回的视图中

谷歌搜索“lazy-load-listview”将返回大量结果

这也是一个更好的解决方案,因为不会同时加载所有图像,当列表太大时,可能会导致内存不足问题

通过对图像进行缓存,可以实现额外的性能提升,这样,如果图像在缓存中,就不需要重新加载图像。这可能有些过分,但imagename=>SoftReference(位图)的哈希映射可以提供此功能。如果缓存中存在密钥,并且SoftReference仍然有效,则使用那里的位图;否则,使用异步任务重新加载映像(并将其保存到缓存…)


最后,所有这些都有一个有趣的问题。如您所见,getView()有时会循环使用视图——也就是说,当某个特定列表项从显示中滚动出来时,它有时会被重用(以避免重新创建新视图的成本)。因此,可能正在运行一个异步任务,该任务引用了当前正在用于其他新对象的视图。延迟加载模式通常会在视图上设置标记,如果异步任务返回时该标记保持不变,则会继续并将图像添加到视图中。否则,意味着不再需要图像。

这是需要加载图像的列表视图的典型问题。接受的模式是“延迟加载”映像,这本质上意味着在getView(在适配器中)中启动一个加载映像的异步任务。视图将返回,UI线程将继续,因此不会出现性能问题。稍后,AsyncTask完成,并将下载的映像添加到先前返回的视图中

谷歌搜索“lazy-load-listview”将返回大量结果

这也是一个更好的解决方案,因为不会同时加载所有图像,当列表太大时,可能会导致内存不足问题

通过对图像进行缓存,可以实现额外的性能提升,这样,如果图像在缓存中,就不需要重新加载图像。这可能有些过分,但imagename=>SoftReference(位图)的哈希映射可以提供此功能。如果缓存中存在密钥,并且SoftReference仍然有效,则使用那里的位图;否则,使用异步任务重新加载映像(并将其保存到缓存…)


最后,所有这些都有一个有趣的问题。如您所见,getView()有时会循环使用视图——也就是说,当某个特定列表项从显示中滚动出来时,它有时会被重用(以避免重新创建新视图的成本)。因此,可能正在运行一个异步任务,该任务引用了当前正在用于其他新对象的视图。延迟加载模式通常会在视图上设置标记,如果异步任务返回时该标记保持不变,则会继续并将图像添加到视图中。否则,这意味着图像不再需要。

非常感谢Todd和Elijah提供的信息。我最终使用的是nostra13提供的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提供的奇妙图书馆

非常感谢托德和以利亚提供的信息。我最终使用的是nostra13提供的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);
            }
         });
}
它工作得很好!非常感谢诺斯特拉13