【问题标题】:Yet another "Can't create handler inside thread that has not called Looper.prepare()" topic另一个“无法在未调用 Looper.prepare() 的线程内创建处理程序”主题
【发布时间】:2015-02-03 18:39:21
【问题描述】:

我有这个代码,它是一个 Activity,当它启动时会检查互联网连接,如果有连接,那么生活就会继续。否则会出现一个对话框以打开连接。但是我创建了一个线程,每 10 秒检查一次连接,如果连接丢失,它将再次显示对话框。

package greensmartcampus.eu.smartcampususerfeedbackapp;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.os.Bundle;
import android.provider.Settings;
import android.view.Menu;
import android.view.MenuItem;
import android.widget.Toast;

import java.net.InetAddress;


public class HomeScreen extends AbstractPortraitActivity {

    private static final int WIFI_REQUEST_CODE = 1;
    private boolean networkSettingsDialogOpened = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_home_screen);
        this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                while (!HomeScreen.this.isInternetAvailable()) {
                    if (!networkSettingsDialogOpened)
                        HomeScreen.this.createNetErrorDialog();
                    try {
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }

(...)

    private boolean isInternetAvailable() {
        try {
            final InetAddress ipAddr = InetAddress.getByName("google.com");
            if (ipAddr.equals("")) {
                return false;
            } else {
                return true;
            }
        } catch (Exception e) {
            return false;
        }
    }

    private void createNetErrorDialog() {
        networkSettingsDialogOpened = true;
        final AlertDialog.Builder builder = new AlertDialog.Builder(this);
        builder.setMessage("You need a network connection to use this application. Please turn on mobile network or Wi-Fi in Settings.")
                .setTitle("Unable to connect")
                .setCancelable(false)
                .setPositiveButton("Settings",
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int id) {
                                Intent i = new Intent(Settings.ACTION_WIRELESS_SETTINGS);
                                startActivityForResult(i, WIFI_REQUEST_CODE);
                            }
                        }
                )
                .setNegativeButton("Cancel",
                        new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int id) {
                                HomeScreen.this.finish();
                            }
                        }
                );
        final AlertDialog alert = builder.create();
        alert.show();
    }

    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == WIFI_REQUEST_CODE) {
            if (resultCode == RESULT_OK) {
                networkSettingsDialogOpened = false;
                Toast.makeText(HomeScreen.this, "Returned Ok",
                        Toast.LENGTH_LONG).show();
            }
            if (resultCode == RESULT_CANCELED) {
                networkSettingsDialogOpened = false;
                Toast.makeText(HomeScreen.this, "Returned Canceled",
                        Toast.LENGTH_LONG).show();
            }
        }
    }
}

但是我收到以下错误:

02-03 18:13:14.525    2683-2699/greensmartcampus.eu.smartcampususerfeedbackapp E/AndroidRuntime﹕ FATAL EXCEPTION: Thread-193
    Process: greensmartcampus.eu.smartcampususerfeedbackapp, PID: 2683
    java.lang.RuntimeException: Can't create handler inside thread that has not called Looper.prepare()
            at android.os.Handler.<init>(Handler.java:200)
            at android.os.Handler.<init>(Handler.java:114)
            at android.app.Dialog.<init>(Dialog.java:108)
            at android.app.AlertDialog.<init>(AlertDialog.java:125)
            at android.app.AlertDialog$Builder.create(AlertDialog.java:967)
            at greensmartcampus.eu.smartcampususerfeedbackapp.HomeScreen.createNetErrorDialog(HomeScreen.java:97)
            at greensmartcampus.eu.smartcampususerfeedbackapp.HomeScreen.access$200(HomeScreen.java:15)
            at greensmartcampus.eu.smartcampususerfeedbackapp.HomeScreen$1.run(HomeScreen.java:29)

注意:第 97 行包含:

final AlertDialog alert = builder.create();

我用谷歌搜索了很多,我已经在使用 runOnUiThread 的陈词滥调,但它并没有解决它。

我错过了什么?

【问题讨论】:

    标签: android multithreading android-intent android-activity android-ui


    【解决方案1】:

    您检查互联网的方式我猜您正在导致您的 UI 线程进入休眠状态。你应该这样做。

    创建一个Handler和Thread running flag:

    Handler mHandler = new Handler();
    boolean isRunning = true;
    

    然后,从你的 onCreate() 方法中使用这个线程:

    new Thread(new Runnable() {
        @Override
        public void run() {
            while (isRunning) {
                try {
                    Thread.sleep(10000);
                    mHandler.post(new Runnable() {
                        @Override
                        public void run() {
                            if(!HomeScreen.this.isInternetAvailable()){
                                if (!networkSettingsDialogOpened)
                                    HomeScreen.this.createNetErrorDialog();
                            }
                        }
                    });
                 } catch (Exception e) {
                 }
             }
         }
        }).start(); 
    

    稍微改变一下这个方法

    private boolean isInternetAvailable() {
        try {
            final InetAddress ipAddr = InetAddress.getByName("google.com");
            if (ipAddr.equals("")) {
                return false;
            } else {
                isRunning = true;
                return true;
            }
        } catch (Exception e) {
            return false;
        }
    }
    

    【讨论】:

    • 两个答案都解决了我的问题,我怎样才能选择一个作为这个主题的正确答案。我可以以某种方式将两个答案都选为获胜者吗?
    • 不,您只能选择一个!你可以为任何人去。
    • 我不能。我已经学会了非常有用的方法来解决这个未来的问题,两个答案都是正确的答案......也许我们可以扔硬币。但这仍然是不公平的......
    【解决方案2】:

    您不能从 UI 线程上运行的代码调用 Thread.sleep()。这是你的代码:

        this.runOnUiThread(new Runnable() {
            @Override
            public void run() {
                while (!HomeScreen.this.isInternetAvailable()) {
                    if (!networkSettingsDialogOpened)
                        HomeScreen.this.createNetErrorDialog();
                    try {
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    

    您开玩笑说需要在 UI 线程上运行显示Dialog 的代码。试试这个:

        new Thread(new Runnable() {
            @Override
            public void run() {
                while (!HomeScreen.this.isInternetAvailable()) {
                    if (!networkSettingsDialogOpened)
                        // Show the Dialog on the UI thread
                        HomeScreen.this.runOnUiThread(new Runnable() {
                            @Override
                            public void run() {
                                HomeScreen.this.createNetErrorDialog();
                            }
                        });
                    try {
                        Thread.sleep(10000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    

    【讨论】:

    • 两个答案都解决了我的问题,我怎样才能选择一个作为这个主题的正确答案。我可以以某种方式将两个答案都选为获胜者吗?
    • 不。您只能选择一个。随便挑一个。我不会生气的。
    • 我不能。我已经学会了非常有用的方法来解决这个未来的问题,两个答案都是正确的答案......也许我们可以扔硬币。但这仍然是不公平的......
    • 只选择另一个。我已经有更多的声望点了:-)
    • 好的。谢谢。我希望你的回答得到大量的赞成票作为交换。 :)
    猜你喜欢
    • 1970-01-01
    • 2012-08-15
    • 2011-09-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多