안녕하세요
불루투스 chat 예제를 응용하여 블루투스 통신 앱을 만들고 있습니다.
그런데 문제는..
connected 함수에서 connectedTread 함수를 start 하니 예상치 못한 예러가 발생합니다.
이틀동안 이부분만 봐도 답이 안나오네요
한수만 가르쳐주세요 뭐가 문제 인지..
혹시다 다른데서 잘 못 된줄 알고, 계속 찾아봣는데 아무리 찾아도 답이 안나옵니다.
소스 코드 입니다.
public class BluetoothService{
// Debugging
private static final String TAG = "BluetoothChatService";
private static final boolean D = true;
// Name for the SDP record when creating server socket
private static final String NAME = "BluetoothChat";
// Unique UUID for this application
//private static final UUID MY_UUID = UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");
private static final UUID MY_UUID = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");
// Member fields
private final BluetoothAdapter mAdapter;
private final Handler mHandler ;
private AcceptThread mAcceptThread;
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
private int mState;
// Constants that indicate the current connection state
public static final int STATE_NONE = 0; // we're doing nothing
public static final int STATE_LISTEN = 1; // now listening for incoming connections
public static final int STATE_CONNECTING = 2; // now initiating an outgoing connection
public static final int STATE_CONNECTED = 3; // now connected to a remote device
public BluetoothService(Context context, Handler handler) {
mAdapter = BluetoothAdapter.getDefaultAdapter();
mState = STATE_NONE;
mHandler = handler;
}
private synchronized void setState(int state) {
if (D) Log.d(TAG, "setState() " + mState + " -> " + state);
mState = state;
// Give the new state to the Handler so the UI Activity can update
mHandler.obtainMessage(btService.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
}
/* Return the current connection state. */
public synchronized int getState() {
return mState;
}
public synchronized void start() {
if (D) Log.d(TAG, "start");
// Cancel any thread attempting to make a connection
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
// Cancel any thread currently running a connection
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
// Start the thread to listen on a BluetoothServerSocket
if (mAcceptThread == null) {
mAcceptThread = new AcceptThread();
mAcceptThread.start();
//////////// 이다음 함수 호출 하여 위치정보 및 문자 수신!!!
}
setState(STATE_LISTEN);
}
public synchronized void connect(BluetoothDevice device) {
if (D) Log.d(TAG, "connect to: " + device);
// Cancel any thread attempting to make a connection
if (mState == STATE_CONNECTING) {
if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
}
// Cancel any thread currently running a connection
if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
// Start the thread to connect with the given device
mConnectThread = new ConnectThread(device);
mConnectThread.start();
setState(STATE_CONNECTING);
}
public synchronized void connected(BluetoothSocket socket, BluetoothDevice device) {
if (D) Log.d(TAG, "connected");
Message msg1 = mHandler.obtainMessage(btService.MESSAGE_TOAST);
Bundle bundle1= new Bundle();
bundle1.putString(btService.TOAST, "connected : 함수 진입!! mConnectThread : " + mConnectThread);
msg1.setData(bundle1);
mHandler.sendMessage(msg1);
try {
Thread.sleep(5000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// If a connection was accepted
// Cancel the thread that completed the connection
// 연결을 완료 시 thread 취소
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
// Cancel any thread currently running a connection
//현재 연결을 실행하는 스레드를 취소
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
// Cancel the accept thread because we only want to connect to one device
//하나의 디바이스 연결을 원하기 때문에 accept thread 취소
if (mAcceptThread != null) {
mAcceptThread.cancel();
mAcceptThread = null;
}
// Start the thread to manage the connection and perform transmissions
mConnectedThread = new ConnectedThread(socket);
mConnectedThread.start(); /// 여기에서 문제 발생!!!!!!
이것만 실행하면 앱이 예상치 못한 에러라고 말하며 죽습니다.
//UI 활동에 다시 연결된 장치의 이름을 보내기
Message msg = mHandler.obtainMessage(btService.MESSAGE_DEVICE_NAME);
Bundle bundle = new Bundle();
bundle.putString(btService.DEVICE_NAME, device.getName());
msg.setData(bundle);
mHandler.sendMessage(msg);
setState(STATE_CONNECTED);
}
public synchronized void stop() {
if (D) Log.d(TAG, "stop");
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
if (mAcceptThread != null) {
mAcceptThread.cancel();
mAcceptThread = null;
}
setState(STATE_NONE);
}
public void write(byte[] out) {
// Create temporary object
ConnectedThread r;
// Synchronize a copy of the ConnectedThread
synchronized (this) {
if (mState != STATE_CONNECTED) return;
r = mConnectedThread;
}
// Perform the write unsynchronized
r.write(out);
}
private void connectionFailed() {
setState(STATE_LISTEN);
// Send a failure message back to the Activity
Message msg = mHandler.obtainMessage(btService.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(btService.TOAST, "Unable to connect device");
msg.setData(bundle);
mHandler.sendMessage(msg);
}
private void connectionLost() {
setState(STATE_LISTEN);
// Send a failure message back to the Activity
Message msg = mHandler.obtainMessage(btService.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(btService.TOAST, "Device connection was lost");
msg.setData(bundle);
mHandler.sendMessage(msg);
// Cancel any thread attempting to make a connection
if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
// Cancel any thread currently running a connection
if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
if (mAcceptThread != null) {mAcceptThread.cancel(); mAcceptThread.stop(); mAcceptThread = null;}
mAcceptThread = new AcceptThread();
mAcceptThread.start();
setState(STATE_LISTEN);
}
private class AcceptThread extends Thread {
// The local server socket
private final BluetoothServerSocket mmServerSocket;
public AcceptThread() {
BluetoothServerSocket tmp = null;
///////////////////////////////////////////////////////////////////////////////////
Message msg = mHandler.obtainMessage(btService.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(btService.TOAST, "AcceptThread 생성");
msg.setData(bundle);
mHandler.sendMessage(msg);
///////////////////////////////////////////////////////////////////////////////
// Create a new listening server socket
//새로운 청취 서버 소켓을 만듭니다
try {
tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);
} catch (IOException e) {
Log.e(TAG, "listen() failed", e);
}
mmServerSocket = tmp;
}
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
if (D) Log.d(TAG, "BEGIN mAcceptThread" + this);
setName("AcceptThread");
BluetoothSocket socket = null;
///////////////////////////////////////////////////////////////////////////////////////////////
Message msg = mHandler.obtainMessage(btService.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(btService.TOAST, "AcceptThread 실행 (Start-run() 함수 발동!!");
msg.setData(bundle);
mHandler.sendMessage(msg);
//////////////////////////////////////////////////////////////////////////////////////////////
// Listen to the server socket if we're not connected
//우리가 연결되지 않은 경우 서버 소켓에 기다리기
while (mState != STATE_CONNECTED) {
try {
// This is a blocking call and will only return on a
// successful connection or an exception
socket = mmServerSocket.accept();
} catch (Exception e) {
Log.e(TAG, "accept() failed", e);
break;
}
Message msg1 = mHandler.obtainMessage(btService.MESSAGE_TOAST);
Bundle bundle1 = new Bundle();
bundle1.putString(btService.TOAST, "socket : "+ socket.toString());
msg1.setData(bundle1);
mHandler.sendMessage(msg1);
try {
Thread.sleep(1000);
} catch (InterruptedException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
// If a connection was accepted
try{
if (socket != null) {
synchronized (BluetoothService.this) {
switch (mState) {
case STATE_LISTEN: // 지금 들어오는 연결 수신
case STATE_CONNECTING: // 지금 나가는 연결의 시작
// Situation normal. Start the connected thread.
//정상적인 상황. 연결된 스레드를 시작합니다.
connected(socket, socket.getRemoteDevice());
break;
case STATE_NONE: //
case STATE_CONNECTED: //이제 원격 장치에 연결
// Either not ready or already connected. Terminate new socket.
//어느 준비하거나 이미 연결되지 않았습니다. 새로운 소켓을 종료 할 수 있습니다.
try {
socket.close();
} catch (IOException e) {
Log.e(TAG, "Could not close unwanted socket", e);
}
break;
}
}
}
}catch(Exception ex){
}
}
if (D) Log.i(TAG, "END mAcceptThread");
}
public void cancel() {
if (D) Log.d(TAG, "cancel " + this);
try {
mmServerSocket.close();
} catch (IOException e) {
Log.e(TAG, "close() of server failed", e);
}
}
}
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
// TODO Auto-generated constructor stub
mmDevice = device;
BluetoothSocket tmp = null;
// Get a BluetoothSocket for a connection with the
// given BluetoothDevice
try {
tmp = device.createRfcommSocketToServiceRecord(MY_UUID);
} catch (IOException e) {
Log.e(TAG, "create() failed", e);
}
mmSocket = tmp;
}
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
Log.i(TAG, "BEGIN mConnectThread");
setName("ConnectThread");
// Always cancel discovery because it will slow down a connection
mAdapter.cancelDiscovery();
// Make a connection to the BluetoothSocket
try {
// This is a blocking call and will only return on a
// successful connection or an exception
mmSocket.connect();
} catch (IOException e) {
connectionFailed();
// Close the socket
try {
mmSocket.close();
} catch (IOException e2) {
Log.e(TAG, "unable to close() socket during connection failure", e2);
}
// Start the service over to restart listening mode
//듣기 모드를 다시 시작 서비스를 다시 시작
BluetoothService.this.start();
return;
}
// Reset the ConnectThread because we're done
synchronized (BluetoothService.this) {
mConnectThread = null;
}
// Start the connected thread
//원격 블루투스 장치에 연결 되었을때 사용하는 스레드를 기동하는 메소드를 호출한다
connected(mmSocket, mmDevice);
}
public void cancel(){
try{
mmSocket.close();
}catch(IOException e){
Log.e(TAG, "cloase() of connect socket failed ", e);
}
}
}
private class ConnectedThread extends Thread{
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutputStream;
public ConnectedThread(BluetoothSocket socket) {
// TODO Auto-generated constructor stub
Log.d(TAG, "create ConnectedThread");
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try{
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
// isConnected = true;
}catch (IOException e){
Log.e(TAG, "temp sockets not created", e);
}
mmInStream = tmpIn;
mmOutputStream = tmpOut;
}
@Override
public void run() {
// TODO Auto-generated method stub
super.run();
Message msg1 = mHandler.obtainMessage(btService.MESSAGE_TOAST);
Bundle bundle1= new Bundle();
bundle1.putString(btService.TOAST, "run() : 함수 진입!!!!!!!!!!!!!!!!!!! " );
msg1.setData(bundle1);
mHandler.sendMessage(msg1);
byte[] buffer = new byte[1024];
int bytes;
while(true){
try{
bytes = mmInStream.read(buffer);
mHandler.obtainMessage(btService.MESSAGE_READ, bytes, -1, buffer).sendToTarget();
}catch(IOException e){
Log.e(TAG, " Exception during write", e);
connectionLost();
}
}
}
private void write(byte[] buffer) {
// TODO Auto-generated method stub
try{
mmOutputStream.write(buffer);
mHandler.obtainMessage(btService.MESSAGE_WRITE, -1, -1, buffer).sendToTarget();
}catch(IOException e){
Log.e(TAG, "Exception during write", e);
}
}
private void cancel() {
// TODO Auto-generated method stub
try{
mmSocket.close();
}catch(IOException e){
Log.e(TAG, "Close() of connect socket failed", e);
}
}
}
}
앱이 서비스랑 같이 쓰고 있는데 서비스 부분은 올리지 않았습니다.
스레드 생성하는데 혹시 서비스에서 제약을 받을 수 있는지도 궁금합니다.
mConnectedThread = new ConnectedThread(socket);
mConnectedThread.start(); /// 여기에서 문제 발생!!!!!!
일단 mConnectedThread 생성은 확실하게 되었는데
start가 되지 않아 mConnectedThread.run() 으로 해보니 run 함수는 호출이 되구요
아무래도 스레드가 생성 되지 않는것 같은데 원인을 알 수 있을까요?
ㅠㅠ 이부분만 해결 되면 끝인데; 원인을 찾을수가 없네요
답변기다리겠습니다.
mmConnectedThread.start() 가 실행이 되지 않고, 앱이 죽습니다. 예상치 못한 에러발생이라면서요 그리고 스레드 생성에 대해서는 충분히 알고 있구요 run() 함수를 호출 해본건 님 말대로 run()함수 안에서 문제가 발생 햇는지 확인 하기 위해서 였습니다. 제가 내린 결론은 스레드 pid 가 생성이 되지 않는 것으로 보이는데 혹여나 제가 작성을 잘 못 했나 싶어서요;;
블루투스 통신후에 이루어지는 것이라 로그캣으로 어떻게 살피는지? 직접 폰에 넣어서 해보고 있거든요;;
휴대폰에서 로그캣 볼수 있나요?




쓰레드는 run()으로 호출하시면 안됩니다. 쓰레드 생성 메커니즘을 공부하세요.
글이 너무 길어서 읽지는 못하겠고 일단 어디서 죽는지 알아야 하는데
ConnectedThread에서 죽는다고 하셨으니까 ConnectedThread의 run() 함수 진입점부터 시작해서 중간중간 Log를 박아 넣은 다음
어디서 죽는지부터 확인하세요. 아니면 로그캣을 살펴보셔도 되구요.
앱이 그냥 죽는 건 없습니다. 로그캣에 다 나와요.