Java android 天气应用程序 hangs/freezes 输入错误的城市名称时

Java android weather application hangs/freezes when entering wrong city name

我是 android 编程新手,这是我的第一个应用程序。我在 Samsung Galaxy S4 上使用 Eclipse IDE 和 运行 应用程序。当我输入存在的城市名称时,该应用程序运行良好。但是,当我输入不存在的城市名称时,它会冻结并滞后很多。此外,我无法单击任何按钮或无法编辑任何文本。我正在使用 api.openweathermap.org 获取 XML 格式的天气信息,然后解析它并将其显示在屏幕上。如果我尝试获取有关无法识别的城市的信息,我会得到这样的回复:{"message":"Error: Not found city","cod":"404"} 显然是 JSON 格式。我试图找到解决方案,但我不知道它是否正确以及我的应用程序挂起的原因。我试图将 API 的回复转换为字符串并检查它是否包含 "404" 。我post下面的源代码:

MainActivity.java :

package com.example.michal.myapplication;

import com.example.michal.myapplication.R;

import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Color;
import android.graphics.Typeface;
import android.support.v7.app.ActionBarActivity;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.provider.Settings;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.webkit.URLUtil;
import android.widget.Button;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity {
   EditText textEditMiasto,textEditKraj,textEditTemperatura,textEditWilgotnosc,textEditCisnienie;

   private String urlAdres = "http://api.openweathermap.org/data/2.5/weather?q=";
   private String urlTryb = "&mode=xml";
   private MyXMLParser obj;
   Button btnOK,btnClear;


   protected void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);
      btnOK=(Button)findViewById(R.id.button);
      btnClear=(Button)findViewById(R.id.buttonClr);

      textEditMiasto=(EditText)findViewById(R.id.editText);
      textEditKraj=(EditText)findViewById(R.id.editText2);
      textEditTemperatura=(EditText)findViewById(R.id.editText3);
      textEditWilgotnosc=(EditText)findViewById(R.id.editText4);
      textEditCisnienie=(EditText)findViewById(R.id.editText5);
      textEditMiasto.setTextColor(Color.WHITE);
      textEditKraj.setTextColor(Color.WHITE);
      textEditTemperatura.setTextColor(Color.WHITE);
      textEditWilgotnosc.setTextColor(Color.WHITE);
      textEditCisnienie.setTextColor(Color.WHITE);
      /*
      Intent addAccountIntent = new Intent(Settings.ACTION_ADD_ACCOUNT); 
      addAccountIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_DOCUMENT); 
      addAccountIntent.putExtra(Settings.EXTRA_AUTHORITIES, new String[]{"com.example.michal.myapplication"}); 
      startActivity(addAccountIntent);
      */

      btnOK.setOnClickListener(new View.OnClickListener() {
         @Override
         public void onClick(View v) {
            String url = textEditMiasto.getText().toString();
            String finalUrl = urlAdres + url + urlTryb;
            textEditKraj.setText(finalUrl);


            obj = new MyXMLParser(finalUrl);
            obj.fetchXML();

            while(obj.parsingComplete);
            textEditKraj.setText("Kraj : "+obj.getKraj());
            textEditTemperatura.setText("Temperatura : "+obj.getTemperatura()+" "+obj.getTemperaturaUnit());
            textEditWilgotnosc.setText("Wilgotnosc : "+obj.getWilgotnosc()+" "+obj.getWilgotnoscUnit());
            textEditCisnienie.setText("Cisnienie : "+obj.getCisnienie()+" "+obj.getCisnienieUnit());


         }
      });

      btnClear.setOnClickListener(new View.OnClickListener() {

        @Override
        public void onClick(View arg0) {
            textEditMiasto.setText("");
            textEditKraj.setText("");
            textEditTemperatura.setText("");
            textEditWilgotnosc.setText("");
            textEditCisnienie.setText("");

        }
    });
   }

   @Override
   public boolean onCreateOptionsMenu(Menu menu) {
      // Inflate the menu; this adds items to the action bar if it is present.
     // getMenuInflater().inflate(R.menu.menu_mai\, menu);
      return true;
   }

   @Override
   public boolean onOptionsItemSelected(MenuItem item) {
      // Handle action bar item clicks here. The action bar will
      // automatically handle clicks on the Home/Up button, so long
      // as you specify a parent activity in AndroidManifest.xml.

      int id = item.getItemId();

      //noinspection SimplifiableIfStatement
      if (id == R.id.action_settings) {
         return true;
      }
      return super.onOptionsItemSelected(item);
   }
}

MyXMLParser.java :

package com.example.michal.myapplication;

import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import org.xmlpull.v1.XmlPullParserFactory;

import android.webkit.URLUtil;
import android.widget.Toast;

import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
import java.io.StringBufferInputStream;
import java.io.StringReader;
import java.io.StringWriter;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.Buffer;

import org.apache.commons.io.IOUtils;

public class MyXMLParser {
   private String kraj = "county";
   private String temperatura = "temperature";
   private String wilgotnosc = "humidity";
   private String cisnienie = "pressure";
   private String temperaturaUnit=" ";
   private String wilgotnoscUnit=" ";
   private String cisnienieUnit="";
   private String urlString = " ";

   private XmlPullParserFactory xmlFactoryObject;
   public volatile boolean parsingComplete = true;
   boolean flaga=true;
   public void setKraj(String kraj) {
    this.kraj = kraj;
}

public void setTemperatura(String temperatura) {
    this.temperatura = temperatura;
}

public void setWilgotnosc(String wilgotnosc) {
    this.wilgotnosc = wilgotnosc;
}

public void setCisnienie(String cisnienie) {
    this.cisnienie = cisnienie;
}

public void setTemperaturaUnit(String temperaturaUnit) {
    this.temperaturaUnit = temperaturaUnit;
}

public void setWilgotnoscUnit(String wilgotnoscUnit) {
    this.wilgotnoscUnit = wilgotnoscUnit;
}

public void setCisnienieUnit(String cisnienieUnit) {
    this.cisnienieUnit = cisnienieUnit;
}

   public MyXMLParser(String url){
      this.urlString = url;
   }

   public String getKraj(){
      return kraj;
   }

   public String getTemperatura(){
      return temperatura;
   }

   public String getWilgotnosc(){
      return wilgotnosc;
   }

   public String getCisnienie(){
      return cisnienie;
   }

   public void parseXMLAndStoreIt(XmlPullParser myParser) {
      int event;
      String text=null;
      boolean flaga=true;


      try {
         event = myParser.getEventType();
         //if(text.equals("{\'message\':\'Error: Not found city\',\'cod\':\'404\'}")==true)
        //   return;



         while (event != XmlPullParser.END_DOCUMENT) {
             //if(event!=XmlPullParser.START_TAG||event!=XmlPullParser.TEXT||event!=XmlPullParser.END_TAG||event == XmlPullParser.END_DOCUMENT)
            //   break;
            String name=myParser.getName();

            switch (event){
               case XmlPullParser.START_TAG:
               break;

               case XmlPullParser.TEXT:
               text = myParser.getText();
               break;

               case XmlPullParser.END_TAG:
               if(name.equals("country")){
                  kraj = text;
               }

               else if(name.equals("humidity")){
                  wilgotnosc = myParser.getAttributeValue(null,"value");
                  wilgotnoscUnit=myParser.getAttributeValue(null,"unit");

               }

               else if(name.equals("pressure")){
                  cisnienie = myParser.getAttributeValue(null,"value");
                  cisnienieUnit=myParser.getAttributeValue(null,"unit");
               }

               else if(name.equals("temperature")){
                  temperatura = myParser.getAttributeValue(null,"value");
                  temperaturaUnit=myParser.getAttributeValue(null,"unit");
               }
               else{

               }
               break;

            }
                event = myParser.next();
         }

         parsingComplete = false;

      }

      catch (XmlPullParserException e) {
          e.printStackTrace();

      } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

   }

   public String getTemperaturaUnit() {
    return temperaturaUnit;
}

public String getWilgotnoscUnit() {
    return wilgotnoscUnit;
}

public String getCisnienieUnit() {
    return cisnienieUnit;
}

public void fetchXML(){
     Thread thread=new Thread(new Runnable() {

            @Override
            public void run() {
                try {
                       URL url = new URL(urlString);


                       HttpURLConnection conn = (HttpURLConnection)url.openConnection();

                       conn.setReadTimeout(10000 /* milliseconds */);
                       conn.setConnectTimeout(15000 /* milliseconds */);
                       conn.setRequestMethod("GET");
                       conn.setDoInput(true);
                       conn.connect();



                       InputStream stream = conn.getInputStream();
                       BufferedInputStream input=new BufferedInputStream(stream);
                       input.mark(100000);

                       StringWriter writer = new StringWriter();
                       IOUtils.copy(input, writer,"UTF-8");
                       String theString = writer.toString();

                       input.reset();
                       if(theString.contains("404")==false)
                       {
                           xmlFactoryObject = XmlPullParserFactory.newInstance();
                           XmlPullParser myparser = xmlFactoryObject.newPullParser();

                           myparser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, true);
                           myparser.setInput(input, null);
                           parseXMLAndStoreIt(myparser);
                       }

                       writer.close();
                       stream.close();
                       conn.disconnect();


                    }
                    catch (Exception e) {
                        e.printStackTrace();
                    }


            }
        });
     thread.start();
   }
}

AndroidManifest.xml :

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="com.example.michal.myapplication" 
   android:installLocation="preferExternal">
   <uses-permission android:name="android.permission.INTERNET"/>
   <application
      android:allowBackup="true"

      android:label="@string/app_name"
      android:theme="@style/AppTheme" >

      <activity
         android:name="com.example.michal.myapplication.MainActivity"
         android:label="@string/app_name" >

         <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
         </intent-filter>

      </activity>

   </application>
</manifest>

Logcat :

05-31 10:54:17.051: I/dalvikvm(8052): Could not find method android.content.res.TypedArray.getChangingConfigurations, referenced from method android.support.v7.internal.widget.TintTypedArray.getChangingConfigurations
05-31 10:54:17.051: W/dalvikvm(8052): VFY: unable to resolve virtual method 408: Landroid/content/res/TypedArray;.getChangingConfigurations ()I
05-31 10:54:17.051: D/dalvikvm(8052): VFY: replacing opcode 0x6e at 0x0002
05-31 10:54:17.051: I/dalvikvm(8052): Could not find method android.content.res.TypedArray.getType, referenced from method android.support.v7.internal.widget.TintTypedArray.getType
05-31 10:54:17.051: W/dalvikvm(8052): VFY: unable to resolve virtual method 430: Landroid/content/res/TypedArray;.getType (I)I
05-31 10:54:17.051: D/dalvikvm(8052): VFY: replacing opcode 0x6e at 0x0002
05-31 10:54:17.101: D/dalvikvm(8052): GC_FOR_ALLOC freed 154K, 44% free 14579K/25840K, paused 19ms, total 20ms
05-31 10:54:17.131: I/dalvikvm-heap(8052): Grow heap (frag case) to 34.536MB for 15892496-byte allocation
05-31 10:54:17.251: I/dalvikvm(8052): Could not find method android.content.res.Resources.getDrawable, referenced from method android.support.v7.internal.widget.ResourcesWrapper.getDrawable
05-31 10:54:17.251: W/dalvikvm(8052): VFY: unable to resolve virtual method 371: Landroid/content/res/Resources;.getDrawable (ILandroid/content/res/Resources$Theme;)Landroid/graphics/drawable/Drawable;
05-31 10:54:17.251: D/dalvikvm(8052): VFY: replacing opcode 0x6e at 0x0002
05-31 10:54:17.251: I/dalvikvm(8052): Could not find method android.content.res.Resources.getDrawableForDensity, referenced from method android.support.v7.internal.widget.ResourcesWrapper.getDrawableForDensity
05-31 10:54:17.251: W/dalvikvm(8052): VFY: unable to resolve virtual method 373: Landroid/content/res/Resources;.getDrawableForDensity (IILandroid/content/res/Resources$Theme;)Landroid/graphics/drawable/Drawable;
05-31 10:54:17.251: D/dalvikvm(8052): VFY: replacing opcode 0x6e at 0x0002

一段时间后我也收到:

05-31 10:55:57.008: I/dalvikvm(8052): threadid=3: reacting to signal 3
05-31 10:55:57.258: D/dalvikvm(8052): JIT unchain all for threadid=1
05-31 10:55:57.309: I/dalvikvm(8052): Wrote stack traces to '/data/anr/traces.txt'

在此先感谢您的帮助。

这是因为您处理线程的方式。你的:

 while(obj.parsingComplete);

... 显然锁定了主 UI 线程。不要那样做!使用 AsyncTask 在后台线程中进行解析并在后台任务完成时更新主线程中的 UI 而不是在主 UI 线程中等待并从后台线程中分离出来手动。