これはより一般的な質問だと思いますが、私の Android プログラムは、これら 2 つのスレッド作成関連の関数呼び出しの間にメイン UI スレッドで onResume を呼び出しているようです。これにより、発生したくない他の呼び出しが発生します。これまでのところ、これを回避する唯一の方法は、グローバルフラグを設定することです (これは好きではなく、私の意見ではプログラミングの悪い習慣です)。次のようになります。
mConnectThread = new ConnectThread(bd);
mConnectThread.start();
どういうわけか、これらの呼び出し (BluetoothCommHandler オブジェクトによって UI スレッドから行われる) の間に、onResume が呼び出されます。onResume やその他のアクティビティ ライフサイクル イベントがいつトリガーされるかについて、誰かが私に良い情報源を教えてくれたら、私は大いに感謝します。さらに、私はこれをチェックしました: http://developer.android.com/reference/android/app/Activity.html、見つけることができるヒントがないようでした。
最後の注意 - onResume は、これら 2 つのコマンドが呼び出される間に常に呼び出されるため、実際にはスレッド切り替えの問題ではないと思います。
また、onResume が WAY より前に呼び出される onPause のペアとして呼び出されることにも気付きましたが、これら 2 つの関数呼び出しの間で正確に発生する理由はまだわかりません。
編集:コードは以下に含まれています。
Bluetooth ハンドラ オブジェクトの呼び出し:
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
BluetoothSocket でmDB
あるメンバー変数であり、BluetoothDevice であるメンバー変数です。
要約すると、UI スレッドで BluetoothCommHandler オブジェクトを作成します。これは ConnectThread を作成しようとし、Bluetooth ソケットで accept() コマンドを呼び出しているときに、スレッドの cancel() 関数が呼び出されたために失敗します (単にソケットを閉じる try-catch があります)。このキャンセルは、上記の start() 関数から呼び出され、onResume 関数によって呼び出されます。onResume は、メイン UI アクティビティの上に表示されるセレクタ ダイアログのために呼び出される onPause を補完するものです。この onResume は常に、編集前に言及した最初の 2 行のコードの間で呼び出されるようです。ソケットを閉じずにaccept()を発生させることができるように、なぜそれが常に正確に発生するのかを理解しようとしています。