在Android中,线程导致手机崩溃

3

由于我无法阅读崩溃日志,因此我不知道这段代码中出了什么问题。我们讨论的不是应用程序崩溃,而是手机崩溃,可能是由于死锁线程或某种锁定引起的。欢迎提出建议!


背景:

当我启动连接时,会显示一个对话框,当我按下返回按钮时,该对话框会冻结,过一会儿后手机就会崩溃...

代码:

这是处理与设备连接的线程。我完全没有连接到设备的问题。我所知道的是,当我按下返回按钮时,mmSocket.connect()正在运行。认为问题就出在这里...

class ConnectThread extends Thread {

/**
 * 
 */
private Handler threadhandler;
private BluetoothDevice mmDevice;
private volatile BluetoothSocket mmSocket;
private Message toMain;
//      private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

public ConnectThread(Handler threadhandler, BluetoothDevice device) {

    this.threadhandler = threadhandler;
    this.mmDevice = device;


    // Get a BluetoothSocket to connect with the given BluetoothDevice
    try {
        Method m = mmDevice.getClass().getMethod("createRfcommSocket", new Class[] {int.class});
        mmSocket = (BluetoothSocket) m.invoke(mmDevice, 1);

    }catch (NoSuchMethodException e) {

        e.printStackTrace();
    } catch (IllegalArgumentException e) {

        e.printStackTrace();
    } catch (IllegalAccessException e) {

        e.printStackTrace();
    } catch (InvocationTargetException e) {

        e.printStackTrace();
    }

}

public void run() {
    Looper.prepare();
    try {
        // Connect the device through the socket. This will block
        // until it succeeds or throws an exception

        mmSocket.connect();

        toMain = threadhandler.obtainMessage();
        toMain.arg1 = 1;
        threadhandler.sendMessage(toMain);


    } catch (SecurityException e) {

        Log.e("SecurityExcep", "Oh noes" , e);
        toMain = threadhandler.obtainMessage();
        toMain.arg1 = 2;
        threadhandler.sendMessage(toMain);
        Log.w("MESSAGE", e.getMessage());

    }catch (IOException e) {
        //Bad connection, let's get the hell outta here
        try {
            Log.e("IOExcep", "Oh noes" , e);
            Log.w("MESSAGE", e.getMessage());

            mmSocket.close();
            toMain = threadhandler.obtainMessage();
            toMain.arg1 = 2;
            toMain.obj = e.getMessage();
            threadhandler.sendMessage(toMain);


            return;
        } catch (IOException e1) {
            Log.e("IOExcep2", "Oh noes" , e);
        }
    }
    try {
        mmSocket.close();
    } catch (IOException e) {
        Log.d("CONNECT_CONSTRUCTOR", "Unable to close the socket", e);
    }

    toMain = threadhandler.obtainMessage();
    toMain.arg1 = 3;
    threadhandler.sendMessage(toMain);

    Looper.loop();
    return;
    // Now it should be paired.. only thing to do now is let the user commit to the rest
}

/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
    try {
        mmSocket.close();
    } catch (IOException e) { }
}

}

下面的代码片段是对话框创建器中的一部分,线程名为d

(...)

        case DIALOG_BT_ADDING:
        search_dialog = new ProgressDialog(this);
        search_dialog.setTitle(R.string.adding);
        search_dialog.setMessage(res.getText(R.string.bluetooth_add_accept));
        search_dialog.setIndeterminate(true);           
        search_dialog.setCancelable(true);
        search_dialog.setOnCancelListener(new OnCancelListener() {

            @Override
            public void onCancel(DialogInterface dialog) {
                Log.i("THREAD CONNECT", "Is it alive?: " + d.isAlive());
                if(d != null && d.isAlive()){
                    d.cancel();
                    //d = null;
                }
                if(d2 != null && d2.isAlive()){
                    d2.cancel(false);
                    //d2 = null;

                }
                search_dialog.dismiss();
                showDialog(DIALOG_NEW_DEVICE_FOUND);

            }
        });         
        return search_dialog;
(...)

这里是执行ConnectThread类的代码片段。
private void connectBluetooth(boolean nextstage, IOException e1){
    if(!nextstage){
        showDialog(DIALOG_BT_ADDING);

        d = new ConnectThread(threadhandler, selected_car.getDevice());
        d.start();

    }
    else{
        if(e1 != null){

            d2 = new BluetoothCheckThread(checkthreadhandler,mBluetoothAdapter, 
                    5000, car_bt, after_bt);
            d2.start();
            search_dialog.dismiss();
        }
        else{
            showDialog(DIALOG_BT_ADDING_FAILED);
        }
    }
}

希望你们能够帮助我!感谢任何反馈。


我认为你的代码并没有做你想要它做的事情。你能否解释一下你认为它在做什么?为什么要在线程中搞Loopers?你所调用的run()方法直到Looper.quit()被调用才会完成。ConnectThread()是在哪里启动的? - cyngus
我认为我的代码正在与蓝牙设备配对。这是它的主要和唯一目的,它也确实做到了。在连接过程中,我想向处理UI线程的处理程序发送消息,该处理程序当前已实现。当连接超时/主机关闭等情况发生时,会显示对话框。但是,在添加过程中按下返回按钮时出现问题...可能是Looper引起的问题吗? - Mazze
是的,我不明白为什么你在这里使用Looper,因为你没有向带有Looper的线程发送任何消息。同时也不清楚ConnectThread()在哪里/如何启动,你是调用run()还是start()? - cyngus
Loopers已被移除,但问题仍然存在。当在mmSocket.connect()进程期间调用mmSocket.close()时,它会失败。请注意,mmSocket.connect()是一个锁定的调用..这就是问题所在! - Mazze
3个回答

1

好的,你正在从看起来像是UI线程中调用BluetoothSocket.close()。这可能会导致“冻结”。

当你说手机“崩溃”时,你是指它重新启动吗?如果是这样,这是一个完整的重启(屏幕回到你第一次打开手机时发生的情况),还是运行时重启(手机通常显示某种动画,在Nexus设备上,它是四色粒子喷射)?如果不是重启,你是指你只得到一个允许你杀死应用程序的对话框吗?

在任何情况下,您可能需要获取调用BluetoothSocket.connect()的线程的引用,并调用Thread.interrupt()。我不确定BluetoothSocket是否可中断,但让我们希望如此。然后在中断后调用close(),这可能不应该在主线程上调用。


不,我没有调用cancel()函数,在cancel()函数中我使用mmSocket.close()来中断连接。UI的冻结不会导致手机崩溃。系统会意识到UI没有响应,用户无法进行任何操作,从而弹出一个系统对话框询问“等待”或“强制关闭”...这是另外一种情况 :S - Mazze
确实,我没有意识到在BT套接字上调用close()会中断阻塞的调用。你能详细描述一下这个"崩溃"吗?也许你可以按照我提出的思路来描述一下? - cyngus

0

尝试在 dialog.setOnKeyListener() 中使用,按下keyCode_BACK时取消线程。尝试这个会有用。


当对话框被取消时,onCancelListener不会被调用吗?按下返回按钮就可以取消对话框了,是吗? - Mazze
取消对话框与按下返回键相同:http://developer.android.com/reference/android/app/Dialog.html#setCancelable%28boolean%29 - Mazze
当对话框正在运行时,停止它,从而在对话框中调用 OnCancel() - Mazze
尝试使用handler.removeCallBack(runnable)而不是取消线程。 - ilango j
没有由处理程序启动,那我为什么要执行removeCallback呢? - Mazze

-2

看起来你正在对 BluetoothSocket 调用 connect 和 close,这是一个“不行”的做法。它似乎会导致死锁。请参阅此link以获取更多信息。


1
哇,所以这个问题太长了,你没有读完就发了一个回答,而且这个回答是基于你浏览现有答案时收集到的假设......欢迎来到这个网站,但如果你继续这样回答问题,你会得到很多负面声誉。 - user562566
请尝试阅读 OP 的问题并跟随我的链接,而不是只是下投票。我没有发布是因为我认为它不会有用。我也曾经遇到过关闭函数崩溃手机的类似问题。我花时间查找了链接并发布了它。也许我有点讽刺,但如果您阅读问题和示例代码,您应该就明白为什么了。 - Alex

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接