`
xiaoheliushuiya
  • 浏览: 399996 次
文章分类
社区版块
存档分类
最新评论

Android 蓝牙开发实例--蓝牙聊天程序的设计和实现 Android 蓝牙开发实例--蓝牙聊天程序的设计和实现

 
阅读更多

Android 蓝牙开发实例--蓝牙聊天程序的设计和实现


转自:http://blog.csdn.net/dlutbrucezhang/article/details/8963696

作者在这里介绍的这个实例是Google SDK中提供的一个蓝牙聊天程序,简单但信息量巨大,非常适合初学者学习蓝牙方面的知识。

在学习这个实例前请读者仔细阅读并理解Socket的工作原理和实现机制,作者的这篇博客中有详细的介绍:

http://blog.csdn.net/dlutbrucezhang/article/details/8577810


在Android1.x的时候,相关API非常不完善,还不能简单的使用Bluetooth开发,有一个开源项目可以帮助程序员使用、开发蓝牙,支持直接方法bluetooth协议栈。在Android2以后,框架提供了一些官方API来进行蓝牙的通信,但目前的程序也比较不完善。本文主要讨论Android2后的Bluetooth通信的API使用方法。

首先看聊天室的效果图:




蓝牙设备连接的过程如下图所示:



下面这张图展示的是蓝牙聊天的时序图:



接下来将贴出源码并对源码做出详细的解释说明:

BluetoothChat.java

例程的主Activity。onCreate()得到本地BluetoothAdapter设备,检查是否支持。onStart()中检查是否启用蓝牙,并请求启用,然后执行setupChat()。setupChat()中先对界面中的控件进行初始化增加点击监听器等,然创建BluetoothChatService对象,该对象在整个应用过程中存在,并执行蓝牙连接建立、消息发送接受等实际的行为。

  1. importandroid.app.Activity;
  2. importandroid.bluetooth.BluetoothAdapter;
  3. importandroid.bluetooth.BluetoothDevice;
  4. importandroid.content.Intent;
  5. importandroid.os.Bundle;
  6. importandroid.os.Handler;
  7. importandroid.os.Message;
  8. importandroid.util.Log;
  9. importandroid.view.KeyEvent;
  10. importandroid.view.Menu;
  11. importandroid.view.MenuInflater;
  12. importandroid.view.MenuItem;
  13. importandroid.view.View;
  14. importandroid.view.Window;
  15. importandroid.view.View.OnClickListener;
  16. importandroid.view.inputmethod.EditorInfo;
  17. importandroid.widget.ArrayAdapter;
  18. importandroid.widget.Button;
  19. importandroid.widget.EditText;
  20. importandroid.widget.ListView;
  21. importandroid.widget.TextView;
  22. importandroid.widget.Toast;
  23. /**
  24. *ThisisthemainActivitythatdisplaysthecurrentchatsession.
  25. */
  26. publicclassBluetoothChatextendsActivity{
  27. //Debugging
  28. privatestaticfinalStringTAG="BluetoothChat";
  29. privatestaticfinalbooleanD=true;
  30. //MessagetypessentfromtheBluetoothChatServiceHandler
  31. publicstaticfinalintMESSAGE_STATE_CHANGE=1;
  32. publicstaticfinalintMESSAGE_READ=2;
  33. publicstaticfinalintMESSAGE_WRITE=3;
  34. publicstaticfinalintMESSAGE_DEVICE_NAME=4;
  35. publicstaticfinalintMESSAGE_TOAST=5;
  36. //KeynamesreceivedfromtheBluetoothChatServiceHandler
  37. publicstaticfinalStringDEVICE_NAME="device_name";
  38. publicstaticfinalStringTOAST="toast";
  39. //Intentrequestcodes
  40. privatestaticfinalintREQUEST_CONNECT_DEVICE=1;
  41. privatestaticfinalintREQUEST_ENABLE_BT=2;
  42. //LayoutViews
  43. privateTextViewmTitle;
  44. privateListViewmConversationView;
  45. privateEditTextmOutEditText;
  46. privateButtonmSendButton;
  47. //Nameoftheconnecteddevice
  48. privateStringmConnectedDeviceName=null;
  49. //Arrayadapterfortheconversationthread
  50. privateArrayAdapter<String>mConversationArrayAdapter;
  51. //Stringbufferforoutgoingmessages
  52. privateStringBuffermOutStringBuffer;
  53. //LocalBluetoothadapter
  54. privateBluetoothAdaptermBluetoothAdapter=null;
  55. //Memberobjectforthechatservices
  56. privateBluetoothChatServicemChatService=null;
  57. @Override
  58. publicvoidonCreate(BundlesavedInstanceState){
  59. super.onCreate(savedInstanceState);
  60. if(D)Log.e(TAG,"+++ONCREATE+++");
  61. //Setupthewindowlayout
  62. requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
  63. setContentView(R.layout.main);
  64. getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,R.layout.custom_title);
  65. //Setupthecustomtitle
  66. mTitle=(TextView)findViewById(R.id.title_left_text);
  67. mTitle.setText(R.string.app_name);
  68. mTitle=(TextView)findViewById(R.id.title_right_text);
  69. //GetlocalBluetoothadapter
  70. mBluetoothAdapter=BluetoothAdapter.getDefaultAdapter();
  71. //Iftheadapterisnull,thenBluetoothisnotsupported
  72. if(mBluetoothAdapter==null){
  73. Toast.makeText(this,"Bluetoothisnotavailable",Toast.LENGTH_LONG).show();
  74. finish();
  75. return;
  76. }
  77. }
  78. @Override
  79. publicvoidonStart(){
  80. super.onStart();
  81. if(D)Log.e(TAG,"++ONSTART++");
  82. //IfBTisnoton,requestthatitbeenabled.
  83. //setupChat()willthenbecalledduringonActivityResult
  84. if(!mBluetoothAdapter.isEnabled()){
  85. IntentenableIntent=newIntent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
  86. startActivityForResult(enableIntent,REQUEST_ENABLE_BT);
  87. //Otherwise,setupthechatsession
  88. }else{
  89. if(mChatService==null)setupChat();
  90. }
  91. }
  92. @Override
  93. publicsynchronizedvoidonResume(){
  94. super.onResume();
  95. if(D)Log.e(TAG,"+ONRESUME+");
  96. //PerformingthischeckinonResume()coversthecaseinwhichBTwas
  97. //notenabledduringonStart(),sowewerepausedtoenableit...
  98. //onResume()willbecalledwhenACTION_REQUEST_ENABLEactivityreturns.
  99. if(mChatService!=null){
  100. //OnlyifthestateisSTATE_NONE,doweknowthatwehaven'tstartedalready
  101. if(mChatService.getState()==BluetoothChatService.STATE_NONE){
  102. //StarttheBluetoothchatservices
  103. mChatService.start();
  104. }
  105. }
  106. }
  107. privatevoidsetupChat(){
  108. Log.d(TAG,"setupChat()");
  109. //Initializethearrayadapterfortheconversationthread
  110. mConversationArrayAdapter=newArrayAdapter<String>(this,R.layout.message);
  111. mConversationView=(ListView)findViewById(R.id.in);
  112. mConversationView.setAdapter(mConversationArrayAdapter);
  113. //Initializethecomposefieldwithalistenerforthereturnkey
  114. mOutEditText=(EditText)findViewById(R.id.edit_text_out);
  115. mOutEditText.setOnEditorActionListener(mWriteListener);
  116. //Initializethesendbuttonwithalistenerthatforclickevents
  117. mSendButton=(Button)findViewById(R.id.button_send);
  118. mSendButton.setOnClickListener(newOnClickListener(){
  119. publicvoidonClick(Viewv){
  120. //Sendamessageusingcontentoftheedittextwidget
  121. TextViewview=(TextView)findViewById(R.id.edit_text_out);
  122. Stringmessage=view.getText().toString();
  123. sendMessage(message);
  124. }
  125. });
  126. //InitializetheBluetoothChatServicetoperformbluetoothconnections
  127. mChatService=newBluetoothChatService(this,mHandler);
  128. //Initializethebufferforoutgoingmessages
  129. mOutStringBuffer=newStringBuffer("");
  130. }
  131. @Override
  132. publicsynchronizedvoidonPause(){
  133. super.onPause();
  134. if(D)Log.e(TAG,"-ONPAUSE-");
  135. }
  136. @Override
  137. publicvoidonStop(){
  138. super.onStop();
  139. if(D)Log.e(TAG,"--ONSTOP--");
  140. }
  141. @Override
  142. publicvoidonDestroy(){
  143. super.onDestroy();
  144. //StoptheBluetoothchatservices
  145. if(mChatService!=null)mChatService.stop();
  146. if(D)Log.e(TAG,"---ONDESTROY---");
  147. }
  148. privatevoidensureDiscoverable(){
  149. if(D)Log.d(TAG,"ensurediscoverable");
  150. if(mBluetoothAdapter.getScanMode()!=
  151. BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE){
  152. IntentdiscoverableIntent=newIntent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
  153. discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,300);
  154. startActivity(discoverableIntent);
  155. }
  156. }
  157. /**
  158. *Sendsamessage.
  159. *@parammessageAstringoftexttosend.
  160. */
  161. privatevoidsendMessage(Stringmessage){
  162. //Checkthatwe'reactuallyconnectedbeforetryinganything
  163. if(mChatService.getState()!=BluetoothChatService.STATE_CONNECTED){
  164. Toast.makeText(this,R.string.not_connected,Toast.LENGTH_SHORT).show();
  165. return;
  166. }
  167. //Checkthatthere'sactuallysomethingtosend
  168. if(message.length()>0){
  169. //GetthemessagebytesandtelltheBluetoothChatServicetowrite
  170. byte[]send=message.getBytes();
  171. mChatService.write(send);
  172. //Resetoutstringbuffertozeroandcleartheedittextfield
  173. mOutStringBuffer.setLength(0);
  174. mOutEditText.setText(mOutStringBuffer);
  175. }
  176. }
  177. //TheactionlistenerfortheEditTextwidget,tolistenforthereturnkey
  178. privateTextView.OnEditorActionListenermWriteListener=
  179. newTextView.OnEditorActionListener(){
  180. publicbooleanonEditorAction(TextViewview,intactionId,KeyEventevent){
  181. //Iftheactionisakey-upeventonthereturnkey,sendthemessage
  182. if(actionId==EditorInfo.IME_NULL&&event.getAction()==KeyEvent.ACTION_UP){
  183. Stringmessage=view.getText().toString();
  184. sendMessage(message);
  185. }
  186. if(D)Log.i(TAG,"ENDonEditorAction");
  187. returntrue;
  188. }
  189. };
  190. //TheHandlerthatgetsinformationbackfromtheBluetoothChatService
  191. privatefinalHandlermHandler=newHandler(){
  192. @Override
  193. publicvoidhandleMessage(Messagemsg){
  194. switch(msg.what){
  195. caseMESSAGE_STATE_CHANGE:
  196. if(D)Log.i(TAG,"MESSAGE_STATE_CHANGE:"+msg.arg1);
  197. switch(msg.arg1){
  198. caseBluetoothChatService.STATE_CONNECTED:
  199. mTitle.setText(R.string.title_connected_to);
  200. mTitle.append(mConnectedDeviceName);
  201. mConversationArrayAdapter.clear();
  202. break;
  203. caseBluetoothChatService.STATE_CONNECTING:
  204. mTitle.setText(R.string.title_connecting);
  205. break;
  206. caseBluetoothChatService.STATE_LISTEN:
  207. caseBluetoothChatService.STATE_NONE:
  208. mTitle.setText(R.string.title_not_connected);
  209. break;
  210. }
  211. break;
  212. caseMESSAGE_WRITE:
  213. byte[]writeBuf=(byte[])msg.obj;
  214. //constructastringfromthebuffer
  215. StringwriteMessage=newString(writeBuf);
  216. mConversationArrayAdapter.add("Me:"+writeMessage);
  217. break;
  218. caseMESSAGE_READ:
  219. byte[]readBuf=(byte[])msg.obj;
  220. //constructastringfromthevalidbytesinthebuffer
  221. StringreadMessage=newString(readBuf,0,msg.arg1);
  222. mConversationArrayAdapter.add(mConnectedDeviceName+":"+readMessage);
  223. break;
  224. caseMESSAGE_DEVICE_NAME:
  225. //savetheconnecteddevice'sname
  226. mConnectedDeviceName=msg.getData().getString(DEVICE_NAME);
  227. Toast.makeText(getApplicationContext(),"Connectedto"
  228. +mConnectedDeviceName,Toast.LENGTH_SHORT).show();
  229. break;
  230. caseMESSAGE_TOAST:
  231. Toast.makeText(getApplicationContext(),msg.getData().getString(TOAST),
  232. Toast.LENGTH_SHORT).show();
  233. break;
  234. }
  235. }
  236. };
  237. publicvoidonActivityResult(intrequestCode,intresultCode,Intentdata){
  238. if(D)Log.d(TAG,"onActivityResult"+resultCode);
  239. switch(requestCode){
  240. caseREQUEST_CONNECT_DEVICE:
  241. //WhenDeviceListActivityreturnswithadevicetoconnect
  242. if(resultCode==Activity.RESULT_OK){
  243. //GetthedeviceMACaddress
  244. Stringaddress=data.getExtras()
  245. .getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
  246. //GettheBLuetoothDeviceobject
  247. BluetoothDevicedevice=mBluetoothAdapter.getRemoteDevice(address);
  248. //Attempttoconnecttothedevice
  249. mChatService.connect(device);
  250. }
  251. break;
  252. caseREQUEST_ENABLE_BT:
  253. //WhentherequesttoenableBluetoothreturns
  254. if(resultCode==Activity.RESULT_OK){
  255. //Bluetoothisnowenabled,sosetupachatsession
  256. setupChat();
  257. }else{
  258. //UserdidnotenableBluetoothoranerroroccured
  259. Log.d(TAG,"BTnotenabled");
  260. Toast.makeText(this,R.string.bt_not_enabled_leaving,Toast.LENGTH_SHORT).show();
  261. finish();
  262. }
  263. }
  264. }
  265. @Override
  266. publicbooleanonCreateOptionsMenu(Menumenu){
  267. MenuInflaterinflater=getMenuInflater();
  268. inflater.inflate(R.menu.option_menu,menu);
  269. returntrue;
  270. }
  271. @Override
  272. publicbooleanonOptionsItemSelected(MenuItemitem){
  273. switch(item.getItemId()){
  274. caseR.id.scan:
  275. //LaunchtheDeviceListActivitytoseedevicesanddoscan
  276. IntentserverIntent=newIntent(this,DeviceListActivity.class);
  277. startActivityForResult(serverIntent,REQUEST_CONNECT_DEVICE);
  278. returntrue;
  279. caseR.id.discoverable:
  280. //Ensurethisdeviceisdiscoverablebyothers
  281. ensureDiscoverable();
  282. returntrue;
  283. }
  284. returnfalse;
  285. }
  286. }

BluetoothChatService.java

public synchronized void start():

开启mAcceptThread线程,由于样例程序是仅2人的聊天过程,故之前先检测mConnectThread和mConnectedThread是否运行,运行则先退出这些线程。

public synchronized voidconnect(BluetoothDevice device):

取消CONNECTING和CONNECTED状态下的相关线程,然后运行新的mConnectThread线程。

public synchronized voidconnected(BluetoothSocket socket, BluetoothDevice device):

开启一个ConnectedThread来管理对应的当前连接。之前先取消任意现存的mConnectThread、mConnectedThread、mAcceptThread线程,然后开启新mConnectedThread,传入当前刚刚接受的socket连接。最后通过Handler来通知UI连接OK。

public synchronized void stop():

停止所有相关线程,设当前状态为NONE。

public void write(byte[] out):

在STATE_CONNECTED状态下,调用mConnectedThread里的write方法,写入byte。

private void connectionFailed():

连接失败的时候处理,通知ui,并设为STATE_LISTEN状态。

private void connectionLost():

当连接失去的时候,设为STATE_LISTEN状态并通知ui。

内部类:

private class AcceptThread extendsThread:

创建监听线程,准备接受新连接。使用阻塞方式,调用BluetoothServerSocket.accept()。提供cancel方法关闭socket。

private class ConnectThread extendsThread:

这是定义的连接线程,专门用来对外发出连接对方蓝牙的请求和处理流程。构造函数里通过BluetoothDevice.createRfcommSocketToServiceRecord(),从待连接的device产生BluetoothSocket.然后在run方法中connect,成功后调用BluetoothChatSevice的connected()方法。定义cancel()在关闭线程时能够关闭相关socket。

private class ConnectedThread extendsThread:

这个是双方蓝牙连接后一直运行的线程。构造函数中设置输入输出流。Run方法中使用阻塞模式的InputStream.read()循环读取输入流,然后post到UI线程中更新聊天消息。也提供了write()将聊天消息写入输出流传输至对方,传输成功后回写入UI线程。最后cancel()关闭连接的socket。

  1. importjava.io.IOException;
  2. importjava.io.InputStream;
  3. importjava.io.OutputStream;
  4. importjava.util.UUID;
  5. importandroid.annotation.SuppressLint;
  6. importandroid.bluetooth.BluetoothAdapter;
  7. importandroid.bluetooth.BluetoothDevice;
  8. importandroid.bluetooth.BluetoothServerSocket;
  9. importandroid.bluetooth.BluetoothSocket;
  10. importandroid.content.Context;
  11. importandroid.os.Bundle;
  12. importandroid.os.Handler;
  13. importandroid.os.Message;
  14. importandroid.util.Log;
  15. /**
  16. *ThisclassdoesalltheworkforsettingupandmanagingBluetooth
  17. *connectionswithotherdevices.Ithasathreadthatlistensfor
  18. *incomingconnections,athreadforconnectingwithadevice,anda
  19. *threadforperformingdatatransmissionswhenconnected.
  20. */
  21. @SuppressLint("NewApi")
  22. publicclassBluetoothChatService{
  23. //Debugging
  24. privatestaticfinalStringTAG="BluetoothChatService";
  25. privatestaticfinalbooleanD=true;
  26. //NamefortheSDPrecordwhencreatingserversocket
  27. privatestaticfinalStringNAME="BluetoothChat";
  28. //UniqueUUIDforthisapplication
  29. privatestaticfinalUUIDMY_UUID=UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");
  30. //Memberfields
  31. privatefinalBluetoothAdaptermAdapter;
  32. privatefinalHandlermHandler;
  33. privateAcceptThreadmAcceptThread;
  34. privateConnectThreadmConnectThread;
  35. privateConnectedThreadmConnectedThread;
  36. privateintmState;
  37. //Constantsthatindicatethecurrentconnectionstate
  38. publicstaticfinalintSTATE_NONE=0;//we'redoingnothing
  39. publicstaticfinalintSTATE_LISTEN=1;//nowlisteningforincomingconnections
  40. publicstaticfinalintSTATE_CONNECTING=2;//nowinitiatinganoutgoingconnection
  41. publicstaticfinalintSTATE_CONNECTED=3;//nowconnectedtoaremotedevice
  42. /**
  43. *Constructor.PreparesanewBluetoothChatsession.
  44. *@paramcontextTheUIActivityContext
  45. *@paramhandlerAHandlertosendmessagesbacktotheUIActivity
  46. */
  47. publicBluetoothChatService(Contextcontext,Handlerhandler){
  48. mAdapter=BluetoothAdapter.getDefaultAdapter();
  49. mState=STATE_NONE;
  50. mHandler=handler;
  51. }
  52. /**
  53. *Setthecurrentstateofthechatconnection
  54. *@paramstateAnintegerdefiningthecurrentconnectionstate
  55. */
  56. privatesynchronizedvoidsetState(intstate){
  57. if(D)Log.d(TAG,"setState()"+mState+"->"+state);
  58. mState=state;
  59. //GivethenewstatetotheHandlersotheUIActivitycanupdate
  60. mHandler.obtainMessage(BluetoothChat.MESSAGE_STATE_CHANGE,state,-1).sendToTarget();
  61. }
  62. /**
  63. *Returnthecurrentconnectionstate.*/
  64. publicsynchronizedintgetState(){
  65. returnmState;
  66. }
  67. /**
  68. *Startthechatservice.SpecificallystartAcceptThreadtobegina
  69. *sessioninlistening(server)mode.CalledbytheActivityonResume()*/
  70. publicsynchronizedvoidstart(){
  71. if(D)Log.d(TAG,"start");
  72. //Cancelanythreadattemptingtomakeaconnection
  73. if(mConnectThread!=null){mConnectThread.cancel();mConnectThread=null;}
  74. //Cancelanythreadcurrentlyrunningaconnection
  75. if(mConnectedThread!=null){mConnectedThread.cancel();mConnectedThread=null;}
  76. //StartthethreadtolistenonaBluetoothServerSocket
  77. if(mAcceptThread==null){
  78. mAcceptThread=newAcceptThread();
  79. mAcceptThread.start();
  80. }
  81. setState(STATE_LISTEN);
  82. }
  83. /**
  84. *StarttheConnectThreadtoinitiateaconnectiontoaremotedevice.
  85. *@paramdeviceTheBluetoothDevicetoconnect
  86. */
  87. publicsynchronizedvoidconnect(BluetoothDevicedevice){
  88. if(D)Log.d(TAG,"connectto:"+device);
  89. //Cancelanythreadattemptingtomakeaconnection
  90. if(mState==STATE_CONNECTING){
  91. if(mConnectThread!=null){mConnectThread.cancel();mConnectThread=null;}
  92. }
  93. //Cancelanythreadcurrentlyrunningaconnection
  94. if(mConnectedThread!=null){mConnectedThread.cancel();mConnectedThread=null;}
  95. //Startthethreadtoconnectwiththegivendevice
  96. mConnectThread=newConnectThread(device);
  97. mConnectThread.start();
  98. setState(STATE_CONNECTING);
  99. }
  100. /**
  101. *StarttheConnectedThreadtobeginmanagingaBluetoothconnection
  102. *@paramsocketTheBluetoothSocketonwhichtheconnectionwasmade
  103. *@paramdeviceTheBluetoothDevicethathasbeenconnected
  104. */
  105. publicsynchronizedvoidconnected(BluetoothSocketsocket,BluetoothDevicedevice){
  106. if(D)Log.d(TAG,"connected");
  107. //Cancelthethreadthatcompletedtheconnection
  108. if(mConnectThread!=null){mConnectThread.cancel();mConnectThread=null;}
  109. //Cancelanythreadcurrentlyrunningaconnection
  110. if(mConnectedThread!=null){mConnectedThread.cancel();mConnectedThread=null;}
  111. //Canceltheacceptthreadbecauseweonlywanttoconnecttoonedevice
  112. if(mAcceptThread!=null){mAcceptThread.cancel();mAcceptThread=null;}
  113. //Startthethreadtomanagetheconnectionandperformtransmissions
  114. mConnectedThread=newConnectedThread(socket);
  115. mConnectedThread.start();
  116. //SendthenameoftheconnecteddevicebacktotheUIActivity
  117. Messagemsg=mHandler.obtainMessage(BluetoothChat.MESSAGE_DEVICE_NAME);
  118. Bundlebundle=newBundle();
  119. bundle.putString(BluetoothChat.DEVICE_NAME,device.getName());
  120. msg.setData(bundle);
  121. mHandler.sendMessage(msg);
  122. setState(STATE_CONNECTED);
  123. }
  124. /**
  125. *Stopallthreads
  126. */
  127. publicsynchronizedvoidstop(){
  128. if(D)Log.d(TAG,"stop");
  129. if(mConnectThread!=null){mConnectThread.cancel();mConnectThread=null;}
  130. if(mConnectedThread!=null){mConnectedThread.cancel();mConnectedThread=null;}
  131. if(mAcceptThread!=null){mAcceptThread.cancel();mAcceptThread=null;}
  132. setState(STATE_NONE);
  133. }
  134. /**
  135. *WritetotheConnectedThreadinanunsynchronizedmanner
  136. *@paramoutThebytestowrite
  137. *@seeConnectedThread#write(byte[])
  138. */
  139. publicvoidwrite(byte[]out){
  140. //Createtemporaryobject
  141. ConnectedThreadr;
  142. //SynchronizeacopyoftheConnectedThread
  143. synchronized(this){
  144. if(mState!=STATE_CONNECTED)return;
  145. r=mConnectedThread;
  146. }
  147. //Performthewriteunsynchronized
  148. r.write(out);
  149. }
  150. /**
  151. *IndicatethattheconnectionattemptfailedandnotifytheUIActivity.
  152. */
  153. privatevoidconnectionFailed(){
  154. setState(STATE_LISTEN);
  155. //SendafailuremessagebacktotheActivity
  156. Messagemsg=mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST);
  157. Bundlebundle=newBundle();
  158. bundle.putString(BluetoothChat.TOAST,"Unabletoconnectdevice");
  159. msg.setData(bundle);
  160. mHandler.sendMessage(msg);
  161. }
  162. /**
  163. *IndicatethattheconnectionwaslostandnotifytheUIActivity.
  164. */
  165. privatevoidconnectionLost(){
  166. setState(STATE_LISTEN);
  167. //SendafailuremessagebacktotheActivity
  168. Messagemsg=mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST);
  169. Bundlebundle=newBundle();
  170. bundle.putString(BluetoothChat.TOAST,"Deviceconnectionwaslost");
  171. msg.setData(bundle);
  172. mHandler.sendMessage(msg);
  173. }
  174. /**
  175. *Thisthreadrunswhilelisteningforincomingconnections.Itbehaves
  176. *likeaserver-sideclient.Itrunsuntilaconnectionisaccepted
  177. *(oruntilcancelled).
  178. */
  179. @SuppressLint("NewApi")
  180. privateclassAcceptThreadextendsThread{
  181. //Thelocalserversocket
  182. privatefinalBluetoothServerSocketmmServerSocket;
  183. publicAcceptThread(){
  184. BluetoothServerSockettmp=null;
  185. //Createanewlisteningserversocket
  186. try{
  187. //开启监听
  188. tmp=mAdapter.listenUsingRfcommWithServiceRecord(NAME,MY_UUID);
  189. }catch(IOExceptione){
  190. Log.e(TAG,"listen()failed",e);
  191. }
  192. mmServerSocket=tmp;
  193. }
  194. publicvoidrun(){
  195. if(D)Log.d(TAG,"BEGINmAcceptThread"+this);
  196. setName("AcceptThread");
  197. BluetoothSocketsocket=null;
  198. //Listentotheserversocketifwe'renotconnected
  199. while(mState!=STATE_CONNECTED){
  200. try{
  201. //Thisisablockingcallandwillonlyreturnona
  202. //successfulconnectionoranexception
  203. socket=mmServerSocket.accept();
  204. }catch(IOExceptione){
  205. Log.e(TAG,"accept()failed",e);
  206. break;
  207. }
  208. //Ifaconnectionwasaccepted
  209. if(socket!=null){
  210. synchronized(BluetoothChatService.this){
  211. switch(mState){
  212. caseSTATE_LISTEN:
  213. caseSTATE_CONNECTING:
  214. //Situationnormal.Starttheconnectedthread.
  215. connected(socket,socket.getRemoteDevice());
  216. break;
  217. caseSTATE_NONE:
  218. caseSTATE_CONNECTED:
  219. //Eithernotreadyoralreadyconnected.Terminatenewsocket.
  220. try{
  221. socket.close();
  222. }catch(IOExceptione){
  223. Log.e(TAG,"Couldnotcloseunwantedsocket",e);
  224. }
  225. break;
  226. }
  227. }
  228. }
  229. }
  230. if(D)Log.i(TAG,"ENDmAcceptThread");
  231. }
  232. publicvoidcancel(){
  233. if(D)Log.d(TAG,"cancel"+this);
  234. try{
  235. mmServerSocket.close();
  236. }catch(IOExceptione){
  237. Log.e(TAG,"close()ofserverfailed",e);
  238. }
  239. }
  240. }
  241. /**
  242. *Thisthreadrunswhileattemptingtomakeanoutgoingconnection
  243. *withadevice.Itrunsstraightthrough;theconnectioneither
  244. *succeedsorfails.
  245. */
  246. privateclassConnectThreadextendsThread{
  247. privatefinalBluetoothSocketmmSocket;
  248. privatefinalBluetoothDevicemmDevice;
  249. publicConnectThread(BluetoothDevicedevice){
  250. mmDevice=device;
  251. BluetoothSockettmp=null;
  252. //GetaBluetoothSocketforaconnectionwiththe
  253. //givenBluetoothDevice
  254. try{
  255. tmp=device.createRfcommSocketToServiceRecord(MY_UUID);
  256. }catch(IOExceptione){
  257. Log.e(TAG,"create()failed",e);
  258. }
  259. mmSocket=tmp;
  260. }
  261. publicvoidrun(){
  262. Log.i(TAG,"BEGINmConnectThread");
  263. setName("ConnectThread");
  264. //Alwayscanceldiscoverybecauseitwillslowdownaconnection
  265. mAdapter.cancelDiscovery();
  266. //MakeaconnectiontotheBluetoothSocket
  267. try{
  268. //Thisisablockingcallandwillonlyreturnona
  269. //successfulconnectionoranexception
  270. mmSocket.connect();
  271. }catch(IOExceptione){
  272. connectionFailed();
  273. //Closethesocket
  274. try{
  275. mmSocket.close();
  276. }catch(IOExceptione2){
  277. Log.e(TAG,"unabletoclose()socketduringconnectionfailure",e2);
  278. }
  279. //Starttheserviceovertorestartlisteningmode
  280. BluetoothChatService.this.start();
  281. return;
  282. }
  283. //ResettheConnectThreadbecausewe'redone
  284. synchronized(BluetoothChatService.this){
  285. mConnectThread=null;
  286. }
  287. //Starttheconnectedthread
  288. connected(mmSocket,mmDevice);
  289. }
  290. publicvoidcancel(){
  291. try{
  292. mmSocket.close();
  293. }catch(IOExceptione){
  294. Log.e(TAG,"close()ofconnectsocketfailed",e);
  295. }
  296. }
  297. }
  298. /**
  299. *Thisthreadrunsduringaconnectionwitharemotedevice.
  300. *Ithandlesallincomingandoutgoingtransmissions.
  301. */
  302. privateclassConnectedThreadextendsThread{
  303. privatefinalBluetoothSocketmmSocket;
  304. privatefinalInputStreammmInStream;
  305. privatefinalOutputStreammmOutStream;
  306. publicConnectedThread(BluetoothSocketsocket){
  307. Log.d(TAG,"createConnectedThread");
  308. mmSocket=socket;
  309. InputStreamtmpIn=null;
  310. OutputStreamtmpOut=null;
  311. //GettheBluetoothSocketinputandoutputstreams
  312. try{
  313. tmpIn=socket.getInputStream();
  314. tmpOut=socket.getOutputStream();
  315. }catch(IOExceptione){
  316. Log.e(TAG,"tempsocketsnotcreated",e);
  317. }
  318. mmInStream=tmpIn;
  319. mmOutStream=tmpOut;
  320. }
  321. publicvoidrun(){
  322. Log.i(TAG,"BEGINmConnectedThread");
  323. byte[]buffer=newbyte[1024];
  324. intbytes;
  325. //KeeplisteningtotheInputStreamwhileconnected
  326. while(true){
  327. try{
  328. //ReadfromtheInputStream
  329. bytes=mmInStream.read(buffer);
  330. //SendtheobtainedbytestotheUIActivity
  331. mHandler.obtainMessage(BluetoothChat.MESSAGE_READ,bytes,-1,buffer)
  332. .sendToTarget();
  333. }catch(IOExceptione){
  334. Log.e(TAG,"disconnected",e);
  335. connectionLost();
  336. break;
  337. }
  338. }
  339. }
  340. /**
  341. *WritetotheconnectedOutStream.
  342. *@parambufferThebytestowrite
  343. */
  344. publicvoidwrite(byte[]buffer){
  345. try{
  346. mmOutStream.write(buffer);
  347. //SharethesentmessagebacktotheUIActivity
  348. mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE,-1,-1,buffer)
  349. .sendToTarget();
  350. }catch(IOExceptione){
  351. Log.e(TAG,"Exceptionduringwrite",e);
  352. }
  353. }
  354. publicvoidcancel(){
  355. try{
  356. mmSocket.close();
  357. }catch(IOExceptione){
  358. Log.e(TAG,"close()ofconnectsocketfailed",e);
  359. }
  360. }
  361. }
  362. }

DeviceListActivity.java

该类包含UI和操作的Activity类,作用是得到系统默认蓝牙设备的已配对设备列表,以及搜索出的未配对的新设备的列表。然后提供点击后发出连接设备请求的功能。

  1. importjava.util.Set;
  2. importandroid.annotation.SuppressLint;
  3. importandroid.app.Activity;
  4. importandroid.bluetooth.BluetoothAdapter;
  5. importandroid.bluetooth.BluetoothDevice;
  6. importandroid.content.BroadcastReceiver;
  7. importandroid.content.Context;
  8. importandroid.content.Intent;
  9. importandroid.content.IntentFilter;
  10. importandroid.os.Bundle;
  11. importandroid.util.Log;
  12. importandroid.view.View;
  13. importandroid.view.Window;
  14. importandroid.view.View.OnClickListener;
  15. importandroid.widget.AdapterView;
  16. importandroid.widget.ArrayAdapter;
  17. importandroid.widget.Button;
  18. importandroid.widget.ListView;
  19. importandroid.widget.TextView;
  20. importandroid.widget.AdapterView.OnItemClickListener;
  21. /**
  22. *ThisActivityappearsasadialog.Itlistsanypaireddevicesand
  23. *devicesdetectedintheareaafterdiscovery.Whenadeviceischosen
  24. *bytheuser,theMACaddressofthedeviceissentbacktotheparent
  25. *ActivityintheresultIntent.
  26. */
  27. @SuppressLint("NewApi")
  28. publicclassDeviceListActivityextendsActivity{
  29. //Debugging
  30. privatestaticfinalStringTAG="DeviceListActivity";
  31. privatestaticfinalbooleanD=true;
  32. //ReturnIntentextra
  33. publicstaticStringEXTRA_DEVICE_ADDRESS="device_address";
  34. //Memberfields
  35. privateBluetoothAdaptermBtAdapter;
  36. privateArrayAdapter<String>mPairedDevicesArrayAdapter;
  37. privateArrayAdapter<String>mNewDevicesArrayAdapter;
  38. @Override
  39. protectedvoidonCreate(BundlesavedInstanceState){
  40. super.onCreate(savedInstanceState);
  41. //Setupthewindow
  42. requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
  43. setContentView(R.layout.device_list);
  44. //SetresultCANCELEDincasetheuserbacksout
  45. setResult(Activity.RESULT_CANCELED);
  46. //Initializethebuttontoperformdevicediscovery
  47. ButtonscanButton=(Button)findViewById(R.id.button_scan);
  48. scanButton.setOnClickListener(newOnClickListener(){
  49. publicvoidonClick(Viewv){
  50. doDiscovery();
  51. v.setVisibility(View.GONE);
  52. }
  53. });
  54. //Initializearrayadapters.Oneforalreadypaireddevicesand
  55. //onefornewlydiscovereddevices
  56. mPairedDevicesArrayAdapter=newArrayAdapter<String>(this,R.layout.device_name);
  57. mNewDevicesArrayAdapter=newArrayAdapter<String>(this,R.layout.device_name);
  58. //FindandsetuptheListViewforpaireddevices
  59. ListViewpairedListView=(ListView)findViewById(R.id.paired_devices);
  60. pairedListView.setAdapter(mPairedDevicesArrayAdapter);
  61. pairedListView.setOnItemClickListener(mDeviceClickListener);
  62. //FindandsetuptheListViewfornewlydiscovereddevices
  63. ListViewnewDevicesListView=(ListView)findViewById(R.id.new_devices);
  64. newDevicesListView.setAdapter(mNewDevicesArrayAdapter);
  65. newDevicesListView.setOnItemClickListener(mDeviceClickListener);
  66. //Registerforbroadcastswhenadeviceisdiscovered
  67. IntentFilterfilter=newIntentFilter(BluetoothDevice.ACTION_FOUND);
  68. this.registerReceiver(mReceiver,filter);
  69. //Registerforbroadcastswhendiscoveryhasfinished
  70. filter=newIntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
  71. this.registerReceiver(mReceiver,filter);
  72. //GetthelocalBluetoothadapter
  73. mBtAdapter=BluetoothAdapter.getDefaultAdapter();
  74. //Getasetofcurrentlypaireddevices
  75. Set<BluetoothDevice>pairedDevices=mBtAdapter.getBondedDevices();
  76. //Iftherearepaireddevices,addeachonetotheArrayAdapter
  77. if(pairedDevices.size()>0){
  78. findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
  79. for(BluetoothDevicedevice:pairedDevices){
  80. mPairedDevicesArrayAdapter.add(device.getName()+"\n"+device.getAddress());
  81. }
  82. }else{
  83. StringnoDevices=getResources().getText(R.string.none_paired).toString();
  84. mPairedDevicesArrayAdapter.add(noDevices);
  85. }
  86. }
  87. @Override
  88. protectedvoidonDestroy(){
  89. super.onDestroy();
  90. //Makesurewe'renotdoingdiscoveryanymore
  91. if(mBtAdapter!=null){
  92. mBtAdapter.cancelDiscovery();
  93. }
  94. //Unregisterbroadcastlisteners
  95. this.unregisterReceiver(mReceiver);
  96. }
  97. /**
  98. *StartdevicediscoverwiththeBluetoothAdapter
  99. */
  100. privatevoiddoDiscovery(){
  101. if(D)Log.d(TAG,"doDiscovery()");
  102. //Indicatescanninginthetitle
  103. setProgressBarIndeterminateVisibility(true);
  104. setTitle(R.string.scanning);
  105. //Turnonsub-titlefornewdevices
  106. findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);
  107. //Ifwe'realreadydiscovering,stopit
  108. if(mBtAdapter.isDiscovering()){
  109. mBtAdapter.cancelDiscovery();
  110. }
  111. //RequestdiscoverfromBluetoothAdapter
  112. mBtAdapter.startDiscovery();
  113. }
  114. //Theon-clicklistenerforalldevicesintheListViews
  115. privateOnItemClickListenermDeviceClickListener=newOnItemClickListener(){
  116. publicvoidonItemClick(AdapterView<?>av,Viewv,intarg2,longarg3){
  117. //Canceldiscoverybecauseit'scostlyandwe'reabouttoconnect
  118. mBtAdapter.cancelDiscovery();
  119. //GetthedeviceMACaddress,whichisthelast17charsintheView
  120. Stringinfo=((TextView)v).getText().toString();
  121. Stringaddress=info.substring(info.length()-17);
  122. //CreatetheresultIntentandincludetheMACaddress
  123. Intentintent=newIntent();
  124. intent.putExtra(EXTRA_DEVICE_ADDRESS,address);
  125. //SetresultandfinishthisActivity
  126. setResult(Activity.RESULT_OK,intent);
  127. finish();
  128. }
  129. };
  130. //TheBroadcastReceiverthatlistensfordiscovereddevicesand
  131. //changesthetitlewhendiscoveryisfinished
  132. privatefinalBroadcastReceivermReceiver=newBroadcastReceiver(){
  133. @Override
  134. publicvoidonReceive(Contextcontext,Intentintent){
  135. Stringaction=intent.getAction();
  136. //Whendiscoveryfindsadevice
  137. if(BluetoothDevice.ACTION_FOUND.equals(action)){
  138. //GettheBluetoothDeviceobjectfromtheIntent
  139. BluetoothDevicedevice=intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
  140. //Ifit'salreadypaired,skipit,becauseit'sbeenlistedalready
  141. if(device.getBondState()!=BluetoothDevice.BOND_BONDED){
  142. mNewDevicesArrayAdapter.add(device.getName()+"\n"+device.getAddress());
  143. }
  144. //Whendiscoveryisfinished,changetheActivitytitle
  145. }elseif(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){
  146. setProgressBarIndeterminateVisibility(false);
  147. setTitle(R.string.select_device);
  148. if(mNewDevicesArrayAdapter.getCount()==0){
  149. StringnoDevices=getResources().getText(R.string.none_found).toString();
  150. mNewDevicesArrayAdapter.add(noDevices);
  151. }
  152. }
  153. }
  154. };
  155. }

作者在这里介绍的这个实例是Google SDK中提供的一个蓝牙聊天程序,简单但信息量巨大,非常适合初学者学习蓝牙方面的知识。

在学习这个实例前请读者仔细阅读并理解Socket的工作原理和实现机制,作者的这篇博客中有详细的介绍:

http://blog.csdn.net/dlutbrucezhang/article/details/8577810


在Android1.x的时候,相关API非常不完善,还不能简单的使用Bluetooth开发,有一个开源项目可以帮助程序员使用、开发蓝牙,支持直接方法bluetooth协议栈。在Android2以后,框架提供了一些官方API来进行蓝牙的通信,但目前的程序也比较不完善。本文主要讨论Android2后的Bluetooth通信的API使用方法。

首先看聊天室的效果图:




蓝牙设备连接的过程如下图所示:



下面这张图展示的是蓝牙聊天的时序图:



接下来将贴出源码并对源码做出详细的解释说明:

BluetoothChat.java

例程的主Activity。onCreate()得到本地BluetoothAdapter设备,检查是否支持。onStart()中检查是否启用蓝牙,并请求启用,然后执行setupChat()。setupChat()中先对界面中的控件进行初始化增加点击监听器等,然创建BluetoothChatService对象,该对象在整个应用过程中存在,并执行蓝牙连接建立、消息发送接受等实际的行为。

  1. importandroid.app.Activity;
  2. importandroid.bluetooth.BluetoothAdapter;
  3. importandroid.bluetooth.BluetoothDevice;
  4. importandroid.content.Intent;
  5. importandroid.os.Bundle;
  6. importandroid.os.Handler;
  7. importandroid.os.Message;
  8. importandroid.util.Log;
  9. importandroid.view.KeyEvent;
  10. importandroid.view.Menu;
  11. importandroid.view.MenuInflater;
  12. importandroid.view.MenuItem;
  13. importandroid.view.View;
  14. importandroid.view.Window;
  15. importandroid.view.View.OnClickListener;
  16. importandroid.view.inputmethod.EditorInfo;
  17. importandroid.widget.ArrayAdapter;
  18. importandroid.widget.Button;
  19. importandroid.widget.EditText;
  20. importandroid.widget.ListView;
  21. importandroid.widget.TextView;
  22. importandroid.widget.Toast;
  23. /**
  24. *ThisisthemainActivitythatdisplaysthecurrentchatsession.
  25. */
  26. publicclassBluetoothChatextendsActivity{
  27. //Debugging
  28. privatestaticfinalStringTAG="BluetoothChat";
  29. privatestaticfinalbooleanD=true;
  30. //MessagetypessentfromtheBluetoothChatServiceHandler
  31. publicstaticfinalintMESSAGE_STATE_CHANGE=1;
  32. publicstaticfinalintMESSAGE_READ=2;
  33. publicstaticfinalintMESSAGE_WRITE=3;
  34. publicstaticfinalintMESSAGE_DEVICE_NAME=4;
  35. publicstaticfinalintMESSAGE_TOAST=5;
  36. //KeynamesreceivedfromtheBluetoothChatServiceHandler
  37. publicstaticfinalStringDEVICE_NAME="device_name";
  38. publicstaticfinalStringTOAST="toast";
  39. //Intentrequestcodes
  40. privatestaticfinalintREQUEST_CONNECT_DEVICE=1;
  41. privatestaticfinalintREQUEST_ENABLE_BT=2;
  42. //LayoutViews
  43. privateTextViewmTitle;
  44. privateListViewmConversationView;
  45. privateEditTextmOutEditText;
  46. privateButtonmSendButton;
  47. //Nameoftheconnecteddevice
  48. privateStringmConnectedDeviceName=null;
  49. //Arrayadapterfortheconversationthread
  50. privateArrayAdapter<String>mConversationArrayAdapter;
  51. //Stringbufferforoutgoingmessages
  52. privateStringBuffermOutStringBuffer;
  53. //LocalBluetoothadapter
  54. privateBluetoothAdaptermBluetoothAdapter=null;
  55. //Memberobjectforthechatservices
  56. privateBluetoothChatServicemChatService=null;
  57. @Override
  58. publicvoidonCreate(BundlesavedInstanceState){
  59. super.onCreate(savedInstanceState);
  60. if(D)Log.e(TAG,"+++ONCREATE+++");
  61. //Setupthewindowlayout
  62. requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);
  63. setContentView(R.layout.main);
  64. getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE,R.layout.custom_title);
  65. //Setupthecustomtitle
  66. mTitle=(TextView)findViewById(R.id.title_left_text);
  67. mTitle.setText(R.string.app_name);
  68. mTitle=(TextView)findViewById(R.id.title_right_text);
  69. //GetlocalBluetoothadapter
  70. mBluetoothAdapter=BluetoothAdapter.getDefaultAdapter();
  71. //Iftheadapterisnull,thenBluetoothisnotsupported
  72. if(mBluetoothAdapter==null){
  73. Toast.makeText(this,"Bluetoothisnotavailable",Toast.LENGTH_LONG).show();
  74. finish();
  75. return;
  76. }
  77. }
  78. @Override
  79. publicvoidonStart(){
  80. super.onStart();
  81. if(D)Log.e(TAG,"++ONSTART++");
  82. //IfBTisnoton,requestthatitbeenabled.
  83. //setupChat()willthenbecalledduringonActivityResult
  84. if(!mBluetoothAdapter.isEnabled()){
  85. IntentenableIntent=newIntent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
  86. startActivityForResult(enableIntent,REQUEST_ENABLE_BT);
  87. //Otherwise,setupthechatsession
  88. }else{
  89. if(mChatService==null)setupChat();
  90. }
  91. }
  92. @Override
  93. publicsynchronizedvoidonResume(){
  94. super.onResume();
  95. if(D)Log.e(TAG,"+ONRESUME+");
  96. //PerformingthischeckinonResume()coversthecaseinwhichBTwas
  97. //notenabledduringonStart(),sowewerepausedtoenableit...
  98. //onResume()willbecalledwhenACTION_REQUEST_ENABLEactivityreturns.
  99. if(mChatService!=null){
  100. //OnlyifthestateisSTATE_NONE,doweknowthatwehaven'tstartedalready
  101. if(mChatService.getState()==BluetoothChatService.STATE_NONE){
  102. //StarttheBluetoothchatservices
  103. mChatService.start();
  104. }
  105. }
  106. }
  107. privatevoidsetupChat(){
  108. Log.d(TAG,"setupChat()");
  109. //Initializethearrayadapterfortheconversationthread
  110. mConversationArrayAdapter=newArrayAdapter<String>(this,R.layout.message);
  111. mConversationView=(ListView)findViewById(R.id.in);
  112. mConversationView.setAdapter(mConversationArrayAdapter);
  113. //Initializethecomposefieldwithalistenerforthereturnkey
  114. mOutEditText=(EditText)findViewById(R.id.edit_text_out);
  115. mOutEditText.setOnEditorActionListener(mWriteListener);
  116. //Initializethesendbuttonwithalistenerthatforclickevents
  117. mSendButton=(Button)findViewById(R.id.button_send);
  118. mSendButton.setOnClickListener(newOnClickListener(){
  119. publicvoidonClick(Viewv){
  120. //Sendamessageusingcontentoftheedittextwidget
  121. TextViewview=(TextView)findViewById(R.id.edit_text_out);
  122. Stringmessage=view.getText().toString();
  123. sendMessage(message);
  124. }
  125. });
  126. //InitializetheBluetoothChatServicetoperformbluetoothconnections
  127. mChatService=newBluetoothChatService(this,mHandler);
  128. //Initializethebufferforoutgoingmessages
  129. mOutStringBuffer=newStringBuffer("");
  130. }
  131. @Override
  132. publicsynchronizedvoidonPause(){
  133. super.onPause();
  134. if(D)Log.e(TAG,"-ONPAUSE-");
  135. }
  136. @Override
  137. publicvoidonStop(){
  138. super.onStop();
  139. if(D)Log.e(TAG,"--ONSTOP--");
  140. }
  141. @Override
  142. publicvoidonDestroy(){
  143. super.onDestroy();
  144. //StoptheBluetoothchatservices
  145. if(mChatService!=null)mChatService.stop();
  146. if(D)Log.e(TAG,"---ONDESTROY---");
  147. }
  148. privatevoidensureDiscoverable(){
  149. if(D)Log.d(TAG,"ensurediscoverable");
  150. if(mBluetoothAdapter.getScanMode()!=
  151. BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE){
  152. IntentdiscoverableIntent=newIntent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
  153. discoverableIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,300);
  154. startActivity(discoverableIntent);
  155. }
  156. }
  157. /**
  158. *Sendsamessage.
  159. *@parammessageAstringoftexttosend.
  160. */
  161. privatevoidsendMessage(Stringmessage){
  162. //Checkthatwe'reactuallyconnectedbeforetryinganything
  163. if(mChatService.getState()!=BluetoothChatService.STATE_CONNECTED){
  164. Toast.makeText(this,R.string.not_connected,Toast.LENGTH_SHORT).show();
  165. return;
  166. }
  167. //Checkthatthere'sactuallysomethingtosend
  168. if(message.length()>0){
  169. //GetthemessagebytesandtelltheBluetoothChatServicetowrite
  170. byte[]send=message.getBytes();
  171. mChatService.write(send);
  172. //Resetoutstringbuffertozeroandcleartheedittextfield
  173. mOutStringBuffer.setLength(0);
  174. mOutEditText.setText(mOutStringBuffer);
  175. }
  176. }
  177. //TheactionlistenerfortheEditTextwidget,tolistenforthereturnkey
  178. privateTextView.OnEditorActionListenermWriteListener=
  179. newTextView.OnEditorActionListener(){
  180. publicbooleanonEditorAction(TextViewview,intactionId,KeyEventevent){
  181. //Iftheactionisakey-upeventonthereturnkey,sendthemessage
  182. if(actionId==EditorInfo.IME_NULL&&event.getAction()==KeyEvent.ACTION_UP){
  183. Stringmessage=view.getText().toString();
  184. sendMessage(message);
  185. }
  186. if(D)Log.i(TAG,"ENDonEditorAction");
  187. returntrue;
  188. }
  189. };
  190. //TheHandlerthatgetsinformationbackfromtheBluetoothChatService
  191. privatefinalHandlermHandler=newHandler(){
  192. @Override
  193. publicvoidhandleMessage(Messagemsg){
  194. switch(msg.what){
  195. caseMESSAGE_STATE_CHANGE:
  196. if(D)Log.i(TAG,"MESSAGE_STATE_CHANGE:"+msg.arg1);
  197. switch(msg.arg1){
  198. caseBluetoothChatService.STATE_CONNECTED:
  199. mTitle.setText(R.string.title_connected_to);
  200. mTitle.append(mConnectedDeviceName);
  201. mConversationArrayAdapter.clear();
  202. break;
  203. caseBluetoothChatService.STATE_CONNECTING:
  204. mTitle.setText(R.string.title_connecting);
  205. break;
  206. caseBluetoothChatService.STATE_LISTEN:
  207. caseBluetoothChatService.STATE_NONE:
  208. mTitle.setText(R.string.title_not_connected);
  209. break;
  210. }
  211. break;
  212. caseMESSAGE_WRITE:
  213. byte[]writeBuf=(byte[])msg.obj;
  214. //constructastringfromthebuffer
  215. StringwriteMessage=newString(writeBuf);
  216. mConversationArrayAdapter.add("Me:"+writeMessage);
  217. break;
  218. caseMESSAGE_READ:
  219. byte[]readBuf=(byte[])msg.obj;
  220. //constructastringfromthevalidbytesinthebuffer
  221. StringreadMessage=newString(readBuf,0,msg.arg1);
  222. mConversationArrayAdapter.add(mConnectedDeviceName+":"+readMessage);
  223. break;
  224. caseMESSAGE_DEVICE_NAME:
  225. //savetheconnecteddevice'sname
  226. mConnectedDeviceName=msg.getData().getString(DEVICE_NAME);
  227. Toast.makeText(getApplicationContext(),"Connectedto"
  228. +mConnectedDeviceName,Toast.LENGTH_SHORT).show();
  229. break;
  230. caseMESSAGE_TOAST:
  231. Toast.makeText(getApplicationContext(),msg.getData().getString(TOAST),
  232. Toast.LENGTH_SHORT).show();
  233. break;
  234. }
  235. }
  236. };
  237. publicvoidonActivityResult(intrequestCode,intresultCode,Intentdata){
  238. if(D)Log.d(TAG,"onActivityResult"+resultCode);
  239. switch(requestCode){
  240. caseREQUEST_CONNECT_DEVICE:
  241. //WhenDeviceListActivityreturnswithadevicetoconnect
  242. if(resultCode==Activity.RESULT_OK){
  243. //GetthedeviceMACaddress
  244. Stringaddress=data.getExtras()
  245. .getString(DeviceListActivity.EXTRA_DEVICE_ADDRESS);
  246. //GettheBLuetoothDeviceobject
  247. BluetoothDevicedevice=mBluetoothAdapter.getRemoteDevice(address);
  248. //Attempttoconnecttothedevice
  249. mChatService.connect(device);
  250. }
  251. break;
  252. caseREQUEST_ENABLE_BT:
  253. //WhentherequesttoenableBluetoothreturns
  254. if(resultCode==Activity.RESULT_OK){
  255. //Bluetoothisnowenabled,sosetupachatsession
  256. setupChat();
  257. }else{
  258. //UserdidnotenableBluetoothoranerroroccured
  259. Log.d(TAG,"BTnotenabled");
  260. Toast.makeText(this,R.string.bt_not_enabled_leaving,Toast.LENGTH_SHORT).show();
  261. finish();
  262. }
  263. }
  264. }
  265. @Override
  266. publicbooleanonCreateOptionsMenu(Menumenu){
  267. MenuInflaterinflater=getMenuInflater();
  268. inflater.inflate(R.menu.option_menu,menu);
  269. returntrue;
  270. }
  271. @Override
  272. publicbooleanonOptionsItemSelected(MenuItemitem){
  273. switch(item.getItemId()){
  274. caseR.id.scan:
  275. //LaunchtheDeviceListActivitytoseedevicesanddoscan
  276. IntentserverIntent=newIntent(this,DeviceListActivity.class);
  277. startActivityForResult(serverIntent,REQUEST_CONNECT_DEVICE);
  278. returntrue;
  279. caseR.id.discoverable:
  280. //Ensurethisdeviceisdiscoverablebyothers
  281. ensureDiscoverable();
  282. returntrue;
  283. }
  284. returnfalse;
  285. }
  286. }

BluetoothChatService.java

public synchronized void start():

开启mAcceptThread线程,由于样例程序是仅2人的聊天过程,故之前先检测mConnectThread和mConnectedThread是否运行,运行则先退出这些线程。

public synchronized voidconnect(BluetoothDevice device):

取消CONNECTING和CONNECTED状态下的相关线程,然后运行新的mConnectThread线程。

public synchronized voidconnected(BluetoothSocket socket, BluetoothDevice device):

开启一个ConnectedThread来管理对应的当前连接。之前先取消任意现存的mConnectThread、mConnectedThread、mAcceptThread线程,然后开启新mConnectedThread,传入当前刚刚接受的socket连接。最后通过Handler来通知UI连接OK。

public synchronized void stop():

停止所有相关线程,设当前状态为NONE。

public void write(byte[] out):

在STATE_CONNECTED状态下,调用mConnectedThread里的write方法,写入byte。

private void connectionFailed():

连接失败的时候处理,通知ui,并设为STATE_LISTEN状态。

private void connectionLost():

当连接失去的时候,设为STATE_LISTEN状态并通知ui。

内部类:

private class AcceptThread extendsThread:

创建监听线程,准备接受新连接。使用阻塞方式,调用BluetoothServerSocket.accept()。提供cancel方法关闭socket。

private class ConnectThread extendsThread:

这是定义的连接线程,专门用来对外发出连接对方蓝牙的请求和处理流程。构造函数里通过BluetoothDevice.createRfcommSocketToServiceRecord(),从待连接的device产生BluetoothSocket.然后在run方法中connect,成功后调用BluetoothChatSevice的connected()方法。定义cancel()在关闭线程时能够关闭相关socket。

private class ConnectedThread extendsThread:

这个是双方蓝牙连接后一直运行的线程。构造函数中设置输入输出流。Run方法中使用阻塞模式的InputStream.read()循环读取输入流,然后post到UI线程中更新聊天消息。也提供了write()将聊天消息写入输出流传输至对方,传输成功后回写入UI线程。最后cancel()关闭连接的socket。

  1. importjava.io.IOException;
  2. importjava.io.InputStream;
  3. importjava.io.OutputStream;
  4. importjava.util.UUID;
  5. importandroid.annotation.SuppressLint;
  6. importandroid.bluetooth.BluetoothAdapter;
  7. importandroid.bluetooth.BluetoothDevice;
  8. importandroid.bluetooth.BluetoothServerSocket;
  9. importandroid.bluetooth.BluetoothSocket;
  10. importandroid.content.Context;
  11. importandroid.os.Bundle;
  12. importandroid.os.Handler;
  13. importandroid.os.Message;
  14. importandroid.util.Log;
  15. /**
  16. *ThisclassdoesalltheworkforsettingupandmanagingBluetooth
  17. *connectionswithotherdevices.Ithasathreadthatlistensfor
  18. *incomingconnections,athreadforconnectingwithadevice,anda
  19. *threadforperformingdatatransmissionswhenconnected.
  20. */
  21. @SuppressLint("NewApi")
  22. publicclassBluetoothChatService{
  23. //Debugging
  24. privatestaticfinalStringTAG="BluetoothChatService";
  25. privatestaticfinalbooleanD=true;
  26. //NamefortheSDPrecordwhencreatingserversocket
  27. privatestaticfinalStringNAME="BluetoothChat";
  28. //UniqueUUIDforthisapplication
  29. privatestaticfinalUUIDMY_UUID=UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");
  30. //Memberfields
  31. privatefinalBluetoothAdaptermAdapter;
  32. privatefinalHandlermHandler;
  33. privateAcceptThreadmAcceptThread;
  34. privateConnectThreadmConnectThread;
  35. privateConnectedThreadmConnectedThread;
  36. privateintmState;
  37. //Constantsthatindicatethecurrentconnectionstate
  38. publicstaticfinalintSTATE_NONE=0;//we'redoingnothing
  39. publicstaticfinalintSTATE_LISTEN=1;//nowlisteningforincomingconnections
  40. publicstaticfinalintSTATE_CONNECTING=2;//nowinitiatinganoutgoingconnection
  41. publicstaticfinalintSTATE_CONNECTED=3;//nowconnectedtoaremotedevice
  42. /**
  43. *Constructor.PreparesanewBluetoothChatsession.
  44. *@paramcontextTheUIActivityContext
  45. *@paramhandlerAHandlertosendmessagesbacktotheUIActivity
  46. */
  47. publicBluetoothChatService(Contextcontext,Handlerhandler){
  48. mAdapter=BluetoothAdapter.getDefaultAdapter();
  49. mState=STATE_NONE;
  50. mHandler=handler;
  51. }
  52. /**
  53. *Setthecurrentstateofthechatconnection
  54. *@paramstateAnintegerdefiningthecurrentconnectionstate
  55. */
  56. privatesynchronizedvoidsetState(intstate){
  57. if(D)Log.d(TAG,"setState()"+mState+"->"+state);
  58. mState=state;
  59. //GivethenewstatetotheHandlersotheUIActivitycanupdate
  60. mHandler.obtainMessage(BluetoothChat.MESSAGE_STATE_CHANGE,state,-1).sendToTarget();
  61. }
  62. /**
  63. *Returnthecurrentconnectionstate.*/
  64. publicsynchronizedintgetState(){
  65. returnmState;
  66. }
  67. /**
  68. *Startthechatservice.SpecificallystartAcceptThreadtobegina
  69. *sessioninlistening(server)mode.CalledbytheActivityonResume()*/
  70. publicsynchronizedvoidstart(){
  71. if(D)Log.d(TAG,"start");
  72. //Cancelanythreadattemptingtomakeaconnection
  73. if(mConnectThread!=null){mConnectThread.cancel();mConnectThread=null;}
  74. //Cancelanythreadcurrentlyrunningaconnection
  75. if(mConnectedThread!=null){mConnectedThread.cancel();mConnectedThread=null;}
  76. //StartthethreadtolistenonaBluetoothServerSocket
  77. if(mAcceptThread==null){
  78. mAcceptThread=newAcceptThread();
  79. mAcceptThread.start();
  80. }
  81. setState(STATE_LISTEN);
  82. }
  83. /**
  84. *StarttheConnectThreadtoinitiateaconnectiontoaremotedevice.
  85. *@paramdeviceTheBluetoothDevicetoconnect
  86. */
  87. publicsynchronizedvoidconnect(BluetoothDevicedevice){
  88. if(D)Log.d(TAG,"connectto:"+device);
  89. //Cancelanythreadattemptingtomakeaconnection
  90. if(mState==STATE_CONNECTING){
  91. if(mConnectThread!=null){mConnectThread.cancel();mConnectThread=null;}
  92. }
  93. //Cancelanythreadcurrentlyrunningaconnection
  94. if(mConnectedThread!=null){mConnectedThread.cancel();mConnectedThread=null;}
  95. //Startthethreadtoconnectwiththegivendevice
  96. mConnectThread=newConnectThread(device);
  97. mConnectThread.start();
  98. setState(STATE_CONNECTING);
  99. }
  100. /**
  101. *StarttheConnectedThreadtobeginmanagingaBluetoothconnection
  102. *@paramsocketTheBluetoothSocketonwhichtheconnectionwasmade
  103. *@paramdeviceTheBluetoothDevicethathasbeenconnected
  104. */
  105. publicsynchronizedvoidconnected(BluetoothSocketsocket,BluetoothDevicedevice){
  106. if(D)Log.d(TAG,"connected");
  107. //Cancelthethreadthatcompletedtheconnection
  108. if(mConnectThread!=null){mConnectThread.cancel();mConnectThread=null;}
  109. //Cancelanythreadcurrentlyrunningaconnection
  110. if(mConnectedThread!=null){mConnectedThread.cancel();mConnectedThread=null;}
  111. //Canceltheacceptthreadbecauseweonlywanttoconnecttoonedevice
  112. if(mAcceptThread!=null){mAcceptThread.cancel();mAcceptThread=null;}
  113. //Startthethreadtomanagetheconnectionandperformtransmissions
  114. mConnectedThread=newConnectedThread(socket);
  115. mConnectedThread.start();
  116. //SendthenameoftheconnecteddevicebacktotheUIActivity
  117. Messagemsg=mHandler.obtainMessage(BluetoothChat.MESSAGE_DEVICE_NAME);
  118. Bundlebundle=newBundle();
  119. bundle.putString(BluetoothChat.DEVICE_NAME,device.getName());
  120. msg.setData(bundle);
  121. mHandler.sendMessage(msg);
  122. setState(STATE_CONNECTED);
  123. }
  124. /**
  125. *Stopallthreads
  126. */
  127. publicsynchronizedvoidstop(){
  128. if(D)Log.d(TAG,"stop");
  129. if(mConnectThread!=null){mConnectThread.cancel();mConnectThread=null;}
  130. if(mConnectedThread!=null){mConnectedThread.cancel();mConnectedThread=null;}
  131. if(mAcceptThread!=null){mAcceptThread.cancel();mAcceptThread=null;}
  132. setState(STATE_NONE);
  133. }
  134. /**
  135. *WritetotheConnectedThreadinanunsynchronizedmanner
  136. *@paramoutThebytestowrite
  137. *@seeConnectedThread#write(byte[])
  138. */
  139. publicvoidwrite(byte[]out){
  140. //Createtemporaryobject
  141. ConnectedThreadr;
  142. //SynchronizeacopyoftheConnectedThread
  143. synchronized(this){
  144. if(mState!=STATE_CONNECTED)return;
  145. r=mConnectedThread;
  146. }
  147. //Performthewriteunsynchronized
  148. r.write(out);
  149. }
  150. /**
  151. *IndicatethattheconnectionattemptfailedandnotifytheUIActivity.
  152. */
  153. privatevoidconnectionFailed(){
  154. setState(STATE_LISTEN);
  155. //SendafailuremessagebacktotheActivity
  156. Messagemsg=mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST);
  157. Bundlebundle=newBundle();
  158. bundle.putString(BluetoothChat.TOAST,"Unabletoconnectdevice");
  159. msg.setData(bundle);
  160. mHandler.sendMessage(msg);
  161. }
  162. /**
  163. *IndicatethattheconnectionwaslostandnotifytheUIActivity.
  164. */
  165. privatevoidconnectionLost(){
  166. setState(STATE_LISTEN);
  167. //SendafailuremessagebacktotheActivity
  168. Messagemsg=mHandler.obtainMessage(BluetoothChat.MESSAGE_TOAST);
  169. Bundlebundle=newBundle();
  170. bundle.putString(BluetoothChat.TOAST,"Deviceconnectionwaslost");
  171. msg.setData(bundle);
  172. mHandler.sendMessage(msg);
  173. }
  174. /**
  175. *Thisthreadrunswhilelisteningforincomingconnections.Itbehaves
  176. *likeaserver-sideclient.Itrunsuntilaconnectionisaccepted
  177. *(oruntilcancelled).
  178. */
  179. @SuppressLint("NewApi")
  180. privateclassAcceptThreadextendsThread{
  181. //Thelocalserversocket
  182. privatefinalBluetoothServerSocketmmServerSocket;
  183. publicAcceptThread(){
  184. BluetoothServerSockettmp=null;
  185. //Createanewlisteningserversocket
  186. try{
  187. //开启监听
  188. tmp=mAdapter.listenUsingRfcommWithServiceRecord(NAME,MY_UUID);
  189. }catch(IOExceptione){
  190. Log.e(TAG,"listen()failed",e);
  191. }
  192. mmServerSocket=tmp;
  193. }
  194. publicvoidrun(){
  195. if(D)Log.d(TAG,"BEGINmAcceptThread"+this);
  196. setName("AcceptThread");
  197. BluetoothSocketsocket=null;
  198. //Listentotheserversocketifwe'renotconnected
  199. while(mState!=STATE_CONNECTED){
  200. try{
  201. //Thisisablockingcallandwillonlyreturnona
  202. //successfulconnectionoranexception
  203. socket=mmServerSocket.accept();
  204. }catch(IOExceptione){
  205. Log.e(TAG,"accept()failed",e);
  206. break;
  207. }
  208. //Ifaconnectionwasaccepted
  209. if(socket!=null){
  210. synchronized(BluetoothChatService.this){
  211. switch(mState){
  212. caseSTATE_LISTEN:
  213. caseSTATE_CONNECTING:
  214. //Situationnormal.Starttheconnectedthread.
  215. connected(socket,socket.getRemoteDevice());
  216. break;
  217. caseSTATE_NONE:
  218. caseSTATE_CONNECTED:
  219. //Eithernotreadyoralreadyconnected.Terminatenewsocket.
  220. try{
  221. socket.close();
  222. }catch(IOExceptione){
  223. Log.e(TAG,"Couldnotcloseunwantedsocket",e);
  224. }
  225. break;
  226. }
  227. }
  228. }
  229. }
  230. if(D)Log.i(TAG,"ENDmAcceptThread");
  231. }
  232. publicvoidcancel(){
  233. if(D)Log.d(TAG,"cancel"+this);
  234. try{
  235. mmServerSocket.close();
  236. }catch(IOExceptione){
  237. Log.e(TAG,"close()ofserverfailed",e);
  238. }
  239. }
  240. }
  241. /**
  242. *Thisthreadrunswhileattemptingtomakeanoutgoingconnection
  243. *withadevice.Itrunsstraightthrough;theconnectioneither
  244. *succeedsorfails.
  245. */
  246. privateclassConnectThreadextendsThread{
  247. privatefinalBluetoothSocketmmSocket;
  248. privatefinalBluetoothDevicemmDevice;
  249. publicConnectThread(BluetoothDevicedevice){
  250. mmDevice=device;
  251. BluetoothSockettmp=null;
  252. //GetaBluetoothSocketforaconnectionwiththe
  253. //givenBluetoothDevice
  254. try{
  255. tmp=device.createRfcommSocketToServiceRecord(MY_UUID);
  256. }catch(IOExceptione){
  257. Log.e(TAG,"create()failed",e);
  258. }
  259. mmSocket=tmp;
  260. }
  261. publicvoidrun(){
  262. Log.i(TAG,"BEGINmConnectThread");
  263. setName("ConnectThread");
  264. //Alwayscanceldiscoverybecauseitwillslowdownaconnection
  265. mAdapter.cancelDiscovery();
  266. //MakeaconnectiontotheBluetoothSocket
  267. try{
  268. //Thisisablockingcallandwillonlyreturnona
  269. //successfulconnectionoranexception
  270. mmSocket.connect();
  271. }catch(IOExceptione){
  272. connectionFailed();
  273. //Closethesocket
  274. try{
  275. mmSocket.close();
  276. }catch(IOExceptione2){
  277. Log.e(TAG,"unabletoclose()socketduringconnectionfailure",e2);
  278. }
  279. //Starttheserviceovertorestartlisteningmode
  280. BluetoothChatService.this.start();
  281. return;
  282. }
  283. //ResettheConnectThreadbecausewe'redone
  284. synchronized(BluetoothChatService.this){
  285. mConnectThread=null;
  286. }
  287. //Starttheconnectedthread
  288. connected(mmSocket,mmDevice);
  289. }
  290. publicvoidcancel(){
  291. try{
  292. mmSocket.close();
  293. }catch(IOExceptione){
  294. Log.e(TAG,"close()ofconnectsocketfailed",e);
  295. }
  296. }
  297. }
  298. /**
  299. *Thisthreadrunsduringaconnectionwitharemotedevice.
  300. *Ithandlesallincomingandoutgoingtransmissions.
  301. */
  302. privateclassConnectedThreadextendsThread{
  303. privatefinalBluetoothSocketmmSocket;
  304. privatefinalInputStreammmInStream;
  305. privatefinalOutputStreammmOutStream;
  306. publicConnectedThread(BluetoothSocketsocket){
  307. Log.d(TAG,"createConnectedThread");
  308. mmSocket=socket;
  309. InputStreamtmpIn=null;
  310. OutputStreamtmpOut=null;
  311. //GettheBluetoothSocketinputandoutputstreams
  312. try{
  313. tmpIn=socket.getInputStream();
  314. tmpOut=socket.getOutputStream();
  315. }catch(IOExceptione){
  316. Log.e(TAG,"tempsocketsnotcreated",e);
  317. }
  318. mmInStream=tmpIn;
  319. mmOutStream=tmpOut;
  320. }
  321. publicvoidrun(){
  322. Log.i(TAG,"BEGINmConnectedThread");
  323. byte[]buffer=newbyte[1024];
  324. intbytes;
  325. //KeeplisteningtotheInputStreamwhileconnected
  326. while(true){
  327. try{
  328. //ReadfromtheInputStream
  329. bytes=mmInStream.read(buffer);
  330. //SendtheobtainedbytestotheUIActivity
  331. mHandler.obtainMessage(BluetoothChat.MESSAGE_READ,bytes,-1,buffer)
  332. .sendToTarget();
  333. }catch(IOExceptione){
  334. Log.e(TAG,"disconnected",e);
  335. connectionLost();
  336. break;
  337. }
  338. }
  339. }
  340. /**
  341. *WritetotheconnectedOutStream.
  342. *@parambufferThebytestowrite
  343. */
  344. publicvoidwrite(byte[]buffer){
  345. try{
  346. mmOutStream.write(buffer);
  347. //SharethesentmessagebacktotheUIActivity
  348. mHandler.obtainMessage(BluetoothChat.MESSAGE_WRITE,-1,-1,buffer)
  349. .sendToTarget();
  350. }catch(IOExceptione){
  351. Log.e(TAG,"Exceptionduringwrite",e);
  352. }
  353. }
  354. publicvoidcancel(){
  355. try{
  356. mmSocket.close();
  357. }catch(IOExceptione){
  358. Log.e(TAG,"close()ofconnectsocketfailed",e);
  359. }
  360. }
  361. }
  362. }

DeviceListActivity.java

该类包含UI和操作的Activity类,作用是得到系统默认蓝牙设备的已配对设备列表,以及搜索出的未配对的新设备的列表。然后提供点击后发出连接设备请求的功能。

  1. importjava.util.Set;
  2. importandroid.annotation.SuppressLint;
  3. importandroid.app.Activity;
  4. importandroid.bluetooth.BluetoothAdapter;
  5. importandroid.bluetooth.BluetoothDevice;
  6. importandroid.content.BroadcastReceiver;
  7. importandroid.content.Context;
  8. importandroid.content.Intent;
  9. importandroid.content.IntentFilter;
  10. importandroid.os.Bundle;
  11. importandroid.util.Log;
  12. importandroid.view.View;
  13. importandroid.view.Window;
  14. importandroid.view.View.OnClickListener;
  15. importandroid.widget.AdapterView;
  16. importandroid.widget.ArrayAdapter;
  17. importandroid.widget.Button;
  18. importandroid.widget.ListView;
  19. importandroid.widget.TextView;
  20. importandroid.widget.AdapterView.OnItemClickListener;
  21. /**
  22. *ThisActivityappearsasadialog.Itlistsanypaireddevicesand
  23. *devicesdetectedintheareaafterdiscovery.Whenadeviceischosen
  24. *bytheuser,theMACaddressofthedeviceissentbacktotheparent
  25. *ActivityintheresultIntent.
  26. */
  27. @SuppressLint("NewApi")
  28. publicclassDeviceListActivityextendsActivity{
  29. //Debugging
  30. privatestaticfinalStringTAG="DeviceListActivity";
  31. privatestaticfinalbooleanD=true;
  32. //ReturnIntentextra
  33. publicstaticStringEXTRA_DEVICE_ADDRESS="device_address";
  34. //Memberfields
  35. privateBluetoothAdaptermBtAdapter;
  36. privateArrayAdapter<String>mPairedDevicesArrayAdapter;
  37. privateArrayAdapter<String>mNewDevicesArrayAdapter;
  38. @Override
  39. protectedvoidonCreate(BundlesavedInstanceState){
  40. super.onCreate(savedInstanceState);
  41. //Setupthewindow
  42. requestWindowFeature(Window.FEATURE_INDETERMINATE_PROGRESS);
  43. setContentView(R.layout.device_list);
  44. //SetresultCANCELEDincasetheuserbacksout
  45. setResult(Activity.RESULT_CANCELED);
  46. //Initializethebuttontoperformdevicediscovery
  47. ButtonscanButton=(Button)findViewById(R.id.button_scan);
  48. scanButton.setOnClickListener(newOnClickListener(){
  49. publicvoidonClick(Viewv){
  50. doDiscovery();
  51. v.setVisibility(View.GONE);
  52. }
  53. });
  54. //Initializearrayadapters.Oneforalreadypaireddevicesand
  55. //onefornewlydiscovereddevices
  56. mPairedDevicesArrayAdapter=newArrayAdapter<String>(this,R.layout.device_name);
  57. mNewDevicesArrayAdapter=newArrayAdapter<String>(this,R.layout.device_name);
  58. //FindandsetuptheListViewforpaireddevices
  59. ListViewpairedListView=(ListView)findViewById(R.id.paired_devices);
  60. pairedListView.setAdapter(mPairedDevicesArrayAdapter);
  61. pairedListView.setOnItemClickListener(mDeviceClickListener);
  62. //FindandsetuptheListViewfornewlydiscovereddevices
  63. ListViewnewDevicesListView=(ListView)findViewById(R.id.new_devices);
  64. newDevicesListView.setAdapter(mNewDevicesArrayAdapter);
  65. newDevicesListView.setOnItemClickListener(mDeviceClickListener);
  66. //Registerforbroadcastswhenadeviceisdiscovered
  67. IntentFilterfilter=newIntentFilter(BluetoothDevice.ACTION_FOUND);
  68. this.registerReceiver(mReceiver,filter);
  69. //Registerforbroadcastswhendiscoveryhasfinished
  70. filter=newIntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
  71. this.registerReceiver(mReceiver,filter);
  72. //GetthelocalBluetoothadapter
  73. mBtAdapter=BluetoothAdapter.getDefaultAdapter();
  74. //Getasetofcurrentlypaireddevices
  75. Set<BluetoothDevice>pairedDevices=mBtAdapter.getBondedDevices();
  76. //Iftherearepaireddevices,addeachonetotheArrayAdapter
  77. if(pairedDevices.size()>0){
  78. findViewById(R.id.title_paired_devices).setVisibility(View.VISIBLE);
  79. for(BluetoothDevicedevice:pairedDevices){
  80. mPairedDevicesArrayAdapter.add(device.getName()+"\n"+device.getAddress());
  81. }
  82. }else{
  83. StringnoDevices=getResources().getText(R.string.none_paired).toString();
  84. mPairedDevicesArrayAdapter.add(noDevices);
  85. }
  86. }
  87. @Override
  88. protectedvoidonDestroy(){
  89. super.onDestroy();
  90. //Makesurewe'renotdoingdiscoveryanymore
  91. if(mBtAdapter!=null){
  92. mBtAdapter.cancelDiscovery();
  93. }
  94. //Unregisterbroadcastlisteners
  95. this.unregisterReceiver(mReceiver);
  96. }
  97. /**
  98. *StartdevicediscoverwiththeBluetoothAdapter
  99. */
  100. privatevoiddoDiscovery(){
  101. if(D)Log.d(TAG,"doDiscovery()");
  102. //Indicatescanninginthetitle
  103. setProgressBarIndeterminateVisibility(true);
  104. setTitle(R.string.scanning);
  105. //Turnonsub-titlefornewdevices
  106. findViewById(R.id.title_new_devices).setVisibility(View.VISIBLE);
  107. //Ifwe'realreadydiscovering,stopit
  108. if(mBtAdapter.isDiscovering()){
  109. mBtAdapter.cancelDiscovery();
  110. }
  111. //RequestdiscoverfromBluetoothAdapter
  112. mBtAdapter.startDiscovery();
  113. }
  114. //Theon-clicklistenerforalldevicesintheListViews
  115. privateOnItemClickListenermDeviceClickListener=newOnItemClickListener(){
  116. publicvoidonItemClick(AdapterView<?>av,Viewv,intarg2,longarg3){
  117. //Canceldiscoverybecauseit'scostlyandwe'reabouttoconnect
  118. mBtAdapter.cancelDiscovery();
  119. //GetthedeviceMACaddress,whichisthelast17charsintheView
  120. Stringinfo=((TextView)v).getText().toString();
  121. Stringaddress=info.substring(info.length()-17);
  122. //CreatetheresultIntentandincludetheMACaddress
  123. Intentintent=newIntent();
  124. intent.putExtra(EXTRA_DEVICE_ADDRESS,address);
  125. //SetresultandfinishthisActivity
  126. setResult(Activity.RESULT_OK,intent);
  127. finish();
  128. }
  129. };
  130. //TheBroadcastReceiverthatlistensfordiscovereddevicesand
  131. //changesthetitlewhendiscoveryisfinished
  132. privatefinalBroadcastReceivermReceiver=newBroadcastReceiver(){
  133. @Override
  134. publicvoidonReceive(Contextcontext,Intentintent){
  135. Stringaction=intent.getAction();
  136. //Whendiscoveryfindsadevice
  137. if(BluetoothDevice.ACTION_FOUND.equals(action)){
  138. //GettheBluetoothDeviceobjectfromtheIntent
  139. BluetoothDevicedevice=intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
  140. //Ifit'salreadypaired,skipit,becauseit'sbeenlistedalready
  141. if(device.getBondState()!=BluetoothDevice.BOND_BONDED){
  142. mNewDevicesArrayAdapter.add(device.getName()+"\n"+device.getAddress());
  143. }
  144. //Whendiscoveryisfinished,changetheActivitytitle
  145. }elseif(BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)){
  146. setProgressBarIndeterminateVisibility(false);
  147. setTitle(R.string.select_device);
  148. if(mNewDevicesArrayAdapter.getCount()==0){
  149. StringnoDevices=getResources().getText(R.string.none_found).toString();
  150. mNewDevicesArrayAdapter.add(noDevices);
  151. }
  152. }
  153. }
  154. };
  155. }
分享到:
评论

相关推荐

    Android蓝牙程序实例

    Android蓝牙程序实例,是你学习android蓝牙程序比较好的参考实例. 采用的是andorid studio开发工具开发的。

    Android 蓝牙BLE全面解析以及智能车锁开发实例

    Android 蓝牙BLE全面解析以及智能车锁开发实例一、蓝牙BLE产生背景——蓝牙的发展历程 二、蓝牙BLE的基本概念 三、蓝牙BLE的架构介绍 1. 蓝牙BLE架构概览 2. 简述BLE如何发送数据包 2.1 广播方式 2.2 连接方式 四、...

    Android BLE蓝牙例子(包括android版Lightblue)实例源码

    Android_Lightblue.apk是Android版的lightblue,在进行ble开发的时候用该app作为辅助工具还是非常不错的,功能较Bluetooth4_3 BLEDemo 这两个demo都强大。不过Android_Lightblue.apk在android5.0以上的版本手机上...

    Android 蓝牙通信简单实例

    这是一个Android蓝牙开发的小程序,代码简单,实现了蓝牙打开、搜索、配对、连接、通信等功能。两个Android项目,一个服务器一个客户端

    Android-ble-master.zip_Android 蓝牙4.0_android_android蓝牙_ble andro

    是一个单片机蓝牙开发案例,android系统4.3以上,手机支持蓝牙4.0,搜索,配对,连接,发现服务及特征值,断开连接等功能。

    Android BLE蓝牙例子(包括android版Lightblue)实例源码.zip

    Android BLE蓝牙例子(包括android版Lightblue)实例源码: 源码里面有Bluetooth4_3/BLEDemo/Android_Lightblue.apk三个.前两个是BLE的demo。BLEDemo这个功能较Bluetooth4_3多一些,有兴趣的可以都看下。Android_...

    Android上蓝牙通信的Demo工程

    这是android的蓝牙聊天通信程序,可以进行蓝牙设备的搜索、连接,含注释

    android开发蓝牙的一个简单例子

    android开发蓝牙的一个简单例子,服务端和客户端的收发文字信息,用于安卓蓝牙开发入门再好不过了

    Android蓝牙设备之间通过UUID通信

    Android蓝牙通信实例,有客户端和服务端两个程序,以便理解起来更加简单明了。

    Android 蓝牙开发实例解析

    本文以实例的方式讲解Android蓝牙开发的知识。  1、使用蓝牙的响应权限 XML/HTML代码 &lt;uses android:name=android.permission.BLUETOOTH/&gt; &lt;uses android:name=android.permission.BLUETOOTH_ADMIN/&gt;  2、配置本...

    基于android的蓝牙功能实现

    基于android的蓝牙功能实现的源码,改源码能实现在android平台上的蓝牙功能。

    android开发实例大全_王东华

    本书以Android应用程序的开发为主题,并结合真实的案例向读者详细介绍了Android的基本组件的使用及应用程序开发的整个流程。本书的讲述由浅入深,实例全面并典型,几乎囊括了所有和Android应用相关的项目。全书分为...

    Android实例-Delphi开发蓝牙官方实例解析(XE10+小米2+小米5)

    2.保证无毒 3.简单,方便,实用 4.实例可以自行改用 5.如有非法,本人无法律责任,由改动代码人负责! 6.需要更多本人作品,查找标签“朱建强” 7.请下载,杀毒后再使用!

    Android应用源码之安卓蓝牙对战demo实例-IT计算机-毕业设计.zip

    Android应用源码开发Demo,主要用于毕业设计学习。

    Android高级编程--源代码

    由于现有的手机应用程序的开发是构建在各手机厂家的私有操作系统之上的,所以它限制了第三方应用程序的开发,而Android为我们提供了一个开放和通用的选择。因为没有了人为制造的障碍,所以Android开发人员可以自由地...

    新版Android开发教程.rar

    的 Android SDK 提供了在 Android 平台上使用 JaVa 语言进行 Android 应用开发必须的工具和 API 接口。 特性 • 应用程序框架 支持组件的重用与替换 • Dalvik Dalvik Dalvik Dalvik 虚拟机 专为移动设备优化 • ...

    android实现蓝牙app代码

    本文实例为大家分享了android实现蓝牙app的具体代码,供大家参考,具体内容如下 private BluetoothGatt bluetoothGatt; private BluetoothGattService gattService; private BluetoothGattCharacteristic ...

    Android蓝牙模块使用简化工具

    用户进行蓝牙开发时,首先将这两个工具类放到你的工程中,其次调用BlueToothUtils中的getSearchedDevices方法(需要实现这个类中的两个接口作为这个方法的参数)来获取搜索到的设备,设备将在接口中返回给你。...

    android开发资料大全

    android自带的示例程序 BluetoothChat 变蓝牙串口助手(内含DIY蓝牙遥控车附源码实例教程) Android高手过招 FAQ 网友收集的android开发书籍(可下载哦) 东软集团内部文件《android编程指南》 从零开始Android...

Global site tag (gtag.js) - Google Analytics