1

我想这是一个更通用的问题,但我的 Android 程序似乎在这两个与线程创建相关的函数调用之间的主 UI 线程中调用 onResume。这会导致其他我不想发生的调用,到目前为止,我发现的唯一解决方法是设置全局标志(我不喜欢,而且我认为这是不好的编程习惯)。它看起来像这样:

mConnectThread = new ConnectThread(bd);
mConnectThread.start();

不知何故,在这些调用之间(由 BluetoothCommHandler 对象从 UI 线程进行),onResume 被调用。如果有人能指出何时触发 onResume 和其他活动生命周期事件的良好来源,我将非常感激。此外,我检查了这个:http: //developer.android.com/reference/android/app/Activity.html,它似乎没有我能找到的任何提示。

最后一点 - onResume 总是在这两个命令之间被调用,这让我认为这不是一个真正的线程切换问题。

我也刚刚注意到 onResume 被称为一对 onPause ,它被更早地调用 - 仍然不知道为什么它恰好发生在这两个函数调用之间。

编辑:代码包含在下面。

蓝牙处理程序对象的调用:

mBComm = new BluetoothCommHandler(this, mHandler);

主 UI 线程中的 onResume 函数(mNoRestartFlag只有在我想要的时候才会调用这个特定的位。它不是我在上面提到的标志 - 它处理我在这里没有谈论的另一种情况):

@Override
protected void onResume() {
    super.onResume();

    mNfcAdapter.enableForegroundDispatch(this, mPendingIntent,
mFilters, mTechLists);

    Log.i(TAG, "OnResume called.");
    if(mBComm != null && !mNoRestartFlag) {
        mBComm.start();
    }
}

AndroidManifest 中的 Activity OptionsHandler(与 DeviceListActivity 相同)声明(请注意,它是一个 Theme.Dialog 样式的活动,它弹出在 UI 线程的顶部,导致我上面提到的 onPause):

activity android:name=".OptionsHandler"
              android:label="@string/select_device"
              android:theme="@android:style/Theme.Dialog"
              android:configChanges="orientation|keyboardHidden" />

实际的 connectThread 被创建:

public synchronized void connect(BluetoothDevice bd) {
    Log.i(TAG, "connect called from inside BluetoothCommHandler");

    if (mAcceptThread == null) {
        Log.i(TAG, "Creating an AcceptThread");
        mAcceptThread = new AcceptThread();
        mAcceptThread.start();
    }

    mConnectThread = new ConnectThread(bd);
    mConnectThread.start();
 }

ConnectThread 的创建和运行(该mDontKill标志我上面提到的用于绕过 onResume 症状的标志):

public ConnectThread(BluetoothDevice bd) {
        Log.i(TAG, "created ConnectThread");
        mBD = bd;
        BluetoothSocket bs = null;

        try {
            bs = mBD.createInsecureRfcommSocketToServiceRecord(MY_UUID);                
        } catch (IOException e) {
            Log.i(TAG, "Could not create an RFCOMM socket!", e);
        }
        mBS = bs;
        if (mBS != null) Log.i(TAG, "BluetoothSocket acquired");
        else Log.i(TAG, "BluetoothSocket null!");

        mDontKillFlag = true;
    }

public void run() {
        Log.i(TAG, "BEGIN ConnectThread");
         // Always cancel discovery because it will slow down a connection
        mBluetoothAdapter.cancelDiscovery();

        mDontKillFlag = false;
        // Make a connection to the BluetoothSocket
        try {
            // This is a blocking call and will only return on a
            // successful connection or an exception
            mBS.connect();
            Log.i(TAG, "Connected to BluetoothDevice");
        } catch (IOException e) {
            Log.i(TAG, e.toString());
            // Close the socket
            try {
                mBS.close();
            } catch (IOException e2) {
                Log.i(TAG, "unable to close RFCOMM socket", e2);
            }
            Log.i(TAG, "About to call connectionFailed");
            connectionFailed();
            return;
        }

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

        // Start the connected thread
        connected(mBS, mBD);
    }

导致问题的实际 start() 函数:

public synchronized void start() {
    if (D) Log.i(TAG, "start called from inside BluetoothCommHandler");

    // Cancel any thread attempting to make a connection
    if (mConnectThread != null && !mDontKillFlag) 
    {mConnectThread.cancel(); mConnectThread = null;}

    // Cancel any thread currently running a connection
    if (mConnectedThread != null) 
    {mConnectedThread.cancel(); mConnectedThread = null;}

    if (mAcceptThread == null) {
        Log.i(TAG, "Creating an AcceptThread");
        mAcceptThread = new AcceptThread();
        mAcceptThread.start();
    }
}

图例: mBS是一个蓝牙套接字mDB的成员变量,一个蓝牙设备的成员变量。

总而言之,我在 UI 线程上创建了一个 BluetoothCommHandler 对象,它尝试创建一个 ConnectThread,然后在蓝牙套接字上调用 accept() 命令时,它失败了,因为线程的 cancel() 函数已被调用(这只是有一个关闭套接字的try-catch)。此取消是从上面列出的 start() 函数调用的,该函数由 onResume 函数调用。onResume 是 onPause 的补充,由于主 UI 活动上出现选择器对话框而被调用。这个 onResume 似乎总是在我提到的 pre-EDIT 的前两行代码之间被调用。我试图弄清楚为什么它总是在那里发生,这样我就可以在没有关闭套接字的情况下发生 accept() 。

4

0 回答 0