蓝牙聊天工具
来源:互联网 发布:如何查看知乎提问者 编辑:程序博客网 时间:2024/04/30 14:28
网上有很多关于蓝牙聊天工具的示例代码,对比参考并加入了自己的理解和创新,自己也做了一个蓝牙聊天工具,总体感觉还可以,下面进行分析一下。
首先定义了 一个Activity主界面,进行聊天信息的输出和发送 。先将聊天界面的XML布局文件贴出来:
activity_bluetooth_chat.xml
<?xml version="1.0" encoding="utf-8"?><LinearLayout android:layout_height="match_parent" android:layout_width="match_parent" android:orientation="vertical" xmlns:android="http://schemas.android.com/apk/res/android"> <ListView android:id="@+id/chat_window_LV" android:layout_width="match_parent" android:layout_height="match_parent" android:transcriptMode="alwaysScroll" android:stackFromBottom="true" android:layout_weight="2"> </ListView> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:orientation="horizontal" android:layout_gravity="bottom"> <Button android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="p" android:onClick="takePhotoClicked"/> <EditText android:id="@+id/input_ET" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_weight="1" android:layout_gravity="bottom"/> <Button android:text="send" android:layout_width="wrap_content" android:layout_height="wrap_content" android:onClick="onSendBtnClicked"/> </LinearLayout></LinearLayout>
包括一个ListView和一个LineLayout布局(一个EditText和一个Button),该ListView用来显示聊天信息的,由一个ArrayAdapter类进行管理,每当收到或者发送 一条信息时,调用add(Object obj)方法可以同步显示出来,另外属性android:transcriptMode=”alwaysScroll”表示当内容 逐渐增多时,会出现滚动条进行帮助显示。 android:stackFromBottom=”true”表示item是从底部开始添加的。而android:layout_gravity=”bottom”>属性表示 该部件的位置,此处是在parent的底部。
聊天记录的ListView里每个item的layout为:
talk_note.xml
<?xml version="1.0" encoding="utf-8"?><TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="20dp" xmlns:android="http://schemas.android.com/apk/res/android"></TextView>
下面来看主Activity,先给出用到的数据成员:
public class BluetoothChat extends AppCompatActivity { private static final String TAG = "BluetoothChat"; public static boolean mBoundListenConnection = false; private static final String path = "/DCIM/camera/"; /* @brief: the flag indicate that the window is in behind */ public static boolean WINDOW_BEHIND_FLAG = true; /* @brief: the handler flag used to decide the action will be taken */ public static final int NEW_DEVICE_READY_TO_CONNECT = 0; /* * @Brief: * the intent request code */ private static final int REQUEST_CODE_ENABLE_BLUETOOTH = 1001; private static final int REQUEST_CODE_SCAN_DEVICES = 1002; public static final int REQUEST_CODE_CAMERA_ACTION = 1003; private static final int REQUEST_CODE_PHOTO_list = 1004; private BluetoothAdapter mBluetoothChatAdapter = null; private static BluetoothChatDevice mBluetoothChatDevice; private ArrayAdapter<String> messageArrayAdapter; private EditText inputArea; public BlueChatHandler mBluetoothChatHandler = new BlueChatHandler(this); private Messenger bluetoothChatMessenger = new Messenger(mBluetoothChatHandler); private Messenger listenMessenger;
给出onCreate方法中做的工作 :
protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_bluetooth_chat); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); inputArea = (EditText)findViewById(R.id.input_ET); ListView message = (ListView)findViewById(R.id.chat_window_LV); messageArrayAdapter = new ArrayAdapter<String>(this,R.layout.talk_note); message.setAdapter(messageArrayAdapter); mBluetoothChatHandler.post(mRunnable); mBluetoothChatDevice = new BluetoothChatDevice(this,mBluetoothChatHandler); mBluetoothChatAdapter = BluetoothAdapter.getDefaultAdapter(); if(mBluetoothChatAdapter==null) { finish(); return; } if (!mBluetoothChatAdapter.isEnabled()) { Intent i = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(i, REQUEST_CODE_ENABLE_BLUETOOTH); }else { if (!mBoundListenConnection) { Intent listenForConnection = new Intent(this, ListenForConnectionService.class); bindService(listenForConnection, mServiceConnection, BIND_AUTO_CREATE); } } // Eula.show(this); }
首先初始化聊天记录 的ListView message和输入部件EditText inputArea。并将message与一个ArrayAdapter messageArrayAdapter关联 起来,进而可以实时同步 聊天信息。初始化Ui thread的handler,并将其 post到一个Runnable对象中,使程序先执行此run()方法:
private Runnable mRunnable = new Runnable() { @Override public void run() { Eula.show(BluetoothChat.this); } };
此处不是本文的重点不做介绍。其实就是一个用户协议,accept后下次打开该 应用时,就不会出现AlertDialog窗口。
然后定义了一个BluetoothChatDevice的实例mBluetoothChatDevice,该类是自己写的一个类,将UI thread的Handler和该Context通过其构造 函数传递给该类。
接着调用mBluetoothChatAdapter = BluetoothAdapter.getDefaultAdapter();获得该设备的蓝牙 接口,并判断是否支持蓝牙,如果不 支持 蓝牙则 返回值mBluetoothChatAdapter ==null。
接着通过调用蓝牙接口的isEnabled()方法判断蓝牙是否已经打开。如果已经打开则启动一个service来监听是否有蓝牙设备接入;如果没有打开则执行打开蓝牙activity,并在打开后启动监听蓝牙设备接入服务。
public static boolean WINDOW_BEHIND_FLAG = true;为indicate当前applicaton是否visible。如果visible则直接将聊天 信息同步到ListView message中,如果Invisible,则会出现Toast提示信息。
public static boolean mBoundListenConnection = false;为是否bind了监听设备接入的服务,由于是在onCreate方法中启动服务的。所以在onDestory方法中unbind服务。
要想bind一个service必须 具有一个ServiceConnection,给出此数据成员的代码:
private ServiceConnection mServiceConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName name, IBinder service) { listenMessenger = new Messenger(service); Message msg = Message.obtain(null,ListenForConnectionService.START_LISTEN_HANDLER_MESS,bluetoothChatMessenger); mBoundListenConnection = true; try { listenMessenger.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } @Override public void onServiceDisconnected(ComponentName name) { mBoundListenConnection = false; try { listenMessenger.send(Message.obtain(null, ListenForConnectionService.STOP_LISTEN_HANDLER_MESS)); } catch (RemoteException e) { e.printStackTrace(); } } };
在方法public void onServiceConnected(ComponentName name, IBinder service) 中得到一个Messenger对象,此对象 由Ibinder service初始化,是监听蓝牙接入的Handler,因此进行listenMessenger.send(msg)时,会在监听service中收到消息,并启动监听thread,并且将该包含UI thread的handler的Messenger发给 绑定的服务中,这样在此监听 服务中 就可以向UI thread传递消息了。
看看这段断码后看onActivityResult方法
public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()){ case R.id.scan_for_blueDevice: Intent i = new Intent(this,BluetoothDeviceList.class); startActivityForResult(i, REQUEST_CODE_SCAN_DEVICES); break; case R.id.visibleBluetooth: Intent scanIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); scanIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION,300); Log.d(TAG,"type"+scanIntent.getType()); startActivity(scanIntent); break; default: break; } return super.onOptionsItemSelected(item); }
此段完成了启动来源可发现的activity,以及启动 蓝牙搜索设备的activity。
protected void onActivityResult(int requestCode, int resultCode, Intent data) { switch (requestCode) { case REQUEST_CODE_ENABLE_BLUETOOTH: if(resultCode==RESULT_CANCELED) { Toast.makeText(this,"the bluetooth device is not enable",Toast.LENGTH_LONG).show(); finish(); return; } if(!mBoundListenConnection) { Intent listenForConnection = new Intent(this, ListenForConnectionService.class); bindService(listenForConnection, mServiceConnection, BIND_AUTO_CREATE); } break; case REQUEST_CODE_SCAN_DEVICES: String address = data.getExtras().getString(BluetoothDeviceList.SELECTED_BLUETOOTH_DEVICE_ADDR); BluetoothDevice bluetoothDevice = mBluetoothChatAdapter.getRemoteDevice(address); mBluetoothChatDevice.connect(bluetoothDevice); break; default: super.onActivityResult(requestCode, resultCode, data); break; } }
给出UI thead的Handler:
private class BlueChatHandler extends Handler { private Context context; public BlueChatHandler(Context c) { context = c; } @Override public void handleMessage(Message msg) { switch (msg.what) { case NEW_DEVICE_READY_TO_CONNECT: BluetoothSocket socket = (BluetoothSocket)msg.obj; mBluetoothChatDevice.chat(socket); break; case BluetoothChatDevice.SEND_MESSAGE: byte[] bytes = (byte[])msg.obj; String tmp = new String(bytes); messageArrayAdapter.add(mBluetoothChatAdapter.getName()+": "+tmp); break; case BluetoothChatDevice.RECEIVE_MESSAGE: // Bitmap bitmap; byte[] mbytes = (byte[])msg.obj; /* if (mbytes.length != 0) { bitmap = BitmapFactory.decodeByteArray(mbytes, 0, mbytes.length); } else { return; }*/ String mtmp = new String(mbytes,0,msg.arg1); messageArrayAdapter.add(BluetoothChatDevice.connectedDeviceName+": "+mtmp); // messageArrayAdapter.add(bitmap); if(WINDOW_BEHIND_FLAG) Toast.makeText(BluetoothChat.this,BluetoothChatDevice.connectedDeviceName+": " + " "+mtmp,Toast.LENGTH_LONG).show(); break; case BluetoothChatDevice.TOAST_MESSAGE: switch (msg.arg1) { case BluetoothChatDevice.TOAST_MESSAGE_UNCONNECT: Toast.makeText(context, msg.obj.toString() + " unconnected", Toast.LENGTH_SHORT).show(); break; case BluetoothChatDevice.TOAST_MESSAGE_CONNECT: Toast.makeText(context,msg.obj.toString()+" connect", Toast.LENGTH_SHORT).show(); break; default: break; } break; default: super.handleMessage(msg); break; } }
给出BluetoothChatdevice类:
/** * Created by almo.liu on 2016/4/20. */public class BluetoothChatDevice implements Serializable { private static final String TAG = "BluetoothChatDevice"; public static final int IN_CHATTING_FLAG = 0; public static final int IN_CONNECTING_FLAG = 1; public static final int IN_CONNECTED_FLAG = 2; public static final int NO_EVENT_HAPPEN = -1; public static int STATE = NO_EVENT_HAPPEN; public static final int RECEIVE_MESSAGE = 11; public static final int SEND_MESSAGE = 12; public static final int TOAST_MESSAGE = 13; public static final int TOAST_MESSAGE_CONNECT = 14; public static final int TOAST_MESSAGE_UNCONNECT = 15; private Context mContext; private Handler mBluetoothChatDeviceHandler; public static String connectedDeviceName = null; private ConnectingThread mConnectingThread; private ChatThread mChatThread; public BluetoothChatDevice(Context context,Handler handler) { mContext = context; mBluetoothChatDeviceHandler = handler; } public synchronized void chat(BluetoothSocket bluetoothSocket) { if(mChatThread!=null) mChatThread.cancel(); mChatThread = new ChatThread(bluetoothSocket); mChatThread.start(); } public synchronized void connect(BluetoothDevice bluetoothDevice) { if(mConnectingThread!=null) mConnectingThread.cancel(); mConnectingThread = new ConnectingThread(bluetoothDevice); mConnectingThread.start(); } public void send(byte[] bytes) { if(mChatThread!=null) mChatThread.write(bytes); else Toast.makeText(mContext,"please connected a device!",Toast.LENGTH_SHORT).show(); } private void connectionLost() { mBluetoothChatDeviceHandler.obtainMessage(TOAST_MESSAGE,TOAST_MESSAGE_UNCONNECT, 1,connectedDeviceName).sendToTarget(); connectedDeviceName = null; } private void successConnect() { mBluetoothChatDeviceHandler.obtainMessage(TOAST_MESSAGE,TOAST_MESSAGE_CONNECT, 0,connectedDeviceName).sendToTarget(); } private class ConnectingThread extends Thread { BluetoothSocket socket; public ConnectingThread(BluetoothDevice bluetoothDevice) { BluetoothSocket bluetoothSocket = null; STATE = IN_CONNECTING_FLAG; try { bluetoothSocket = bluetoothDevice.createRfcommSocketToServiceRecord( ListenForConnectionService.MY_UUID_INSECURE); } catch (IOException e) { STATE = NO_EVENT_HAPPEN; } socket = bluetoothSocket; } @Override public void run() { try { socket.connect(); } catch (IOException e) { STATE = NO_EVENT_HAPPEN; mConnectingThread = null; return; } STATE = IN_CONNECTED_FLAG; mConnectingThread = null; chat(socket); } public synchronized void cancel() { try { socket.close(); mConnectingThread = null; STATE = NO_EVENT_HAPPEN; } catch (IOException e) { e.printStackTrace(); } } } private class ChatThread extends Thread { private BluetoothSocket socket; private InputStream inputStream; private OutputStream outputStream; public ChatThread(BluetoothSocket b) { InputStream tmp_input = null; OutputStream tmp_output = null; STATE = IN_CHATTING_FLAG; socket = b; try { tmp_input= socket.getInputStream(); tmp_output = socket.getOutputStream(); } catch (IOException e) { Log.d(TAG,"exception in create out and in stream"); STATE = NO_EVENT_HAPPEN; } connectedDeviceName = socket.getRemoteDevice().getName(); successConnect(); outputStream = tmp_output; inputStream = tmp_input; } public synchronized void write(byte[] bytes) { if(mChatThread==null) return; try { outputStream.write(bytes); } catch (IOException e) { return; } mBluetoothChatDeviceHandler.obtainMessage(SEND_MESSAGE,bytes).sendToTarget(); } @Override public void run() { byte[] buffer = new byte[1024]; int num = 0; while(true) { try { num = inputStream.read(buffer); Log.d(TAG,new String(buffer)); } catch (IOException e) { Log.d(TAG, "exception in read: " + num); mChatThread = null; break; } mBluetoothChatDeviceHandler.obtainMessage(RECEIVE_MESSAGE,num,0,buffer).sendToTarget(); } connectionLost(); STATE = NO_EVENT_HAPPEN; mChatThread = null; } public synchronized void cancel() { try { STATE = NO_EVENT_HAPPEN; socket.close(); mChatThread = null; } catch (IOException e) { e.printStackTrace(); } } }}
给出监听设备接入的service:
public class ListenForConnectionService extends Service { private static final String TAG = "ListenFor"; public static final UUID MY_UUID_SECURE = UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66"); public static final UUID MY_UUID_INSECURE = UUID.fromString("8ce255c0-200a-11e0-ac64-0800200c9a66"); private static boolean loop_listen = false; private BluetoothAdapter mListenAdapter ; private BluetoothServerSocket mListenBluetoothServerSocket; public static final int START_LISTEN_HANDLER_MESS = 1; public static final int STOP_LISTEN_HANDLER_MESS = 2; private Messenger blueChatMessenger; private Handler listenHandler = new Handler() { @Override public void handleMessage(Message msg) { switch (msg.what) { case START_LISTEN_HANDLER_MESS: blueChatMessenger = (Messenger)msg.obj; listen(); break; case STOP_LISTEN_HANDLER_MESS: cancelListen(); break; default: super.handleMessage(msg); break; } } }; Messenger listenMessenger = new Messenger(listenHandler); @Override public void onCreate() { super.onCreate();/* mListenAdapter = BluetoothAdapter.getDefaultAdapter(); BluetoothServerSocket tmp; try { tmp = mListenAdapter.listenUsingInsecureRfcommWithServiceRecord("test",MY_UUID_INSECURE); } catch (IOException e) { return; } mListenBluetoothServerSocket = tmp; */ } @Override public void onDestroy() { super.onDestroy(); loop_listen = false; } @Nullable @Override public IBinder onBind(Intent intent) { return listenMessenger.getBinder(); } @Override public void onRebind(Intent intent) { super.onRebind(intent); } private Runnable listenRunnable = new Runnable() { @Override public void run() { BluetoothSocket socket = null; while(loop_listen) { if(mListenBluetoothServerSocket==null) { mListenAdapter = BluetoothAdapter.getDefaultAdapter(); BluetoothServerSocket tmp; Log.d(TAG,"null++++++++++++++++++"); try { tmp = mListenAdapter.listenUsingInsecureRfcommWithServiceRecord("test",MY_UUID_INSECURE); } catch (IOException e) { return; } mListenBluetoothServerSocket = tmp; continue; } try { socket = mListenBluetoothServerSocket.accept(); } catch (IOException e) { loop_listen = false; break; } if(socket!=null) { Message msg = Message.obtain(null,BluetoothChat.NEW_DEVICE_READY_TO_CONNECT,socket); try { blueChatMessenger.send(msg); } catch (RemoteException e) { e.printStackTrace(); } } } } }; /* the method called to contact with the service */ public void listen() { loop_listen = true; Thread listenThread = new Thread(listenRunnable); listenThread.start(); } public void cancelListen() { loop_listen = false; }}
- 蓝牙聊天工具
- 聊天工具
- 聊天工具
- 聊聊 聊天工具
- 局域网聊天工具
- 办公室聊天工具
- Web聊天工具
- 局域网聊天工具
- 局域网聊天工具
- 局域网聊天工具
- UDP聊天工具
- 即时聊天工具
- 网络聊天工具
- 聊天工具 客户端
- 聊天工具服务器
- 局域网聊天工具
- Tox 聊天工具
- 蓝牙
- python中xrange简
- iOS开发--多线程编程(三)NSOperation
- linux redis安装
- ViewPager无限自动轮播+动画
- MySQL不存在则创建数据库数据表
- 蓝牙聊天工具
- iOS开发工具集合
- 2015级C++第10、11周程序阅读(补充) 继承和派生
- centos7之lnmp安装
- To The Max
- html5手机网站需要加的那些meta/link标签,html5 meta全解
- git Pull Request 是什么意思?
- 04-树4 是否同一棵二叉搜索树
- OpenGL与OpenCV实现增强现实