2013-03-26 36 views
-2

此代碼更新2個ListView,其中來自Web上的JSON數據和LazyAdapter將URL中的圖像轉換爲ListView,在2.3上正常工作,但在Android 4.0上無效。Android NetworkOnMainThreadException - 在4.0上的ListView JSON和LazyAdapter

這是代碼

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

}

謝謝你幫助我。

+4

爲什麼你要在onPostExecute()中創建runOnUiThread()。此方法已經在UI線程上運行。你應該閱讀[AsyncTask的參考](http://developer.android.com/reference/android/os/AsyncTask.html)。 – Sajmon 2013-03-26 20:47:47

+0

這個問題被問了很多次'NetworkOnMainThreadExceptoin'你應該在發佈問題之前先搜索這裏。 – 2013-03-26 20:59:37

+0

我正在搜索,但沒有找到我的問題的答覆。 – 2013-03-26 22:51:50

回答

0

當您嘗試從主UI線程進行網絡實時操作時,會發生NetworkOnMainThreadException。你應該在後臺線程上做同樣的事情,比如asynctask。

在你的getview中,你正在downlaoding一個位圖。

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有很好的解釋。

我建議你使用通用圖像加載器。

懶惰列表是延遲從SD卡或服務器使用URL加載圖像。這就像按需加載圖像。

圖像可以緩存到本地SD卡或手機mmeory。網址被認爲是關鍵。如果密鑰存在於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); 
} 
} 

懶列表的替代方案是通用圖像裝載機

https://github.com/nostra13/Android-Universal-Image-Loader。它基於Lazy List(基於相同原理)。但它有很多其他配置。我寧願使用通用圖像加載程序因爲它給你更多的配置選項。如果downlaod失敗,您可以顯示錯誤圖像。可以顯示圓角的圖像。可以緩存在光盤或內存上。可以壓縮圖像。

在您的自定義適配器構造

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

問題在於你的getView方法,它在UI線程上運行,但你已經調用了一些使用互聯網的東西。這裏的問題電話:

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

按照某個版本的Android(蜂窩據我記不清了),這是不允許的互聯網的使用可能需要一段時間,你不應該讓UI等候。完成。

這是一件很好的事情,你找到它,因爲它可能會導致ANRs的情況下,互聯網在設備上運行速度太慢,沒有任何崩潰。

解決此問題的一種方法是對每個視圖使用ViewHolder,它還將包含一個asyncTask用於加載圖像並在完成時將其設置爲相關的ImageView。如果viewHolder已經有一個任務,它應該被取消,因爲它屬於不再可見的東西。如果你願意,你也可以添加緩存機制。一般來說,如果您懷疑某個函數可能會運行很長時間(比如說,超過1秒),那麼您應該讓它在後臺運行(或者嘗試真正改善它),而不是讓UI線程處理它。原因是你會得到一個不流暢的應用程序,如果你的功能運行了大約5秒鐘左右,你也會得到一個ANR。

+0

是的,蜂窩:http://developer.android.com/reference/android/os/NetworkOnMainThreadException.html – kabuko 2013-03-26 20:52:59

0

不推薦,原因是顯而易見的,但你可以添加到您的類:

StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder().permitAll().build() 
StrictMode.setThreadPolicy(policy); 
相關問題