2014-01-28 104 views
0

我正在學習HTML和使用XML DOM解析數據。爲此,我創建了一個從雅虎的wheater API讀取Wheater的應用程序。AsyncTask中的Looper

當執行該應用程序時,在logcat中顯示錯誤:java.lang.RuntimeException:無法在沒有調用者Looper.prepare()的線程中創建處理程序。

我不知道這是什麼意思,或者代碼是否正確。

這是鏈接到雅虎的惠特API的XML文件:

http://weather.yahooapis.com/forecastrss?w=766273&u=c

這是我的代碼:

public class WeatherActivity extends Activity { 

private static final String WEATHER_URL = "http://weather.yahooapis.com/forecastjson?w="; 
private static final String MADRID_CODE = "766273"; 

private static final String LOCATION_NAME = "location"; 
private static final String CITY_NAME = "city"; 
private static final String CONDITION_NAME = "condition"; 
private static final String TEMPERATURE_NAME = "temperature"; 
private static final String FORECAST_NAME = "forecast"; 
private static final String DAY_NAME = "day"; 
private static final String HIGH_TEMPERATURE_NAME = "high_temperature"; 
private static final String LOW_TEMPERATURE_NAME = "low_temperature"; 

private static final String TODAY = "Today"; 
private static final String TOMORROW = "Tomorrow"; 

private Button mButton; 
private TextView mCity; 
private TextView mToday; 
private TextView mTomorrow; 


private class WeatherInfo { 
    String city; 
    int temperatureNow; 
    int lowTemperature; 
    int highTemperature; 
    int lowTemperatureTomorrow; 
    int highTemperatureTomorrow; 
} 

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

    mCity = (TextView) findViewById(R.id.city); 
    mToday = (TextView) findViewById(R.id.today); 
    mTomorrow = (TextView) findViewById(R.id.tomorrow); 

    mButton = (Button) findViewById(R.id.button); 
    mButton.setOnClickListener(new OnClickListener() { 

     public void onClick(View v) { 
      launch(); 
     } 
    }); 
} 

private void launch(){ 
    try { 
     new WeatherAsyncTask().execute(MADRID_CODE); 
    } catch (IllegalArgumentException e) { 
     e.printStackTrace(); 
     Toast.makeText(WeatherActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show(); 
    } 
} 


private class WeatherAsyncTask extends AsyncTask<String, Void, WeatherInfo>{ 

    @Override 
    protected WeatherInfo doInBackground(String... params) { 
     String code = params[0]; 
     if (TextUtils.isEmpty(code)) 
      throw new IllegalArgumentException("Code cannot be empty"); 

     URL url = null; 
     HttpURLConnection connection = null; 

     try { 
      url = new URL(WEATHER_URL + code); 
      connection = (HttpURLConnection) url.openConnection(); 
      connection.setRequestMethod("GET"); 

      InputStream is = connection.getInputStream(); 
      WeatherInfo info = readWeatherInfo(is); 
      return info; 

     } catch (IOException e) { 
      e.printStackTrace(); 
      Toast.makeText(WeatherActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show(); 
     } finally { 
      if (connection != null) 
       connection.disconnect(); 
     } 
     return null; 
    } 

    @Override 
    protected void onPostExecute(WeatherInfo result) { 
     super.onPostExecute(result); 
     showResult(result); 
    } 



    private WeatherInfo readWeatherInfo(InputStream is){ 
     if (is == null) 
      return null; 

     WeatherInfo info = new WeatherInfo(); 

     try { 

      DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); 
      DocumentBuilder builder = factory.newDocumentBuilder(); 
      Document dom = builder.parse(is); 
      Element root = dom.getDocumentElement(); 
      NodeList items = root.getElementsByTagName("item"); 

      for (int i=0; i<items.getLength(); i++) { 
       Node item = items.item(i); 
       NodeList datos = item.getChildNodes(); 

       for (int j=0; j<datos.getLength(); j++) { 
        Node dato = datos.item(j); 
        String etiqueta = dato.getNodeName(); 

        if (etiqueta.equals(LOCATION_NAME)) { 
         String texto = obtenerTexto(dato); 
         if (texto.equals(TEMPERATURE_NAME)) { 
          info.city = texto; 
         } 
        } 

        else if (etiqueta.equals(CONDITION_NAME)) { 
         String texto = obtenerTexto(dato); 
         if (texto.equals(CITY_NAME)) { 
          info.temperatureNow = Integer.parseInt(texto); 
         } 
        } 
        else if (etiqueta.equals(FORECAST_NAME)) { 
         String texto = obtenerTexto(dato); 
         String day = null; 
         int high = -111; 
         int low = -111; 

         if (texto.equals(DAY_NAME)){ 
          day = texto; 
         } else if (texto.equals(HIGH_TEMPERATURE_NAME)){ 
          high = Integer.parseInt(texto); 
         } else if (texto.equals(LOW_TEMPERATURE_NAME)){ 
          low = Integer.parseInt(texto); 
         } 

         if (day.equals(TODAY)){ 
          info.highTemperature = high; 
          info.lowTemperature = low; 
         } else if (day.equals(TOMORROW)){ 
          info.highTemperatureTomorrow = high; 
          info.lowTemperatureTomorrow = low; 
         } 
        } 
       } 
      } 
     } 
     catch (Exception ex) 
     { 
      throw new RuntimeException(ex); 
     } 

     return info; 
    } 


    private String obtenerTexto(Node dato) { 
     StringBuilder texto = new StringBuilder(); 
     NodeList fragmentos = dato.getChildNodes(); 

     for (int k=0;k<fragmentos.getLength();k++) { 
      texto.append(fragmentos.item(k).getNodeValue()); 
     } 
     return texto.toString(); 
    } 

} 

private void showResult(WeatherInfo info){ 
    mCity.setText("Temperature in " + info.city); 
    mToday.setText("Today: " + info.temperatureNow + " F (min: " + info.lowTemperature + " F/max: " + info.highTemperature + " F)."); 
    mTomorrow.setText("Tomorrow: min: " + info.lowTemperatureTomorrow + " F/max: " + info.highTemperatureTomorrow + " F."); 
} 


} 

回答

1

你不能在一個ASyncTaskdoInBackground顯示Toast

嘗試將其包裝在runOnUIThread()如:

runOnUiThread(new Runnable() { 
    @Override 
    public void run() { 
     Toast.makeText(WeatherActivity.this, e.getMessage(), Toast.LENGTH_SHORT).show(); 
    } 
}); 
+1

或者您可以使用'onProgressUpdate()''AsyncTask'預先實現的方法。有了這個,你可以將'e.getMessage()'傳遞給'publishProgress()' – Lonti84

0

您可以使用preimplemented方法AsyncTaskonProgressUpdate()它允許你發佈乾杯。要做到這一點,你必須改變你的AsyncTask聲明爲

private class WeatherAsyncTask extends AsyncTask<String, String, WeatherInfo>

相加法

@Override 
protected void onProgressUpdate(String... values) 
{ 
    super.onProgressUpdate(values); 
    Toast.makeText(WeatherActivity.this, values[0], Toast.LENGTH_SHORT).show(); 
} 

和裏面你AsyncTask你可以趕上你的異常,併爲此

catch (IOException e) 
{ 
    e.printStackTrace(); 
    publishProgress(e.getMessage()); 
} 

所有這些都可以在AsyncTask中默認使用,無需創建新的可運行參數。