2010-07-04 50 views
1

我想將ListView設置爲從Web服務獲取的數據。我在AsyncTask實例中獲取數據,但是當我嘗試設置一些ListView屬性時,它崩潰了(在「lv.setVisibility(View.VISIBLE)」上)。任何人都可以幫忙?在AsyncTask類中設置ListView時的問題

感謝

public class Atable extends Activity { 

    private EditText mSearch; 
    private static final int ACTIVITY_EDIT=0; 
    private Button mSearchButton; 
    private TextView mNoresults; 
    private ListView lv; 
    private CheckBox checkBox; 
    private LocationManager locationManager; 
    private RestaurantList restaurantList; 
    private Criteria criteria; 

    public void onCreate(Bundle savedInstanceState) { 

     super.onCreate(savedInstanceState); 

     setContentView(R.layout.main); 

     lv= (ListView)findViewById(R.id.listview); 

     mNoresults = (TextView) findViewById(R.id.noresults); 
     mNoresults.setVisibility(View.GONE); 

     mSearchButton = (Button)this.findViewById(R.id.button); 
     checkBox = (CheckBox) findViewById(R.id.local_check);   

     locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE); 
     criteria = new Criteria(); 
     criteria.setAccuracy(Criteria.ACCURACY_FINE); 

     mSearchButton.setOnClickListener(new OnClickListener() { 
      @Override 
      public void onClick(View v) { 
       mNoresults.setVisibility(View.GONE); 
       mSearch = (EditText) findViewById(R.id.search); 
       String tmp_str = mSearch.getText().toString().replace(" ","+"); 
       String url = "http://www.atable.org/getRestaurantByQuery/?query=" + tmp_str; 

       if (checkBox.isChecked()) { 

        //get location 
        String provider = locationManager.getBestProvider(criteria, true);     
        Location location = locationManager.getLastKnownLocation(provider); 

        if (location!=null) { 

         String lat = String.valueOf(location.getLatitude()); 
         String lng = String.valueOf(location.getLongitude()); 

         url += "&lat="+lat+"&lng="+lng;     
        } 
       } 
       new GetRestaurantData().execute(url);    
      } 
     }); 

    }; 

    private class GetRestaurantData extends AsyncTask<String, Boolean, RestaurantList> { 

     private HttpClient httpclient = new DefaultHttpClient(); 

     @Override 
     protected RestaurantList doInBackground(String... url) {    

      publishProgress(true);   

      HttpGet httpget = new HttpGet(url[0]);   

      // Execute the request 
      HttpResponse response; 
      try { 
       response = httpclient.execute(httpget); 
       HttpEntity entity = response.getEntity(); 

       if (entity != null) { 

        InputStream instream = entity.getContent(); 

        Reader r = new InputStreamReader(instream);      

        Gson gson = new Gson(); 
        restaurantList = gson.fromJson(r, RestaurantList.class); 

        int nResults = restaurantList.getSize(); 

        if (nResults>0) {      

         lv.setVisibility(View.VISIBLE); //app crashes here      

         lv.setAdapter(new ArrayAdapter<String>(Atable.this ,android.R.layout.simple_list_item_1,restaurantList.getRestaurantNames())); 

         lv.setOnItemClickListener(new OnItemClickListener() { 

          public void onItemClick(AdapterView<?> parent, View view, int position, long id) { 

           Intent intent = new Intent(Atable.this, RestaurantDescription.class); 
           Restaurant tmp_resto = restaurantList.getRestaurant((int)id); 

           String tmp_categories = tmp_resto.getCategories().get(0); 
           for (int i=1; i<tmp_resto.getCategories().size(); i++) { 
            tmp_categories+=", "+tmp_resto.getCategories().get(i); 
           } 

           String address = tmp_resto.getStreet()+", "+tmp_resto.getStreetNumber()+"\n"+tmp_resto.getCity()+ 
               " "+tmp_resto.getPostalCode()+"\n"+tmp_resto.getCountry(); 

           intent.putExtra("name", tmp_resto.getName()); 
           intent.putExtra("address", address);         
           intent.putExtra("rating", tmp_resto.getRating()); 
           intent.putExtra("price_range", tmp_resto.getPriceRange()); 
           intent.putExtra("categories", tmp_categories); 
           intent.putExtra("latitude", tmp_resto.getLatitude()); 
           intent.putExtra("longitude", tmp_resto.getLongitude()); 
           startActivityForResult(intent, ACTIVITY_EDIT); 
          } 
         }); 


        } 

        else { 
         lv.setVisibility(View.GONE); 
         mNoresults.setVisibility(View.VISIBLE); 
        } 

        //Closing the input stream will trigger connection release 
        instream.close(); 
       } 


      } catch (ClientProtocolException e) {     
       e.printStackTrace(); 
      } catch (IOException e) {     
       e.printStackTrace(); 
      } 

      return restaurantList; 
     } 

     @Override 
     protected void onProgressUpdate(Boolean... progress) { 
      // line below coupled with 
      // getWindow().requestFeature(Window.FEATURE_INDETERMINATE_PROGRESS) 
      // before setContentView 
      // will show the wait animation on the top-right corner 
      Atable.this.setProgressBarIndeterminateVisibility(progress[0]); 
     } 

     @Override 
     protected void onPostExecute(RestaurantList result) { 
      publishProgress(false); 
      // Do something with result in your activity 
     } 




    } 

回答

1

在Android中,所有UI更新都是在主線程(也稱爲UI線程)上完成的。當您產生新線程來執行耗時的任務以避免阻止用戶界面時,這很好。

但爲了避免各種不確定的行爲,UI更新總是必須在UI線程上完成。如果您嘗試從其他線程嘗試這樣做,則會引發異常。

在您的示例中,我看到您正在根據nResults的值執行與ListView不同的更新。您可以嘗試爲doInBackground()返回nResults。它將被傳遞給onPostExecute(),它將在UI線程上執行。

你想看看這篇文章,在Android中約絲扣一些有用的信息:http://android-developers.blogspot.com/2009/05/painless-threading.html

HTH

0

不能從doinbachground方法訪問UI線程..你需要做的是從執行後,執行前或進度更新方法...