1

我想将 ListView 设置为从 Web 服务获取的数据。我在 AsyncTask 实例中获取数据,但是当我尝试设置一些 ListView 属性时,它崩溃了(在线“lv.setVisibility(View.VISIBLE);”)。有人可以帮忙吗?

谢谢

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
        }




    }
4

2 回答 2

1

在 Android 中,所有 UI 更新都在主线程(也称为 UI 线程)上完成。当您生成一个新线程来执行耗时的任务以免阻塞 UI 时,这很好。

但是为了避免各种不确定的行为,UI 更新总是必须在 UI 线程上完成。如果您尝试从不同的线程执行此操作,则会引发异常。

在您的示例中,我看到您正在ListView根据nResults. 您可以尝试返回nResults. doInBackground()它将被传递给onPostExecute(),它将在 UI 线程上执行。

您想查看这篇文章,了解有关 Android 线程的一些有用信息:http ://android-developers.blogspot.com/2009/05/painless-threading.html

高温高压

于 2010-07-04T18:11:14.577 回答
0

您无法从 doinbachground 方法访问 ui 线程。您需要从后执行、预执行或进度更新方法中执行此操作...

于 2010-07-04T17:19:06.060 回答