我正在按照Udemy的教程制作天气应用程序。这也是我第一次使用JSON数据,所以我不确定这是否会影响我的情况。然而,每次我运行我的应用程序,它都会打开;当我按下应该显示给定城市天气的按钮时,应用程序崩溃了。
我研究了Looper.准备(),因为它包含在错误中,但是添加looper不起作用(我是编码新手,我可能做得不正确)我还尝试添加runOnUiThread(new Runnable)无效(再次我可能做得不正确)。
public class MainActivity extends AppCompatActivity {
EditText editText;
TextView resultTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
editText = findViewById(R.id.editText);
resultTextView = findViewById(R.id.resultTextView);
}
public void getWeather(View view) {
try {
DownloadTask task = new DownloadTask();
String encodedCityName =
URLEncoder.encode(editText.getText().toString(), "UTF-8");
task.execute("http://openweathermap.org/data/2.5/weather?q="
+ encodedCityName + "&appid=b1b15e88fa797225412429c1c50c122a1");
InputMethodManager mgr = (InputMethodManager)
getSystemService(Context.INPUT_METHOD_SERVICE);
mgr.hideSoftInputFromWindow(editText.getWindowToken(), 0);
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), "Could not find
weather :(", Toast.LENGTH_SHORT).show();
}
}
public class DownloadTask extends AsyncTask<String, Void, String> {
@Override
protected String doInBackground(String... urls) {
String result = "";
URL url;
HttpURLConnection urlConnection = null;
try {
url = new URL(urls[0]);
urlConnection = (HttpURLConnection) url.openConnection();
InputStream in = urlConnection.getInputStream();
InputStreamReader reader = new InputStreamReader(in);
int data = reader.read();
while (data != -1) {
char current = (char) data;
result += current;
data = reader.read();
}
return result;
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(getApplicationContext(), "Could not find
weather :(", Toast.LENGTH_SHORT).show();
return null;
}
}
@Override
protected void onPostExecute(String s) {
super.onPostExecute(s);
Looper.prepare();
try {
JSONObject jsonObject = new JSONObject(s);
String weatherInfo = jsonObject.getString("weather");
Log.i("Weather content", weatherInfo);
JSONArray arr = new JSONArray(weatherInfo);
String message = "";
for (int i = 0; i < arr.length(); i++) {
JSONObject jsonPart = arr.getJSONObject(i);
String main = jsonPart.getString("main");
String description = jsonPart.getString("description");
if (!main.equals("") && !description.equals("")) {
message += main + ": " + description + "\r\n";
}
}
if (!message.equals("")) {
resultTextView.setText(message);
} else {
Toast.makeText(getApplicationContext(), "Could not
find weather :(", Toast.LENGTH_SHORT).show();
}
} catch (Exception e) {
Toast.makeText(getApplicationContext(), "Could not find
weather :(", Toast.LENGTH_SHORT).show();
e.printStackTrace();
}
}
}
}
以下是我的Logcat中出现的错误
2019-09-11 13:24:52.431
7574-7658/com.example.whatstheweather E/AndroidRuntime: FATAL EXCEPTION:
AsyncTask #1
Process: com.example.whatstheweather, PID: 7574
java.lang.RuntimeException: An error occurred while executing
doInBackground()
at android.os.AsyncTask$4.done(AsyncTask.java:399)
at
java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
at java.util.concurrent.FutureTask.run(FutureTask.java:271)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:289) atjava.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167) atjava.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
Caused by: java.lang.RuntimeException: Can't toast on a thread that has
not called Looper.prepare()
at android.widget.Toast$TN.<init>(Toast.java:407)
at android.widget.Toast.<init>(Toast.java:121)
at android.widget.Toast.makeText(Toast.java:286)
at android.widget.Toast.makeText(Toast.java:276)
atcom.example.whatstheweather.MainActivity$DownloadTask.
doInBackground(MainActivity.java:81)
atcom.example.whatstheweather.MainActivity$DownloadTask.
doInBackground(MainActivity.java:53)
at android.os.AsyncTask$3.call(AsyncTask.java:378)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:289)
atjava.util.concurrent.ThreadPoolExecutor.
runWorker(ThreadPoolExecutor.java:1167)
atjava.util.concurrent.ThreadPoolExecutor$Worker.
run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:919)
以下内容来自运行选项卡
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.example.whatstheweather, PID: 11228
java.lang.IllegalStateException: Could not execute method for
android:onClick
at
androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.
onClick(AppCompatViewInflater.java:390)
at android.view.View.performClick(View.java:7140)
at android.view.View.performClickInternal(View.java:7117)
at android.view.View.access$3500(View.java:801)
at android.view.View$PerformClick.run(View.java:27351)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.
run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: java.lang.reflect.InvocationTargetException
at java.lang.reflect.Method.invoke(Native Method)
at
androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.
onClick(AppCompatViewInflater.java:385)
at android.view.View.performClick(View.java:7140)
at android.view.View.performClickInternal(View.java:7117)
at android.view.View.access$3500(View.java:801)
at android.view.View$PerformClick.run(View.java:27351)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.
run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
Caused by: java.lang.RuntimeException: Only one Looper may be created
per thread
at android.os.Looper.prepare(Looper.java:108)
at android.os.Looper.prepare(Looper.java:103)
at
com.example.whatstheweather.MainActivity.getWeather(MainActivity.java:43)
at java.lang.reflect.Method.invoke(Native Method)
at
androidx.appcompat.app.AppCompatViewInflater$DeclaredOnClickListener.
onClick(AppCompatViewInflater.java:385)
at android.view.View.performClick(View.java:7140)
at android.view.View.performClickInternal(View.java:7117)
at android.view.View.access$3500(View.java:801)
at android.view.View$PerformClick.run(View.java:27351)
at android.os.Handler.handleCallback(Handler.java:883)
at android.os.Handler.dispatchMessage(Handler.java:100)
at android.os.Looper.loop(Looper.java:214)
at android.app.ActivityThread.main(ActivityThread.java:7356)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.
run(RuntimeInit.java:492)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)
您的Toast. makeText
方法应该在主线程上调用。你可以这样做:
runOnUiThread(new Runnable() {
public void run() {
Toast.makeText(getApplicationContext(), "Could not find weather :(", Toast.LENGTH_SHORT).show();
}
});
这个问题是因为你的toast是在doIn后台方法中创建和显示的。在android中,用户界面交互操作必须在UI线程中处理。onPostExecute方法在UI线程中调用,但doIn后台方法在另一个线程中调用。要解决您的问题,请从doIn后台方法中删除Toast,并将以下行放在onPostExecute方法中:
// If s equals to null an error ocurred in doInBackground
if (s == null) {
Toast.makeText(getApplicationContext(), "Could not find weather :(",
Toast.LENGTH_SHORT).show();
}
参见:https://developer.android.com/training/multiple-threads/communicate-ui