首页 > 解决方案 > java.lang.RuntimeException:不能在没有调用 Looper.prepare() 的线程上烤面包

问题描述

我正在按照 Udemy 的教程制作天气应用程序。这也是我第一次使用 JSON 数据,所以我不确定这是否会影响我的情况。但是,每次我运行我的应用程序时,它都会打开;当我按下应该显示给定城市天气的按钮时,应用程序崩溃了。

我研究了 Looper.prepare() ,因为它包含在错误中,但是添加 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)

标签: javascriptjavaandroidandroid-studiotoast

解决方案


您的Toast.makeText方法应该在主线程上调用。你可以这样做:

runOnUiThread(new Runnable() {
    public void run() {
        Toast.makeText(getApplicationContext(), "Could not find weather :(", Toast.LENGTH_SHORT).show();
    }
});

推荐阅读