私はAndroid向けのゲームを作成しています。このゲームでは、2つのデバイスが接続して少量のデータを交換し、そのデータを切断して使用します。Bluetoothチャットの例から始めました。この時点で、私はそれをほとんど機能させていますが、いくつかの(ほとんどの)場合、デバイスの1つがデータを受信しません。これは両方のデバイスで同じアプリであるため、両方の送信コードと受信コードは同じです。私はこのように接続しています:
public BluetoothClientThread(BluetoothDevice get_device,boolean secure){
BluetoothSocket temp=null;
device=get_device;
socket_type=secure?"Secure":"Insecure";
try{
if(secure){
temp=device.createRfcommSocketToServiceRecord(UUID_SECURE);
}
else{
temp=device.createRfcommSocketToServiceRecord(UUID_INSECURE);
}
}
catch(IOException e){
StorageManager.error_log_add(context,TAG,"create() on "+socket_type+" client socket failed.",e);
}
socket=temp;
}
public void run(){
bluetooth_adapter.cancelDiscovery();
try{
socket.connect();
}
catch(IOException e){
StorageManager.error_log_add(context,TAG,"Connection failed.",e);
try{
socket.close();
}
catch(IOException ioe){
StorageManager.error_log_add(context,TAG,"close() on "+socket_type+" client socket failed during connection failure.",ioe);
}
connection_failed();
return;
}
synchronized(BluetoothService.this){
bluetooth_client_thread=null;
}
connected(socket,device,socket_type,false);
}
接続したら、ソケットのgetInputStream()とgetOutputStream()を取得します。次に、次のコードを使用して、ソケットの入力を読み取ります。
public void run(){
String packet="";
while(true){
try{
int get_byte=input.read();
char get_char=(char)get_byte;
if(get_char!='\u0003'){
StorageManager.error_log_add(context,"BluetoothService","Adding packet raw data: \""+get_char+"\"",null);
packet+=get_char;
}
else{
StorageManager.error_log_add(context,"BluetoothService","Packet received:\n"+packet,null);
handler.obtainMessage(Activity_Battle_Menu.HANDLER_READ,packet).sendToTarget();
packet="";
}
if(done && they_done){
handler.obtainMessage(Activity_Battle_Menu.HANDLER_READY).sendToTarget();
}
}
catch(IOException e){
StorageManager.error_log_add(context,TAG,"Connection lost.",e);
connection_lost();
break;
}
}
}
一度に1バイトずつデータを読み取り、そのバイトをパケット文字列に追加します。ETX文字に到達すると(送信時にすべての最後に貼り付けます)、完全なパケットが受信され、ハンドラーを介してアクティビティに渡され、そこで処理されます。これが私の書き込みコードです:
public void write(byte[] buffer){
try{
StorageManager.error_log_add(context,"BluetoothService","Writing data:\n"+new String(buffer),null);
output.write(buffer);
}
catch(IOException e){
StorageManager.error_log_add(context,TAG,"write() on "+socket_type+" connected socket failed.",e);
}
}
ご覧のとおり、データ「パケット」が送信されたとき、バイトが受信されたとき、および「パケット」全体が受信されたときに、ログに書き込みます。
これに関連するものがあるかどうかはわかりませんが、Cyanogenmod 7.1(Android 2.3.7)とVirtualBox(Android 2.3.5)で実行されているAndroidx86を使用してNookColorでテストしています。私のアプリのminSdkVersionは8(Android 2.2)です。コンピューターで実行されているAndroidの場合、RocketfishUSBBluetoothアダプターを使用しています。
各インスタンスから送信されるデータのパケットは2つであると想定されています。まず、必要なすべてのゲームデータを保持するデータパケットが送信されます。他のインスタンスのゲームデータが受信されると、アプリは独自のブール値doneをtrueに設定します。また、「完了」パケットを他のインスタンスに送信します。したがって、両方のインスタンスが実行され、もう一方が実行されたことがわかると、すべてのデータが送受信されたことがわかり、両方ともBluetoothスレッドを切断/停止して、データに作用します。
データの送受信時に両方のデバイスにログを記録しているので、ログは何が起こっているのかを教えてくれます。
-最初に、両方のゲームを開始し、Bluetoothアクティビティに移動します(明らかに)。
-次に、エミュレートされたインスタンスからNookインスタンスに接続します。
-エミュレートされたインスタンスは、ゲームデータパケットを送信します。
-Nookインスタンスは、エミュレートされたインスタンスのゲームデータを受信し、独自のデータを送信します(非同期で発生するという理由だけで、これら2つが順番に入れ替わる場合があります)。
-ゲームデータパケットを受信したため、Nookインスタンスは「完了」パケットを送信するようになりました。
-それだ。エミュレートされたインスタンスは、どちらのパケットも受信しません。1バイトも受信せず、input.read()はブロックするだけで、(本来あるべきように)決して到着しない入力を待ちます。
それが私の問題です。次の2つのいずれかが発生しているようです。
データは、例外をスローしなくても、Nookインスタンスのoutput.write()によって送信されることはなく、ログはデータが呼び出されたことを確認します。
エミュレートされたインスタンスのinput.read()によってデータが受信されることはありません。多分それは送信で失われますか?
私の知る限り、私のコードは堅実です。問題はBluetoothに関連しているようです。たぶん、一方または両方のAndroidインスタンスに厄介なBluetooth設定がありますか?
また、まれに(おそらく1/15回)、すべてのパケットが適切に送受信され、ゲームが正常に進行することも付け加えておきます。したがって、問題が発生した場合は通常のみ発生しますが、常に発生するとは限りません。