还有一个 "Can't create handler inside thread that has not called Looper.prepare()" 主题

Yet another "Can't create handler inside thread that has not called Looper.prepare()" topic

我有这个代码,它是一个 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.access0(HomeScreen.java:15)
            at greensmartcampus.eu.smartcampususerfeedbackapp.HomeScreen.run(HomeScreen.java:29)

注意: 第 97 行包含:

final AlertDialog alert = builder.create();

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

我错过了什么?

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

创建一个处理程序和线程运行 标志:

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;
    }
}

您不能从 UI 线程上 运行ning 的代码调用 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();