java - 在 Android Studio 中,我在“doInBackground 方法”中收到此错误
问题描述
这里首先执行 getWeather 方法,该方法执行 DownloadTask 方法,当用户传递一些空值并且 getWeather 中的链接不正确时,在 doInBackground 方法中获取输入流时显示致命错误。
package com.ssd.weatherapp;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.TextView;
import android.widget.Toast;
import org.json.JSONArray;
import org.json.JSONObject;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
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("https://openweathermap.org/data/2.5/weather?q=" + encodedCityName + "&appid=439d4b804bc8187953eb36d2a8c26a02\n");
InputMethodManager mgr = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
mgr.hideSoftInputFromWindow(editText.getWindowToken(), 0);
}catch(Exception e){
e.printStackTrace();
Log.i("info","1st one");
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();
System.out.println(urlConnection.getInputStream());
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);
try {
JSONObject jsonObject = new JSONObject(s);
String weatherInfo = jsonObject.getString("weather");
Log.i("info",weatherInfo);
JSONArray arr = new JSONArray(weatherInfo);
String msg ="";
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("")){
msg += main + ": " + description + "\r\n";
}
}
if(!msg.equals("")){
resultTextView.setText(msg);
}else{
Log.i("info","3rd one");
Toast.makeText(getApplicationContext(),"Could not find weather :(",Toast.LENGTH_SHORT).show();
}
}catch(Exception e){
e.printStackTrace();
Log.i("info","4th one");
Toast.makeText(getApplicationContext(),"Could not find weather :(",Toast.LENGTH_SHORT).show();
}
}
}
}
当我没有在 textView 中输入任何内容并将其发送到 downloadTask 类而不是显示异常并给出祝酒词时发生错误,应用程序崩溃并显示此错误:
2020-06-16 00:01:46.117 7948-7986/com.ssd.weatherapp D/NetworkSecurityConfig: No Network Security Config specified, using platform default
2020-06-16 00:01:47.529 7948-7986/com.ssd.weatherapp W/System.err: java.io.FileNotFoundException: https://openweathermap.org/data/2.5/weather?q=&appid=439d4b804bc8187953eb36d2a8c26a02
2020-06-16 00:01:47.529 7948-7986/com.ssd.weatherapp W/System.err: at com.android.okhttp.internal.huc.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:251)
2020-06-16 00:01:47.529 7948-7986/com.ssd.weatherapp W/System.err: at com.android.okhttp.internal.huc.DelegatingHttpsURLConnection.getInputStream(DelegatingHttpsURLConnection.java:210)
2020-06-16 00:01:47.529 7948-7986/com.ssd.weatherapp W/System.err: at com.android.okhttp.internal.huc.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:26)
2020-06-16 00:01:47.529 7948-7986/com.ssd.weatherapp W/System.err: at com.ssd.weatherapp.MainActivity$DownloadTask.doInBackground(MainActivity.java:74)
2020-06-16 00:01:47.529 7948-7986/com.ssd.weatherapp W/System.err: at com.ssd.weatherapp.MainActivity$DownloadTask.doInBackground(MainActivity.java:60)
2020-06-16 00:01:47.529 7948-7986/com.ssd.weatherapp W/System.err: at android.os.AsyncTask$2.call(AsyncTask.java:333)
2020-06-16 00:01:47.529 7948-7986/com.ssd.weatherapp W/System.err: at java.util.concurrent.FutureTask.run(FutureTask.java:266)
2020-06-16 00:01:47.529 7948-7986/com.ssd.weatherapp W/System.err: at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
2020-06-16 00:01:47.529 7948-7986/com.ssd.weatherapp W/System.err: at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
2020-06-16 00:01:47.529 7948-7986/com.ssd.weatherapp W/System.err: at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
2020-06-16 00:01:47.530 7948-7986/com.ssd.weatherapp W/System.err: at java.lang.Thread.run(Thread.java:764)
--------- beginning of crash
2020-06-16 00:01:47.532 7948-7986/com.ssd.weatherapp E/AndroidRuntime: FATAL EXCEPTION: AsyncTask #1
Process: com.ssd.weatherapp, PID: 7948
java.lang.RuntimeException: An error occurred while executing doInBackground()
at android.os.AsyncTask$3.done(AsyncTask.java:354)
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:245)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
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:393)
at android.widget.Toast.<init>(Toast.java:117)
at android.widget.Toast.makeText(Toast.java:280)
at android.widget.Toast.makeText(Toast.java:270)
at com.ssd.weatherapp.MainActivity$DownloadTask.doInBackground(MainActivity.java:94)
at com.ssd.weatherapp.MainActivity$DownloadTask.doInBackground(MainActivity.java:60)
at android.os.AsyncTask$2.call(AsyncTask.java:333)
at java.util.concurrent.FutureTask.run(FutureTask.java:266)
at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at java.lang.Thread.run(Thread.java:764)
2020-06-16 00:01:47.919 7948-7976/com.ssd.weatherapp D/EGL_emulation: eglMakeCurrent: 0xe7740080: ver 2 0 (tinfo 0xdfb95320)
(注意:当按钮单击它运行 getWeather 方法)但如果我在 textView 中给出正确的值,它工作正常。
解决方案
正如其他人已经指出的那样,您必须注意在主(UI)线程上运行的内容以及在后台线程上运行的内容。
AsyncTask
的doInBackground
在后台线程中运行,因此您无法在此处执行任何与 UI 相关的操作,例如显示Toast
或更新视图。
其他一些需要注意的事情是:
AsyncTask
现在已被弃用,最终将无法使用。- Java 中的内部类应该是静态的(除非有意)以避免泄漏它们的父类。在上面的代码中,如果 GC 在完成后仍在运行,
AsyncTask
则将阻止 GC 清除引用。Activity
Activity
- 与前一点类似,如果 Activity 在
AsyncTask
完成之前被销毁,应用程序将崩溃。因为当AsyncTask
完成并尝试更新 UI 时onPostExecute
,将没有要更新的视图(null)。
推荐阅读
- javascript - 对 .html 文件的获取请求不是由 express 处理的
- django - 如何在 django 中过滤对另一个结果的查询?
- winforms - 将 argb 转换为字符串
- finite-automata - 我需要创建一个有限自动机
- javascript - 如何检测请求的图像是否没有错误(403 Forbidden)
- angular8 - 当 ng --open serve 命令类型在 VS 上时出现 Angular 服务错误
- javascript - mocha.opts 已弃用,如何迁移到 package.json?
- rest - 从 Salesforce 获取文件的 base64 数据
- pine-script - TradingView 小部件使用 PineScript 将标签添加到一个点
- c# - Devexpress wpf CellEditor 绑定到类实例