尝试使微调器可见时,ViewRoot $ CalledFromWrongThreadException

时间:2011-10-17 08:38:51

标签: android multithreading parsing spinner

我正在从服务器解析plist并根据条件我有一个微调器来显示并从中选择值。

这是我实现

的代码
public class RaconTours extends Activity implements OnClickListener {

@Override
    public void onCreate(Bundle savedInstanceState) {

        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        btn = (ImageButton) findViewById(R.id.arrowBtn);
        btn.setOnClickListener(this);
        tourArray = new ArrayList<Tour>();
        btnProfile = (ImageButton) findViewById(R.id.profileBtn);
        spinner = (Spinner) findViewById(R.id.spinner);

        checkSDcardSupport();
        dialog = ProgressDialog.show(RaconTours.this, "", "Loading...",
                true, true);
        splashThread = new Thread() {
            @Override
            public void run() {
                try {
                    /**** Specify the path of the plist file ****/
                    File f = new File(RaconTours.PATH
                            + Constants.TOUR_MASTER_PLIST);
                    if (!f.exists()) {
                        f.createNewFile();
                    }
                    if (f.length() <= 0) {
                        URL plistUrl = new URL(Constants.TOUR_PLIST_URL);
                        TourDescription.httpDownload(f, plistUrl);
                    }
                } catch (MalformedURLException mue) {
                    mue.printStackTrace();
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                }
                /**** Call the method to parse the downloaded plist file ****/
                parsePlist();
                if(dialog!=null){
                    dialog.dismiss();
                }
            }
        };
        splashThread.start();



    }

现在在parsePlist方法中,

    public void parsePlist() {


            try {
                /**** Opens and reads the downloaded file ****/

                InputStream is = new BufferedInputStream(new FileInputStream(
                        RaconTours.PATH + Constants.TOUR_MASTER_PLIST));
                XMLPropertyListConfiguration plist = new XMLPropertyListConfiguration(
                        is);

                HashMap<String, Object> dict = plist.mPlistHashMap;
                // check if more than 1 city exists, if they exist display a spinner to select the city
                if (dict.size() > 2) {
                    try {
                    spinner.setVisibility(View.VISIBLE);
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                    //dict.remove("venueicons");
                    for (Object objSpinner: dict.keySet()) {
                        spin =  (String) objSpinner.toString();
                        // add the keys to the string array list
                        spinnerKeys.add(spin);
                    }
                    // set the array list as the data for the adapter
                    ArrayAdapter<String> spinnerData=new ArrayAdapter<String>(this,
                            android.R.layout.simple_spinner_item,
                            spinnerKeys);

                    spinnerData.setDropDownViewResource(
                            android.R.layout.simple_spinner_dropdown_item);
                        spinner.setAdapter(spinnerData);

                    spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
                        public void onItemSelected(AdapterView<?> parent,
                                View view, int pos, long id) {
                            Object item = parent.getItemAtPosition(pos);
                            city = item.toString();
                        }

                        public void onNothingSelected(AdapterView<?> parent) {
                            Toast.makeText(getApplicationContext(), "Please select a city", Toast.LENGTH_SHORT).show();
                        }
                    });

                }
                for (Object key : dict.keySet()) {

                    if (key.toString().equals("venueicons")) {
                        continue;
                    }
                    city = key.toString();

                    HashMap<String, Object> cityDict = (HashMap<String, Object>) dict
                            .get(city);
                    for (Object cityKey : cityDict.keySet()) {

                         tour = new Tour();
    .....
            }
    }
catch (FileNotFoundException fnfe) {
    fnfe.printStackTrace();
}

这里检查dict的大小大于2,即

if(dict.size()&gt; 2){ ...

}

基于此,我正在使微调器可见,但它正在给我

10-17 08:24:33.240: WARN/System.err(4538): android.view.ViewRoot$CalledFromWrongThreadException: Only the original thread that created a view hierarchy can touch its views.
10-17 08:24:33.250: WARN/System.err(4538):     at android.view.ViewRoot.checkThread(ViewRoot.java:2932)
10-17 08:24:33.250: WARN/System.err(4538):     at android.view.ViewRoot.focusableViewAvailable(ViewRoot.java:1712)
10-17 08:24:33.260: WARN/System.err(4538):     at android.view.ViewGroup.focusableViewAvailable(ViewGroup.java:452)
10-17 08:24:33.270: WARN/System.err(4538):     at android.view.ViewGroup.focusableViewAvailable(ViewGroup.java:452)
10-17 08:24:33.270: WARN/System.err(4538):     at android.view.ViewGroup.focusableViewAvailable(ViewGroup.java:452)
10-17 08:24:33.290: WARN/System.err(4538):     at android.view.View.setFlags(View.java:4633)
10-17 08:24:33.290: WARN/System.err(4538):     at android.view.View.setVisibility(View.java:3116)
10-17 08:24:33.290: WARN/System.err(4538):     at com.racontrs.Racontours.RaconTours.parsePlist(RaconTours.java:157)
10-17 08:24:33.300: WARN/System.err(4538):     at com.racontrs.Racontours.RaconTours$1.run(RaconTours.java:85)

为行

spinner.setVisibility(View.VISIBLE);

对此有何答案?

2 个答案:

答案 0 :(得分:0)

你的splashThread在它自己的线程(不是UI线程)上运行,这意味着对parseList的调用也将在非UI线程上运行,导致UI变为''非法'行动。

你应该研究AsyncTask - 它可能有更好的用途,因为它有在UI线程上运行的方法来进行UI更改。

<强>的AsyncTask-示例

将方法parsePList()替换为以下内容:

private class PListParser extends AsyncTask<Void, Void, Boolean> {
  public Boolean doInBackground( Void... params ) {
    //do the things your method parsePList does here.

    if( dict.size() > 2 )
      return true;
    else
      return false;
  }

  public void onPostExecute( Boolean result ) {
    //result is the return-value of the doInBackground-method
    if( result )
      spinner.setVisibility( View.VISIBLE );
    else
      spinner.setVisibility( View.GONE );
  }
}

然后,您可以执行以下操作,而不是致电parsePList()new PListParser().execute()

答案 1 :(得分:0)

您需要扩展AsyncTask或使用Handler回发到UI线程。一旦你在一个不同的线程中,你就无法进行直接改变UI的调用。