java.lang.RuntimeException:无法在尚未调用 Looper.prepare() 的线程上敬酒 [重复]

Posted

技术标签:

【中文标题】java.lang.RuntimeException:无法在尚未调用 Looper.prepare() 的线程上敬酒 [重复]【英文标题】:java.lang.RuntimeException: Can't toast on a thread that has not called Looper.prepare() [duplicate] 【发布时间】:2020-01-13 16:28:36 【问题描述】:

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

我研究了 Looper.prepare(),因为它包含在错误中,但是添加 looper 不起作用(我是编码新手,我可能做错了)我还尝试将 runOnUiThread(新 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)

【问题讨论】:

【参考方案1】:

问题是因为您的 toast 正在创建并显示在 doInBackground 方法中。在 android 用户界面操作必须在 UI 线程中处理。在 UI 线程中调用 onPostExecute 方法,但在另一个线程中调用方法 doInBackground。要解决您的问题,请从 doInBackground 方法中删除 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

【讨论】:

【参考方案2】:

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

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

【讨论】:

以上是关于java.lang.RuntimeException:无法在尚未调用 Looper.prepare() 的线程上敬酒 [重复]的主要内容,如果未能解决你的问题,请参考以下文章

Android Studio 按钮导致崩溃

添加 ImageView 时应用程序崩溃?