我想这是一个更通用的问题,但我的 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() 。