本來想自己寫一個藍牙聊天的程序的,可是看了好幾天官方提供的源碼,真的看得想哭,真的太蛋筒了,終於明白,基礎差,在做稍微複雜寫的程序的時候,就能看出自己的不足,就有瓶頸。從這個藍牙開發來說,可以說是我做這個Android以來遇到的第一個比較頭痛的問題,但是由於項目要用到藍牙,所以這些天只能硬着皮頭看下去,不得不說,越看,學到的東西越多,但是我也不能一一說出來,但是,不得不說,任然還有不懂的地方。尤其是多線程那一塊,一定要重新認真看。不得不說,這個程序,給我了很大的刺激,讓我明白,我還有太多要學習的。
我這裏把我這幾天看的,然後今天整理的官方的程序寫上了我自己的註釋,不是很多,但是最主要的是,我把程序的部分調序了,因爲我覺得這是一個理解問題,就是按照什麼樣的順序和思路來設計程序的。這樣調序,可以很方便理解。但是,我不能保證我的理解思路就是適合別人的,但是至少適合我。還有就是service裏面的幾個線程的程序,我沒有註釋,因爲真的不知道怎麼註釋比較好,不想直接翻譯他提供的英語。
我依次說下他這三個代碼的思路吧,我覺得第一個DeviceListActivity這個是最容易理解的,也是思路最明確的,內容也最少。大的方面就是兩點,一個是顯示本地已配對設備;二是顯示搜索到的設備。先說第一個,顯示本地已配對設備就直接通過一個set集合把pairedDevices遍歷一遍,然後顯示在listview裏面。第二個稍微複雜點,因爲要先查找,然後再顯示出來。查找直接用startDiscovery就可以了。至於顯示就比較麻煩,因爲查找的過程是查找一個就發送一個廣播,然後繼續查找,直到查找結束。這就有一個問題,怎麼把查找到一個就顯示出一個呢?這就要用到BroadcastReceiver,這裏要設置兩個過濾器,用來處理不同的廣播,一個是用來處理查找到新設備的廣播,一個是用來處理結束查找的廣播。第一個廣播是最重要的,就是查到一個,通過這個過濾器,然後如果是這個廣播,就執行顯示操作。不過這裏顯示有兩部分,一個是顯示name,一個是MAC地址。不過這還麼有完,因爲你只是顯示在listview裏面了,但是你還要設置listview的選項監聽器,因爲我們要能選擇一個設備,然後就進行和設備的配對,至於怎麼配對待會再說,這裏要能響應,然後把MAC地址返回到BluetoothChat這個activity裏面,然後執行配對。所以這裏使用的是setResult,把Intent的內容傳回到主activity。這就是這個DeviceListActivity的全部功能。
接下來說BluetoothChat這個activity。總的來說是一下幾個步驟,檢測藍牙,藍牙是否打開,藍牙的可被檢測性,建立連接,開始聊天服務,但是有一個是貫穿整個流程的,就是UI的動態更新。藍牙的檢測和打開,可被檢測這都很簡單,不多說了。主要是怎麼建立連接,這個要在service裏面說;這個activity最最主要的有兩點,一個是把信息顯示在在listview上,就是發送和接收到的信息都要顯示出來,這個其實也是在service的connectedThread裏面做的,但是顯示部分是在這個裏面,service裏只是通過handler把信息傳給這個activity,BluetoothChat這個activity只是負責顯示。另外一點就是連接狀態的顯示,分爲四個狀態,沒有操作,連接中,連接了,和接收監聽,我這個翻譯也許不準確,但是應該能理解這四個狀態,不過你從顯示上看,只能看到三個,而監聽這個是看不出來的。這四個狀態也是通過handler傳遞信息,然後顯示在狀態欄的。其實這裏面最難的就是這個handler的使用,因爲他有兩個功能,就是上面兩類信息的顯示。而第二類的顯示就是所謂的UI的更新,也就是界面裏能看到的動態listview和textview的顯示。不過我也不能一下子說清楚這個handler,(我也還在學習中),所以希望我們都能好好學習,嘻嘻。。。
最後要說的就是這個service,也是最複雜的部分,其實這部分之所以複雜,主要是用到多線程,因爲,這裏面的很多方法都是阻塞線程的。大體上來說,我也只是說我知道的,這個服務,就是建立連接,那麼中間有那些可能性呢?connect,connectionFailed,connected,connectionLost。而這四種可能性我想大家也都可以有自己的理解,我的理解就是,第一個是連接兩個設備,第二個是連接失敗,第三個是連接成功了,第四個也是連接失敗,不過這個和第二個的區別在於,這個的前一狀態是第三個,而不是第一個。由這四個引出的是兩個線程,也是最重要的線程,ConnectThread和ConnectedThread,第一個是用來建立連接的,第二個是已經連接了,處理的是連接中的事,主要是兩點,一個是收發信息,一個是如果發生connectionLost怎麼辦。而第一個建立連接是通過createRfcommSocketToServiceRecord方法來實現的。但是我們前面說到了這裏有三個線程,還有一個是AcceptThread,這是一個監聽socket的線程,用來查看有沒有連接請求,我對他的理解是,他要監聽的是剛纔連接時說到的那個方法的UUID,然後進行連接。然後返回的是一個socket。這裏還有的就是UI的更新,這裏用到的是state的設置,然後通過handler把這個state返回去,然後更新UI。
好吧,這就是我能理解的部分,還有就是把我的註釋的給展示出來吧。至於以後用到藍牙的部分,以後再更新吧。
這是這個月最後一更了,這個月本來這應該是最有價值的一篇文章,結果,水平太菜了,沒辦法,只能做到這裏,五一回家玩玩吧,放鬆下。。。
DeviceListActivity.java
package com.example.bluetooth;
import java.util.Set;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.TextView;
public class DeviceListActivity extends Activity {
private BluetoothAdapter mBtAdapter;
private ArrayAdapter<String> mPairedDevicesArrayAdapter;
private ArrayAdapter<String> mNewDevicesArrayAdapter;
public static String EXTRA_DEVICE_ADDRESS = "device_address";
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
//這裏設置窗體爲不確定進度,因爲有progressbar
requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
setContentView(R.layout.device_list);
//setResult(Activity.RESULT_CANCELED);
Button scanButton = (Button) findViewById(R.id.button_scan);
scanButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
doDiscovery();
v.setVisibility(View.GONE);
}
});
mPairedDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
mNewDevicesArrayAdapter = new ArrayAdapter<String>(this, R.layout.device_name);
ListView pairedListView = (ListView) findViewById(R.id.paired_devices);
pairedListView.setAdapter(mPairedDevicesArrayAdapter);
pairedListView.setOnItemClickListener(mDeviceClickListener);
ListView newDevicesListView = (ListView) findViewById(R.id.new_devices);
newDevicesListView.setAdapter(mNewDevicesArrayAdapter);
newDevicesListView.setOnItemClickListener(mDeviceClickListener);
//註冊兩個過濾器,用來接收兩個廣播,一個是搜索到一個可用設備,一個是結束搜索
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
this.registerReceiver(mReceiver, filter);
filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
this.registerReceiver(mReceiver, filter);
//獲取本地藍牙適配器,把本地已配對設備顯示出來
mBtAdapter = BluetoothAdapter.getDefaultAdapter();
Set<BluetoothDevice> pairedDevices = mBtAdapter.getBondedDevices();
if (pairedDevices.size() > 0) {
findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
for (BluetoothDevice device : pairedDevices) {
mPairedDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
} else {
String noDevices = getResources().getText(R.string.none_paired).toString();
mPairedDevicesArrayAdapter.add(noDevices);
}
}
//搜索
private void doDiscovery(){
//設置顯示
setProgressBarIndeterminateVisibility(true);
setTitle(R.string.scanning);
findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);
//如果正在搜索,取消正在搜索
if (mBtAdapter.isDiscovering()) {
mBtAdapter.cancelDiscovery();
}
//開始搜索
mBtAdapter.startDiscovery();
}
//監聽器
private OnItemClickListener mDeviceClickListener = new OnItemClickListener(){
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
// TODO Auto-generated method stub
mBtAdapter.cancelDiscovery();
//獲取內容,然後把後面17位的MAC地址取出來,連接只需要MAC地址
String info = ((TextView) arg1).getText().toString();
String address = info.substring(info.length() - 17);
//把MAC地址傳回到主activity,調用setResult在finish之前傳回值
Intent intent = new Intent();
intent.putExtra(EXTRA_DEVICE_ADDRESS, address);
setResult(Activity.RESULT_OK, intent);
finish();
}};
//註冊一個廣播接收,兩個不同的接收給出不同的動作
private final BroadcastReceiver mReceiver = new BroadcastReceiver(){
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
String action = intent.getAction();
if(BluetoothDevice.ACTION_FOUND.equals(action))
{
//把新發現的設備顯示出來
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
if (device.getBondState() != BluetoothDevice.BOND_BONDED)
{
mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
}else if(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action))
{
setProgressBarIndeterminateVisibility(false);
setTitle(R.string.select_device);
if (mNewDevicesArrayAdapter.getCount() == 0)
{
String noDevices = getResources().getText(R.string.none_found).toString();
mNewDevicesArrayAdapter.add(noDevices);
}
}
}};
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
if (mBtAdapter != null)
{
mBtAdapter.cancelDiscovery();
}
//廣播要取消註冊,防止內存泄漏
this.unregisterReceiver(mReceiver);
}
}
BluetoothChat.java
package com.example.bluetooth;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.app.ActionBar;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.Intent;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.inputmethod.EditorInfo;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
public class BluetoothChat extends Activity {
//handler處理
public static final int MESSAGE_STATE_CHANGE = 1;
public static final int MESSAGE_READ = 2;
public static final int MESSAGE_WRITE = 3;
public static final int MESSAGE_DEVICE_NAME = 4;
public static final int MESSAGE_TOAST = 5;
public static final String DEVICE_NAME = "device_name";
public static final String TOAST = "toast";
private static final int REQUEST_CONNECT_DEVICE_SECURE = 1;
private static final int REQUEST_CONNECT_DEVICE_INSECURE = 2;
private static final int REQUEST_ENABLE_BT = 3;
private BluetoothAdapter mBluetoothAdapter = null;
private BluetoothChatService mChatService = null;
private ArrayAdapter<String> mConversationArrayAdapter;
private ListView mConversationView;
private EditText mOutEditText;
private Button mSendButton;
private StringBuffer mOutStringBuffer;
private String mConnectedDeviceName = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
//本地如果沒有藍牙,提示沒有藍牙
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null)
{
Toast.makeText(this, "沒有發現藍牙設備", Toast.LENGTH_LONG).show();
finish();
return;
}
//藍牙是否打開了,沒有的話,讓用戶選擇是否打開
if (!mBluetoothAdapter.isEnabled()) {
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, RESULT_FIRST_USER);
} else {
if (mChatService == null) setupChat();
}
}
//藍牙是否可以被檢測
private void ensureDiscoverable() {
// TODO Auto-generated method stub
if (mBluetoothAdapter.getScanMode() !=
BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
Intent discoverableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 300);
startActivity(discoverableIntent);
}
}
//信息顯示
private void setupChat() {
// TODO Auto-generated method stub
mConversationArrayAdapter = new ArrayAdapter<String>(this, R.layout.message);
mConversationView = (ListView) findViewById(R.id.in);
mConversationView.setAdapter(mConversationArrayAdapter);
mOutEditText = (EditText) findViewById(R.id.edit_text_out);
mOutEditText.setOnEditorActionListener(mWriteListener);
mSendButton = (Button) findViewById(R.id.button_send);
mSendButton.setOnClickListener(new OnClickListener() {
public void onClick(View v) {
// Send a message using content of the edit text widget
TextView view = (TextView) findViewById(R.id.edit_text_out);
String message = view.getText().toString();
sendMessage(message);
}
});
}
//EditText+Button響應,軟鍵盤設置
private TextView.OnEditorActionListener mWriteListener =
new TextView.OnEditorActionListener() {
public boolean onEditorAction(TextView view, int actionId, KeyEvent event) {
if (actionId == EditorInfo.IME_NULL && event.getAction() == KeyEvent.ACTION_UP) {
String message = view.getText().toString();
sendMessage(message);
}
return true;
}
};
//開始聊天服務
@Override
protected synchronized void onResume() {
// TODO Auto-generated method stub
super.onResume();
if (mChatService != null)
{
if (mChatService.getState() == BluetoothChatService.STATE_NONE)
{
mChatService.start();
}
}
}
protected void sendMessage(String message) {
// TODO Auto-generated method stub
//是否已經連接,沒有連接是不能發送信息的
if (mChatService.getState() != BluetoothChatService.STATE_CONNECTED)
{
Toast.makeText(this, R.string.not_connected, Toast.LENGTH_SHORT).show();
return;
}
//發送信息
if (message.length() > 0)
{
byte[] send = message.getBytes();
mChatService.write(send);
mOutStringBuffer.setLength(0);
mOutEditText.setText(mOutStringBuffer);
}
}
//停止服務
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
if (mChatService != null) mChatService.stop();
}
//設置當前連接狀態的顯示
private final void setStatus(int resId) {
final ActionBar actionBar = getActionBar();
actionBar.setSubtitle(resId);
}
private final void setStatus(CharSequence subTitle) {
final ActionBar actionBar = getActionBar();
actionBar.setSubtitle(subTitle);
}
//從BluetoothChatService中讀取message,更新UI顯示
private final Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MESSAGE_STATE_CHANGE:
switch (msg.arg1) {
case BluetoothChatService.STATE_CONNECTED:
setStatus(getString(R.string.title_connected_to, mConnectedDeviceName));
mConversationArrayAdapter.clear();
break;
case BluetoothChatService.STATE_CONNECTING:
setStatus(R.string.title_connecting);
break;
case BluetoothChatService.STATE_LISTEN:
case BluetoothChatService.STATE_NONE:
setStatus(R.string.title_not_connected);
break;
}
break;
case MESSAGE_WRITE:
byte[] writeBuf = (byte[]) msg.obj;
// 寫信息到緩存
String writeMessage = new String(writeBuf);
mConversationArrayAdapter.add("Me: " + writeMessage);
break;
case MESSAGE_READ:
byte[] readBuf = (byte[]) msg.obj;
// 從緩存中讀信息
String readMessage = new String(readBuf, 0, msg.arg1);
mConversationArrayAdapter.add(mConnectedDeviceName+": " + readMessage);
break;
case MESSAGE_DEVICE_NAME:
// 保存設備名稱
mConnectedDeviceName = msg.getData().getString(DEVICE_NAME);
Toast.makeText(getApplicationContext(), "Connected to "
+ mConnectedDeviceName, Toast.LENGTH_SHORT).show();
break;
case MESSAGE_TOAST:
//打印toast
Toast.makeText(getApplicationContext(), msg.getData().getString(TOAST),
Toast.LENGTH_SHORT).show();
break;
}
}
};
//DeviceActivity的結果返回響應
public void onActivityResult(int requestCode, int resultCode, Intent data) {
switch (requestCode) {
case REQUEST_CONNECT_DEVICE_SECURE:
// 返回結果是要求一個連接
if (resultCode == Activity.RESULT_OK) {
connectDevice(data, true);
}
break;
case REQUEST_CONNECT_DEVICE_INSECURE:
//
if (resultCode == Activity.RESULT_OK) {
connectDevice(data, false);
}
break;
case REQUEST_ENABLE_BT:
// 返回結果是要求打開藍牙
if (resultCode == Activity.RESULT_OK) {
setupChat();
} else {
Toast.makeText(this, R.string.bt_not_enabled_leaving, Toast.LENGTH_SHORT).show();
finish();
}
}
}
//連接設備
private void connectDevice(Intent data, boolean secure) {
String address = data.getExtras()
.getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
mChatService.connect(device, secure);
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// TODO Auto-generated method stub
Intent serverIntent = null;
switch (item.getItemId()) {
case R.id.secure_connect_scan:
// Launch the DeviceListActivity to see devices and do scan
serverIntent = new Intent(this, DeviceListActivity.class);
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_SECURE);
return true;
case R.id.insecure_connect_scan:
// Launch the DeviceListActivity to see devices and do scan
serverIntent = new Intent(this, DeviceListActivity.class);
startActivityForResult(serverIntent, REQUEST_CONNECT_DEVICE_INSECURE);
return true;
case R.id.discoverable:
// Ensure this device is discoverable by others
ensureDiscoverable();
return true;
}
return false;
}
}
BluetoothChatService.java
package com.example.bluetooth;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.UUID;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Context;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
public class BluetoothChatService {
private final BluetoothAdapter mAdapter;
private final Handler mHandler;
private AcceptThread mSecureAcceptThread;
private AcceptThread mInsecureAcceptThread;
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
private static final String NAME_SECURE = "BluetoothChatSecure";
private static final String NAME_INSECURE = "BluetoothChatInsecure";
private static final UUID MY_UUID_SECURE =
UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");
private static final UUID MY_UUID_INSECURE =
UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66");
//設置UI的狀態
private int mState;
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 BluetoothChatService(Context context, Handler handler) {
mAdapter = BluetoothAdapter.getDefaultAdapter();
//UI的動態顯示,顯示的是狀態
mState = STATE_NONE;
//信息的處理線程
mHandler = handler;
}
public int getState() {
// TODO Auto-generated method stub
return mState;
}
//改變UI的狀態顯示
private void setState(int stateListen) {
// TODO Auto-generated method stub
mState = stateListen;
mHandler.obtainMessage(BluetoothChat.MESSAGE_STATE_CHANGE, stateListen, -1).sendToTarget();
}
//建立設備之間的連接
public void connect(BluetoothDevice device, boolean secure) {
// TODO Auto-generated method stub
if (mState == STATE_CONNECTING)
{
if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
}
if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
mConnectThread = new ConnectThread(device, secure);
mConnectThread.start();
setState(STATE_CONNECTING);
}
//連接失敗的提示
private void connectionFailed() {
// 把連接失敗顯示在UI上
Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(BluetoothChat.TOAST, "Unable to connect device");
msg.setData(bundle);
mHandler.sendMessage(msg);
// 重新開始服務
BluetoothChatService.this.start();
}
//連接已建立,保持連接
public synchronized void connected(BluetoothSocket socket, BluetoothDevice
device, final String socketType) {
if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
if (mSecureAcceptThread != null)
{
mSecureAcceptThread.cancel();
mSecureAcceptThread = null;
}
if (mInsecureAcceptThread != null) {
mInsecureAcceptThread.cancel();
mInsecureAcceptThread = null;
}
mConnectedThread = new ConnectedThread(socket, socketType);
mConnectedThread.start();
// 在UI上把當前連接的設備名顯示出來
Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_DEVICE_NAME);
Bundle bundle = new Bundle();
bundle.putString(BluetoothChat.DEVICE_NAME, device.getName());
msg.setData(bundle);
mHandler.sendMessage(msg);
setState(STATE_CONNECTED);
}
//連接中斷
private void connectionLost() {
// 連接如果中斷了,就在UI上提示
Message msg = mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST);
Bundle bundle = new Bundle();
bundle.putString(BluetoothChat.TOAST, "Device connection was lost");
msg.setData(bundle);
mHandler.sendMessage(msg);
// 重新開始服務
BluetoothChatService.this.start();
}
//開始聊天服務
public void start() {
// TODO Auto-generated method stub
if (mConnectThread != null) {mConnectThread.cancel(); mConnectThread = null;}
if (mConnectedThread != null) {mConnectedThread.cancel(); mConnectedThread = null;}
setState(STATE_LISTEN);
// 開始監聽socket
if (mSecureAcceptThread == null) {
mSecureAcceptThread = new AcceptThread(true);
mSecureAcceptThread.start();
}
}
//停止服務
public void stop() {
// TODO Auto-generated method stub
if (mConnectThread != null)
{
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null)
{
mConnectedThread.cancel();
mConnectedThread = null;
}
if (mSecureAcceptThread != null)
{
mSecureAcceptThread.cancel();
mSecureAcceptThread = null;
}
if (mInsecureAcceptThread != null) {
mInsecureAcceptThread.cancel();
mInsecureAcceptThread = null;
}
setState(STATE_NONE);
}
//監聽連接請求線程
private class AcceptThread extends Thread{
//本地socket
private final BluetoothServerSocket mmServerSocket;
private String mSocketType;
public AcceptThread(boolean secure){
BluetoothServerSocket tmp = null;
mSocketType = secure ? "Secure":"Insecure";
// 創建一個新的服務socket
try {
if (secure) {
tmp = mAdapter.listenUsingRfcommWithServiceRecord(NAME_SECURE,
MY_UUID_SECURE);
} else {
tmp = mAdapter.listenUsingInsecureRfcommWithServiceRecord(
NAME_INSECURE, MY_UUID_INSECURE);
}
} catch (IOException e) {
}
mmServerSocket = tmp;
}
public void run() {
setName("AcceptThread" + mSocketType);
BluetoothSocket socket = null;
//沒有建立連接
while (mState != STATE_CONNECTED) {
try {
socket = mmServerSocket.accept();
} catch (IOException e) {
break;
}
// 建立了連接
if (socket != null) {
synchronized (BluetoothChatService.this) {
switch (mState) {
case STATE_LISTEN:
case STATE_CONNECTING:
connected(socket, socket.getRemoteDevice(),
mSocketType);
break;
case STATE_NONE:
case STATE_CONNECTED:
try {
socket.close();
} catch (IOException e) {
}
break;
}
}
}
}
}
public void cancel() {
try {
mmServerSocket.close();
} catch (IOException e) {
}
}
}
//連接線程
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
private String mSocketType;
public ConnectThread(BluetoothDevice device, boolean secure) {
mmDevice = device;
BluetoothSocket tmp = null;
mSocketType = secure ? "Secure" : "Insecure";
//連接
try {
if (secure) {
tmp = device.createRfcommSocketToServiceRecord(
MY_UUID_SECURE);
} else {
tmp = device.createInsecureRfcommSocketToServiceRecord(
MY_UUID_INSECURE);
}
} catch (IOException e) {
}
mmSocket = tmp;
}
public void run() {
setName("ConnectThread" + mSocketType);
mAdapter.cancelDiscovery();
//連接到BluetoothSocket
try {
mmSocket.connect();
} catch (IOException e) {
try {
mmSocket.close();
} catch (IOException e2) {
}
connectionFailed();
return;
}
// 取消連接線程
synchronized (BluetoothChatService.this) {
mConnectThread = null;
}
// 開始連接線程
connected(mmSocket, mmDevice, mSocketType);
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
}
}
}
//已連接線程,通過這個線程發送和接收數據
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
//初始化
public ConnectedThread(BluetoothSocket socket, String socketType){
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
try {
//得到輸入輸出數據流
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
//讀
public void run(){
byte[] buffer = new byte[1024];
int bytes;
//長連接
while (true) {
try {
bytes = mmInStream.read(buffer);
// 把信息反饋給UI界面顯示出來
mHandler.obtainMessage(BluetoothChat.MESSAGE_READ, bytes, -1, buffer)
.sendToTarget();
} catch (IOException e) {
connectionLost();
// 重新開始服務
BluetoothChatService.this.start();
break;
}
}
}
//寫
public void write(byte[] buffer) {
try {
mmOutStream.write(buffer);
mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE, -1, -1, buffer)
.sendToTarget();
} catch (IOException e) {
}
}
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) {
}
}
}
//寫接口
public void write(byte[] send) {
// TODO Auto-generated method stub
ConnectedThread r;
synchronized (this) {
if (mState != STATE_CONNECTED) return;
r = mConnectedThread;
}
r.write(send);
}
}