Android NetworkOnMainThreadException - 4.0上的ListView JSON和LazyAdapter

时间:2013-03-26 20:45:20

标签: android json eclipse android-3.0-honeycomb

此代码使用来自JSON的Web上的数据更新2 ListView,并且LazyAdapter将图像从URL转换并放在ListView上,在2.3上工作正常但在Android 4.0上不起作用。

这是代码

EventosActivity.java

    @Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.eventos);

    hojeLista = new ArrayList<HashMap<String, String>>();
    proximosLista = new ArrayList<HashMap<String, String>>();


    new LoadEventos().execute();

}

/**
 * Background Async Task to Load all product by making HTTP Request
 * */
class LoadEventos extends AsyncTask<String, String, String> {

    /**
     * Before starting background thread Show Progress Dialog
     * */
    @Override
    protected void onPreExecute() {
        super.onPreExecute();
        pDialog = new ProgressDialog(EventosActivity.this);
        pDialog.setMessage("Dando uma olhada aqui, peraê...");
        pDialog.setIndeterminate(false);
        pDialog.setCancelable(false);
        pDialog.show();
    }

    /**
     * getting All evento from url
     * */
    protected String doInBackground(String... args) {
        // Building Parameters
        List<NameValuePair> params = new ArrayList<NameValuePair>();
        // getting JSON string from URL
        JSONObject json = jParser.makeHttpRequest(url_hoje, "GET", params);
        JSONObject json2 = jParser.makeHttpRequest(url_proximos, "GET", params);

        try {
            // Checking for SUCCESS TAG
            int success = json.getInt(TAG_SUCCESS);
            int success2 = json2.getInt(TAG_SUCCESS);

            if (success == 1) {
                // evento found
                // Getting Array of Products
                evento = json.getJSONArray(TAG_EVENTO);

                // looping through All Products
                for (int i = 0; i < evento.length(); i++) {
                    JSONObject c = evento.getJSONObject(i);


                    // Storing each json item in variable
                    String id = c.getString(TAG_ID);
                    String titulo = c.getString(TAG_TITULO);
                    String local_nome = c.getString(TAG_LOCAL_NOME);
                    String data = c.getString(TAG_DATA);
                    String imagem = c.getString(TAG_IMAGEM);

                    //if ("16".equals(TAG_CLASSIFICACAO)) { }


                    // creating new HashMap
                    HashMap<String, String> map = new HashMap<String, String>();


                    // adding each child node to HashMap key => value
                    map.put(TAG_ID, id);
                    map.put(TAG_TITULO, titulo);
                    map.put(TAG_LOCAL_NOME, local_nome);
                    map.put(TAG_DATA, data);
                    map.put(TAG_IMAGEM, imagem);

                    // adding HashList to ArrayList
                    hojeLista.add(map);

                }
            }

            if (success2 == 1) {
                // evento found
                // Getting Array of Products
                evento = json2.getJSONArray(TAG_EVENTO);

                // looping through All Products
                for (int i = 0; i < evento.length(); i++) {
                    JSONObject c2 = evento.getJSONObject(i);


                    // Storing each json item in variable
                    String id = c2.getString(TAG_ID);
                    String titulo = c2.getString(TAG_TITULO);
                    String local_nome = c2.getString(TAG_LOCAL_NOME);
                    String data = c2.getString(TAG_DATA);
                    String imagem = c2.getString(TAG_IMAGEM);

                    //if ("16".equals(TAG_CLASSIFICACAO)) { }


                    // creating new HashMap
                    HashMap<String, String> map2 = new HashMap<String, String>();


                    // adding each child node to HashMap key => value
                    map2.put(TAG_ID, id);
                    map2.put(TAG_TITULO, titulo);
                    map2.put(TAG_LOCAL_NOME, local_nome);
                    map2.put(TAG_DATA, data);
                    map2.put(TAG_IMAGEM, imagem);

                    // adding HashList to ArrayList
                    proximosLista.add(map2);

                }
            }

        } catch (JSONException e) {
            e.printStackTrace();
        }


        return null;
    }



    /**
     * After completing background task Dismiss the progress dialog
     * **/
    protected void onPostExecute(String file_url) {
        // dismiss the dialog after getting all evento

        pDialog.dismiss();  

        // updating UI from Background Thread
        runOnUiThread(new Runnable() {
            public void run() {

                ListView list = (ListView)findViewById(android.R.id.list);
                ListView list2 = (ListView)findViewById(R.id.lvProximos);
           ks.     
                LazyAdapter adapter=new LazyAdapter(EventosActivity.this, hojeLista);
                list.setAdapter(adapter);

                LazyAdapter adapter2=new LazyAdapter(EventosActivity.this, proximosLista);
                list2.setAdapter(adapter2);



                list.setOnItemClickListener(new OnItemClickListener() {

                    @Override
                    public void onItemClick(AdapterView<?> parent, View view,
                            int position, long id) {
                        String id2 = ((TextView) view.findViewById(R.id.id)).getText().toString();

                        Intent in = new Intent(getApplicationContext(), EventoDetalheActivity.class);

                        in.putExtra(TAG_ID, id2);

                        startActivityForResult(in, 100);
                    }
                });

                list2.setOnItemClickListener(new OnItemClickListener() {

                    @Override
                    public void onItemClick(AdapterView<?> parent, View view,
                            int position, long id) {
                        String id2 = ((TextView) view.findViewById(R.id.id)).getText().toString();

                        Intent in = new Intent(getApplicationContext(), EventoDetalheActivity.class);

                        in.putExtra(TAG_ID, id2);

                        startActivityForResult(in, 100);
                    }
                });
            }
        });

    }

}}

LazyAdapter.java

public class LazyAdapter extends BaseAdapter {
private Context activity;
private ArrayList<HashMap<String, String>> data;
private LayoutInflater inflater=null;
//public ImageLoader imageLoader; 
private URL url;
private Bitmap bmp;
public LazyAdapter(Context a, ArrayList<HashMap<String, String>> d) {
    activity = a;
    data=d;
    inflater = (LayoutInflater)activity.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
    //imageLoader=new ImageLoader(activity.getApplicationContext());
}

public int getCount() {
    return data.size();
}

public Object getItem(int position) {
    return position;
}

public long getItemId(int position) {
    return position;
}

public View getView(int position, View convertView, ViewGroup parent) {
    View vi=convertView;
    if(convertView==null)
        vi = inflater.inflate(R.layout.eventoitem, null);
    TextView id = (TextView)vi.findViewById(R.id.id); 
    TextView titulo = (TextView)vi.findViewById(R.id.titulo); 
    TextView local_nome = (TextView)vi.findViewById(R.id.local_nome);
    TextView data0 = (TextView)vi.findViewById(R.id.data);
    ImageView im=(ImageView)vi.findViewById(R.id.imgImagem);

    HashMap<String, String> evento = new HashMap<String, String>();
    evento = data.get(position);

    // Setting all values in listview
    id.setText(evento.get("id"));
    titulo.setText(evento.get("titulo"));
    local_nome.setText(evento.get("local_nome"));
    data0.setText(evento.get("data"));

    try {
        url = new URL(evento.get("imagem"));
         bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
           im.setImageBitmap(bmp);
    } catch (MalformedURLException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }


    return vi;
}

}

谢谢你的帮助。

3 个答案:

答案 0 :(得分:2)

问题在于你的getView方法,它在UI线程上运行但你已经调用了一些使用互联网的东西。这是有问题的电话:

bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
       im.setImageBitmap(bmp);

从特定版本的android(我记得蜂窝)开始,这是不允许的,因为互联网使用可能需要一段时间,你不应该让UI等待它完成。

你发现它是一件好事,因为它可能会导致ANR,因为互联网在没有任何崩溃的情况下工作得太慢。

解决这个问题的一种方法是对每个视图使用ViewHolder,它还包括一个asyncTask,用于加载图像并在完成后将其设置为相关的ImageView。如果viewHolder已经有一个任务,它应该被取消,因为它属于不再可见的东西。如果需要,还可以添加缓存机制。

一般情况下,如果您怀疑某个函数可以运行很长时间(比如超过1秒),您应该让它在后台运行(或尝试真正改进它)而不是让UI线程处理它。原因是你将得到一个非流动的应用程序,如果你的功能运行大约5秒左右,你也会得到一个ANR。

答案 1 :(得分:0)

当您尝试从主UI线程进行网络实现操作时,会发生NetworkOnMainThreadException。你应该在像asynctask这样的后台线程上做同样的事情。

在你的getview中,你正在下载一个位图。

bmp = BitmapFactory.decodeStream(url.openConnection().getInputStream());
   im.setImageBitmap(bmp);

我同意android开发者。

您还应该使用viewholder来查看listview。 http://developer.android.com/training/improving-layouts/smooth-scrolling.html

http://www.youtube.com/watch?v=wDBM6wVEO70。该视频对Viewholder和listview有很好的解释。

我建议你使用 Universal Image Loader。

Lazy List是使用url从sdcard或fomr服务器延迟加载图像。这就像点播加载图片一样。

图像可以缓存到本地SD卡或手机存储卡中。网址被认为是关键。如果密钥存在于sdcard显示图像来自SD卡,则通过从服务器下载显示图像并将其缓存到您选择的位置。可以设置缓存限制。您还可以选择自己的位置来缓存图像。缓存也可以被清除。

而不是用户等待下载大图像,然后显示延迟列表按需加载图像。由于缓存了图像区域,您可以离线显示图像。

https://github.com/thest1/LazyList。懒惰列表

在你的getview中

imageLoader.DisplayImage(imageurl, imageview);
ImageLoader Display method

public void DisplayImage(String url, ImageView imageView) //url and imageview as parameters
{
imageViews.put(imageView, url);
Bitmap bitmap=memoryCache.get(url);   //get image from cache using url as key
if(bitmap!=null)         //if image exists
    imageView.setImageBitmap(bitmap);  //dispaly iamge
 else   //downlaod image and dispaly. add to cache.
 {
    queuePhoto(url, imageView);
    imageView.setImageResource(stub_id);
 }
 }

Lazy List的替代方案是Universal Image Loader

https://github.com/nostra13/Android-Universal-Image-Loader。它基于Lazy List(基于相同的原理)。但它有很多其他配置。我更喜欢使用通用图像加载器因为它为您提供了更多配置选项。如果下载失败,您可以显示错误图像。可以显示带圆角的图像。可以缓存在光盘或内存上。可压缩图像。

在自定义适配器构造函数

 File cacheDir = StorageUtils.getOwnCacheDirectory(context, "your folder");

 // Get singletone instance of ImageLoader
 imageLoader = ImageLoader.getInstance();
 // Create configuration for ImageLoader (all options are optional)
 ImageLoaderConfiguration config = new ImageLoaderConfiguration.Builder(a)
      // You can pass your own memory cache implementation
     .discCache(new UnlimitedDiscCache(cacheDir)) // You can pass your own disc cache implementation
     .discCacheFileNameGenerator(new HashCodeFileNameGenerator())
     .enableLogging()
     .build();
 // Initialize ImageLoader with created configuration. Do it once.
 imageLoader.init(config);
 options = new DisplayImageOptions.Builder()
 .showStubImage(R.drawable.stub_id)//display stub image
 .cacheInMemory()
 .cacheOnDisc()
 .displayer(new RoundedBitmapDisplayer(20))
 .build();

在你的getView()

 ImageView image=(ImageView)vi.findViewById(R.id.imageview); 
 imageLoader.displayImage(imageurl, image,options);//provide imageurl, imageview and options

答案 2 :(得分:0)

出于显而易见的原因,不建议这样做,但您可以将其添加到您的班级中:

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build() 
StrictMode.setThreadPolicy(policy);