我必须在一个线程中调用Looper.prepare()吗?

时间:2015-11-22 14:52:04

标签: android bluetooth

我已经搜索了线程和looper之间的关系,我现在只知道这两个词的字面含义是什么。在达到特定条件时,我仍然有点困惑。

当我尝试构建一个关于与蓝牙设备通信的应用程序时,我遇到了这个问题。我在连接线程中遇到了问题。

private class ConnectThread extends Thread {
    private final BluetoothSocket mmSocket;
    private final BluetoothDevice mmDevice;
    private String mSocketType;

    public ConnectThread(BluetoothDevice device, boolean secure) {
        mmDevice = device;
        BluetoothSocket tmp = null;
        mSocketType = secure ? "Secure" : "Insecure";

        // Get a BluetoothSocket for a connection with the
        // given BluetoothDevice
        try {
            if (secure) {
                tmp = device.createRfcommSocketToServiceRecord(
                        MY_UUID_SECURE);
            } else {
                tmp = device.createInsecureRfcommSocketToServiceRecord(
                        MY_UUID_INSECURE);
            }
        } catch (IOException e) {
            tip("Socket Type: " + mSocketType + "create() failed");
        }
        mmSocket = tmp;
    }

    public void run() {
        Looper.prepare();
        setName("ConnectThread" + mSocketType);

        // Always cancel discovery because it will slow down a connection
        if(mBluetoothAdapter.isDiscovering())
            mBluetoothAdapter.cancelDiscovery();

        // Make a connection to the BluetoothSocket
        try {
            // This is a blocking call and will only return on a
            // successful connection or an exception
            mmSocket.connect();
        } catch (IOException e) {
            // Close the socket
            try {
                mmSocket.close();
            } catch (IOException e2) {
                e2.printStackTrace();
            }
            connectionFailed();
            return;
        }

        // Reset the ConnectThread because we're done
        synchronized (BluetoothThreads.this) {
            mConnectThread = null;
        }

        // Start the connected thread
        connected(mmSocket, mmDevice, mSocketType);
        Looper.loop();
    }

    public void cancel() {
        try {
            mmSocket.close();
        } catch (IOException e) {

        }
    }
}

此代码是从Android Developers的示例下载的。而且我自己添加了Looper.prepare(),Looper.loop()。在调用这两种方法时,应用程序将崩溃。我收到了android studio的警告:无法在没有调用Looper.prepare()的线程内创建处理程序。这就是我添加这两种方法的原因。

我想问一下,我是否以正确的方式调用这两种方法?

为什么我必须在没有像其他人一样使用Toast或Handler时调用它们?

3 个答案:

答案 0 :(得分:0)

  

我想问一下,我是否以正确的方式调用这两种方法?

  

为什么我必须在没有像其他人一样使用Toast或Handler时调用它们?

Looper.loop()Looper().prepare()用于创建MessageQueue并处理此MessageQueue android建议使用Handler,因此如果您使用Looper.loop()然后你应该使用Looper.prepare()

答案 1 :(得分:0)

好吧,最后我弄清楚自己的项目有什么问题。 build.gradle没有任何关系,但是感谢 Android Dev

实际上这是我自己的责任。在示例项目BluetoothChat中,调用Log.d()之类的方法来指示调试信息。但我不知道在哪里找到Log.d()的结果,所以我用Toast替换了它们。我觉得那很好。但我发现Toast中不能使用ConnectThread,否则会引发异常:

  

java.lang.RuntimeException:无法在未调用Looper.prepare()的线程内创建处理程序

我在方法Toast中使用connectionFailed(),这就是问题所在。

答案 2 :(得分:0)

实际上,需要Looper.prepare()Looper.loop()。只有当你想在线程中附加Handler时才需要这些,在你的情况下,我看不到这样的要求。

基本上,一旦你调用Looper.prepare(),它就会为这个线程分配一个消息队列,这样处理程序传递的所有后续消息都将以队列方式逐个处理。

注意:要进行调试,请始终使用Log.d() / Log.w() / Log.e()并避免使用祝酒词。