PS:最近同學問我藍牙的事,因此自己也就腦補了一下藍牙...
學習內容:
1.如何實現藍牙通信技術...
藍牙通信其實是手機里很常用的一種通信方式,現在的手機中是必然存在藍牙的,藍牙通信也是有一部分優點的,功耗低,安全性比較高,但是缺點想必大家都知道,傳輸的速率也確實是不快,相比於Wifi通信,確實不值一提...雖然影響范圍並不高,但是既然藍牙存在,那么還是有必要知道藍牙是如何進行通信的...藍牙通信有兩種方式,最常用的就是使用socket套接字來實現藍牙通信...
藍牙通信原理:藍牙通信的原理很簡單,一個設備作為服務端,另一個設備作為客戶端,服務端對外暴露,客戶端通過發送連接請求,服務端進行響應,然后返回一個BluetoothSocket套接字來管理這個連接...那么服務端個客戶端就會共享一個RFCOMM端口,進行數據傳遞...聽起來其實蠻簡單的,實現過程還是有點復雜的...這里我還是直接上一個代碼吧...
這個是Activity.java文件...這是個非常長的代碼塊,看完誰都頭痛...我們還是進行分塊解釋...先把這些代碼都略過...還是看最下面的解釋...

package com.qualcomm.bluetoothclient; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import java.util.ArrayList; import java.util.Set; import java.util.UUID; import android.os.Bundle; import android.os.Handler; import android.os.Message; import android.view.View; import android.view.View.OnClickListener; import android.view.inputmethod.InputMethodManager; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; import android.widget.Button; import android.widget.EditText; import android.widget.ListView; import android.widget.Toast; import android.app.Activity; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.BluetoothSocket; import android.content.BroadcastReceiver; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; public class ClientActivity extends Activity implements OnItemClickListener { private Context mContext; private BluetoothAdapter mBluetoothAdapter; // Bluetooth適配器 private BluetoothDevice device; // 藍牙設備 private ListView mListView; private ArrayList<ChatMessage> list; private ClientAdapter clientAdapter; // ListView適配器 private Button disconnect = null, sendButton = null; private EditText editText = null; private BluetoothSocket socket; // 客戶端socket private ClientThread mClientThread; // 客戶端運行線程 private ReadThread mReadThread; // 讀取流線程 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); init(); } // 變量初始化 private void init() { // TODO Auto-generated method stub mContext = this; mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();//獲取本地藍牙... list = new ArrayList<ChatMessage>();// 初始化list clientAdapter = new ClientAdapter(mContext, list); //適配器,用來限制如何顯示ListView... mListView = (ListView) findViewById(R.id.list); mListView.setFastScrollEnabled(true); mListView.setAdapter(clientAdapter); mListView.setOnItemClickListener(this); // 注冊receiver監聽,注冊廣播... IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(mReceiver, filter); // 獲取已經配對過的藍牙設備 Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();//獲取發現的藍牙設備的基本信息... if (pairedDevices.size() > 0) { for (BluetoothDevice device : pairedDevices) { //將手機名字和物理地址放入到listview中... list.add(new ChatMessage(device.getName() + "\n" + device.getAddress(), true)); clientAdapter.notifyDataSetChanged(); //重新繪制ListView mListView.setSelection(list.size() - 1); } } else { list.add(new ChatMessage("沒有已經配對過的設備", true)); clientAdapter.notifyDataSetChanged(); mListView.setSelection(list.size() - 1); } editText = (EditText) findViewById(R.id.edit); editText.setEnabled(false); editText.clearFocus(); sendButton = (Button) findViewById(R.id.btn_send); sendButton.setEnabled(false); sendButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { // TODO Auto-generated method stub String msg = editText.getText().toString(); if (msg.length() > 0) { sendMessageHandler(msg); editText.setText(""); editText.clearFocus(); InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);//定義一個輸入法對象...通過Context.INPUT_METHOD_SERVICE獲取實例... //當EditText沒有焦點的時候,阻止輸入法的彈出...其實就是在沒點擊EditText獲取焦點的時候,沒有輸入法的顯示... imm.hideSoftInputFromWindow(editText.getWindowToken(), 0); } else { Toast.makeText(mContext, "發送內容不能為空", Toast.LENGTH_SHORT).show(); } } }); disconnect = (Button) findViewById(R.id.disconnect); disconnect.setEnabled(false); disconnect.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { // TODO Auto-generated method stub // 關閉相關服務 closeClient(); BluetoothMsg.isOpen = false; BluetoothMsg.serviceOrCilent = BluetoothMsg.ServerOrCilent.NONE; Toast.makeText(mContext, "連接已斷開", Toast.LENGTH_SHORT).show(); } }); } @Override protected void onStart() { // TODO Auto-generated method stub super.onStart(); if (mBluetoothAdapter != null) { //本地藍牙存在... if (!mBluetoothAdapter.isEnabled()) { //判斷藍牙是否被打開... // 發送打開藍牙的意圖,系統會彈出一個提示對話框 Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); startActivityForResult(enableIntent, RESULT_FIRST_USER); // 設置藍牙的可見性,最大值3600秒,默認120秒,0表示永遠可見(作為客戶端,可見性可以不設置,服務端必須要設置) //打開本機的藍牙功能,持續的時間是永遠可見... Intent displayIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); displayIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 0); startActivity(displayIntent); // 直接打開藍牙 mBluetoothAdapter.enable(); } } } @Override protected void onResume() { // TODO Auto-generated method stub super.onResume(); // 掃描 scanDevice(); } /** * 藍牙設備掃描過程中(mBluetoothAdapter.startDiscovery())會發出的消息 * ACTION_FOUND 掃描到遠程設備 * ACTION_DISCOVERY_FINISHED 掃描結束 */ private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); // When discovery finds a device if (BluetoothDevice.ACTION_FOUND.equals(action)) { // Get the BluetoothDevice object from the Intent // 通過EXTRA_DEVICE附加域來得到一個BluetoothDevice設備 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // If it's already paired, skip it, because it's been listed already // 如果這個設備是不曾配對過的,添加到list列表 if (device.getBondState() != BluetoothDevice.BOND_BONDED) { list.add(new ChatMessage(device.getName() + "\n" + device.getAddress(), false)); clientAdapter.notifyDataSetChanged(); mListView.setSelection(list.size() - 1); } // When discovery is finished, change the Activity title } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) { setProgressBarIndeterminateVisibility(false); if (mListView.getCount() == 0) { list.add(new ChatMessage("沒有發現藍牙設備", false)); clientAdapter.notifyDataSetChanged(); mListView.setSelection(list.size() - 1); } } } }; // Handler更新UI private Handler LinkDetectedHandler = new Handler() { @Override public void handleMessage(Message msg) { //Toast.makeText(mContext, (String)msg.obj, Toast.LENGTH_SHORT).show(); if(msg.what==1) { list.add(new ChatMessage((String)msg.obj, true)); } else { list.add(new ChatMessage((String)msg.obj, false)); } clientAdapter.notifyDataSetChanged(); mListView.setSelection(list.size() - 1); } }; // 當連接上服務器的時候才可以選擇發送數據和斷開連接 private Handler refreshUI = new Handler() { public void handleMessage(Message msg) { if (msg.what == 0) { disconnect.setEnabled(true); sendButton.setEnabled(true); editText.setEnabled(true); } } }; // 開啟客戶端連接服務端 private class ClientThread extends Thread { @Override public void run() { // TODO Auto-generated method stub if (device != null) { try { socket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")); // 連接 Message msg = new Message(); msg.obj = "請稍候,正在連接服務器: "+ BluetoothMsg.BlueToothAddress; msg.what = 0; LinkDetectedHandler.sendMessage(msg); // 通過socket連接服務器,這是一個阻塞過程,直到連接建立或者連接失效 socket.connect(); Message msg2 = new Message(); msg2.obj = "已經連接上服務端!可以發送信息"; msg2.what = 0; LinkDetectedHandler.sendMessage(msg2); // 更新UI界面 Message uiMessage = new Message(); uiMessage.what = 0; refreshUI.sendMessage(uiMessage); // 可以開啟讀數據線程 mReadThread = new ReadThread(); mReadThread.start(); } catch (IOException e) { // TODO Auto-generated catch block // socket.connect()連接失效 Message msg = new Message(); msg.obj = "連接服務端異常!斷開連接重新試一試。"; msg.what = 0; LinkDetectedHandler.sendMessage(msg); } } } } // 通過socket獲取InputStream流 private class ReadThread extends Thread { @Override public void run() { // TODO Auto-generated method stub byte[] buffer = new byte[1024]; int bytes; InputStream is = null; try { is = socket.getInputStream(); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } while(true) { try { if ((bytes = is.read(buffer)) > 0) { byte[] data = new byte[bytes]; for (int i = 0; i < data.length; i++) { data[i] = buffer[i]; } String s = new String(data); Message msg = new Message(); msg.obj = s; msg.what = 1; LinkDetectedHandler.sendMessage(msg); } } catch (IOException e) { // TODO Auto-generated catch block try { is.close(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } break; } } } } // 發送數據 private void sendMessageHandler(String msg) { if (socket == null) { Toast.makeText(mContext, "沒有可用的連接", Toast.LENGTH_SHORT).show(); return; } //如果連接上了,那么獲取輸出流... try { OutputStream os = socket.getOutputStream(); os.write(msg.getBytes()); } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } list.add(new ChatMessage(msg, false)); //將數據存放到list中 clientAdapter.notifyDataSetChanged(); mListView.setSelection(list.size() - 1); } // 停止服務 private void closeClient() { new Thread() { public void run() { if (mClientThread != null) { mClientThread.interrupt(); mClientThread = null; } if (mReadThread != null) { mReadThread.interrupt(); mReadThread = null; } try { if (socket != null) { socket.close(); socket = null; } } catch (IOException e) { // TODO: handle exception } } }.start(); } // 掃描設備 private void scanDevice() { // TODO Auto-generated method stub if (mBluetoothAdapter.isDiscovering()) { //如果正在處於掃描過程... mBluetoothAdapter.cancelDiscovery(); //取消掃描... } else { list.clear(); clientAdapter.notifyDataSetChanged(); // 每次掃描前都先判斷一下是否存在已經配對過的設備 Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices(); if (pairedDevices.size() > 0) { for (BluetoothDevice device : pairedDevices) { list.add(new ChatMessage(device.getName() + "\n" + device.getAddress(), true)); clientAdapter.notifyDataSetChanged(); mListView.setSelection(list.size() - 1); } } else { list.add(new ChatMessage("No devices have been paired", true)); clientAdapter.notifyDataSetChanged(); mListView.setSelection(list.size() - 1); } /* 開始搜索 */ mBluetoothAdapter.startDiscovery(); } } @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { // TODO Auto-generated method stub ChatMessage item = list.get(arg2); //item保存着message和一個boolean數值... String info = item.getMessage(); //單純獲取message的信息... String address = info.substring(info.length() - 17);//獲取MAC地址...其實就是硬件地址... BluetoothMsg.BlueToothAddress = address; // 停止掃描 // BluetoothAdapter.startDiscovery()很耗資源,在嘗試配對前必須中止它 mBluetoothAdapter.cancelDiscovery(); // 通過Mac地址去嘗試連接一個設備 device = mBluetoothAdapter.getRemoteDevice(BluetoothMsg.BlueToothAddress); mClientThread = new ClientThread(); //開啟新的線程... mClientThread.start(); BluetoothMsg.isOpen = true; } @Override protected void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); if (mBluetoothAdapter != null) { mBluetoothAdapter.cancelDiscovery(); // 關閉藍牙 mBluetoothAdapter.disable(); } unregisterReceiver(mReceiver); closeClient(); } }
這個是我自定義了一個類,用來判斷藍牙的連接類型...
package com.qualcomm.bluetoothclient; public class BluetoothMsg { /** * 藍牙連接類型 * */ public enum ServerOrCilent { NONE, SERVICE, CILENT }; //藍牙連接方式 public static ServerOrCilent serviceOrCilent = ServerOrCilent.NONE; //連接藍牙地址 public static String BlueToothAddress = null, lastblueToothAddress = null; //通信線程是否開啟 public static boolean isOpen = false; }
這個是保存我們發送的數據信息的自定義類...
package com.qualcomm.bluetoothclient; /* * 這里定義一個類,用來保存我們發送的數據信息... * */ public class ChatMessage { private String message; private boolean isSiri; public ChatMessage(String message, boolean siri) { // TODO Auto-generated constructor stub this.message = message; this.isSiri = siri; } public String getMessage() { return message; } public void setMessage(String message) { this.message = message; } public boolean isSiri() { return isSiri; } public void setSiri(boolean isSiri) { this.isSiri = isSiri; } }
最后這個是適配器...因為我這里使用到了ListView,因此我需要使用一個適配器來設置ListView以何種方式顯示在屏幕上...
package com.qualcomm.bluetoothclient; import java.util.ArrayList; import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.BaseAdapter; import android.widget.TextView; /* * * * * * */ public class ClientAdapter extends BaseAdapter { private ArrayList<ChatMessage> list; private LayoutInflater mInflater; public ClientAdapter(Context context, ArrayList<ChatMessage> messages) { // TODO Auto-generated constructor stub this.list = messages; this.mInflater = LayoutInflater.from(context); } @Override public int getCount() { // TODO Auto-generated method stub return list.size(); } @Override public Object getItem(int position) { // TODO Auto-generated method stub return list.get(position); } @Override public long getItemId(int position) { // TODO Auto-generated method stub return position; } @Override public int getItemViewType(int position) { // TODO Auto-generated method stub return position; } @Override public View getView(int position, View convertView, ViewGroup parent) { // TODO Auto-generated method stub ViewHolder viewHolder = null; ChatMessage message = list.get(position); if (convertView == null) { convertView = mInflater.inflate(R.layout.list_item, null); viewHolder = new ViewHolder((View)convertView.findViewById(R.id.list_child) , (TextView)convertView.findViewById(R.id.chat_msg)); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder) convertView.getTag(); } if (message.isSiri()) { viewHolder.child.setBackgroundResource(R.drawable.msgbox_rec); } else { viewHolder.child.setBackgroundResource(R.drawable.msgbox_send); } viewHolder.msg.setText(message.getMessage()); return convertView; } class ViewHolder { protected View child; protected TextView msg; public ViewHolder(View child, TextView msg){ this.child = child; this.msg = msg; } } }
在這里我進行正式的解釋...先說第二部分..第二部分是一些初始化的操作...也就是獲取本地藍牙,注冊廣播,設置監聽的一些過程...因為實現通信,我們首先要判斷我們的手機是否有藍牙...獲取到本機的藍牙... 也就是這句話是實現通信的第一步...mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();我們才能夠打開藍牙...然后進行操作...詳細解釋在代碼中...
//→_→ 第二部分... // 變量初始化 private void init() { // TODO Auto-generated method stub mContext = this; mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();//獲取本地藍牙...實現通信的第一步... list = new ArrayList<ChatMessage>();// 初始化list,由於我們最后會將數據以列表的形式進行顯示,因此使用ListView... clientAdapter = new ClientAdapter(mContext, list); //適配器,用來限制如何顯示ListView... mListView = (ListView) findViewById(R.id.list); mListView.setFastScrollEnabled(true); //使用快速滑動功能..目的是能夠快速滑動到指定位置... mListView.setAdapter(clientAdapter); mListView.setOnItemClickListener(this); /* 下面是注冊receiver監聽,注冊廣播...說一下為什么要注冊廣播... * 因為藍牙的通信,需要進行設備的搜索,搜索到設備后我們才能夠實現連接..如果沒有搜索,那還談什么連接... * 因此我們需要搜索,搜索的過程中系統會自動發出三個廣播...這三個廣播為: * ACTION_DISCOVERY_START:開始搜索... * ACTION_DISCOVERY_FINISH:搜索結束... * ACTION_FOUND:正在搜索...一共三個過程...因為我們需要對這三個響應過程進行接收,然后實現一些功能,因此 * 我們需要對廣播進行注冊...知道廣播的人應該都知道,想要對廣播進行接收,必須進行注冊,否則是接收不到的... * */ IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(mReceiver, filter); // 定義一個集合,來保存已經配對過的設備... Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices(); if (pairedDevices.size() > 0) { //如果存在設備... for (BluetoothDevice device : pairedDevices) {//遍歷... //將手機名字和物理地址放入到listview中... list.add(new ChatMessage(device.getName() + "\n" + device.getAddress(), true)); clientAdapter.notifyDataSetChanged(); //重新繪制ListView mListView.setSelection(list.size() - 1); //設置list保存的信息的位置...說白了該條信息始終在上一條信息的下方... } } else { list.add(new ChatMessage("沒有已經配對過的設備", true)); clientAdapter.notifyDataSetChanged(); mListView.setSelection(list.size() - 1); } editText = (EditText) findViewById(R.id.edit); editText.setEnabled(false); editText.clearFocus(); //設置沒有焦點..也就是無法輸入任何文字... sendButton = (Button) findViewById(R.id.btn_send); sendButton.setEnabled(false); sendButton.setOnClickListener(new OnClickListener() {//設置監聽,只有獲取到焦點后才能進行此過程... @Override public void onClick(View arg0) { // TODO Auto-generated method stub String msg = editText.getText().toString(); if (msg.length() > 0) { //調用第五部分線程,通過線程發送我們輸入的文本... sendMessageHandler(msg); //發送完清空... editText.setText(""); editText.clearFocus(); InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);//定義一個輸入法對象...通過Context.INPUT_METHOD_SERVICE獲取實例... //當EditText沒有焦點的時候,阻止輸入法的彈出...其實就是在沒點擊EditText獲取焦點的時候,沒有輸入法的顯示... imm.hideSoftInputFromWindow(editText.getWindowToken(), 0); } else { Toast.makeText(mContext, "發送內容不能為空", Toast.LENGTH_SHORT).show(); } } }); disconnect = (Button) findViewById(R.id.disconnect); disconnect.setEnabled(false); //為斷開連接設置監聽... disconnect.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { // TODO Auto-generated method stub // 關閉相關服務,調用第六部分的函數... closeClient(); //表示藍牙狀態需要關閉... BluetoothMsg.isOpen = false; BluetoothMsg.serviceOrCilent = BluetoothMsg.ServerOrCilent.NONE; Toast.makeText(mContext, "連接已斷開", Toast.LENGTH_SHORT).show(); } }); }
接着就是第三部分了...我們獲取到了本地的藍牙設備,我們就需要把藍牙進行打開了..只有開啟了藍牙,才能夠進行搜索,連接等操作..因此這一步是實現藍牙通信的關鍵...
//→_→ 第三部分... @Override protected void onStart() { // TODO Auto-generated method stub super.onStart(); if (mBluetoothAdapter != null) { //本地藍牙存在... if (!mBluetoothAdapter.isEnabled()) { //判斷藍牙是否被打開... // 發送打開藍牙的意圖,系統會彈出一個提示對話框,打開藍牙是需要傳遞intent的... // intent這個重要的東西,大家應該都知道,它能夠實現應用之間通信和交互.... Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE); //打開本機的藍牙功能...使用startActivityForResult()方法...這里我們開啟的這個Activity是需要它返回執行結果給主Activity的... startActivityForResult(enableIntent, RESULT_FIRST_USER); Intent displayIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE); // 設置藍牙的可見性,最大值3600秒,默認120秒,0表示永遠可見(作為客戶端,可見性可以不設置,服務端必須要設置) displayIntent.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 0); //這里只需要開啟另一個activity,讓其一直顯示藍牙...沒必要把信息返回..因此調用startActivity() startActivity(displayIntent); // 直接打開藍牙 mBluetoothAdapter.enable();//這步才是真正打開藍牙的部分.... } } } //這步就是當線程從Pause狀態到Avtive狀態要執行的過程... @Override protected void onResume() { // TODO Auto-generated method stub super.onResume(); // 掃描 scanDevice(); //調用第七部分的掃描過程... }
然后是第四部分....第四部分是對廣播響應后的接收過程..這個過程也是重要的,因為我們在開啟藍牙后掃描的時候,如果有設備可以連接,我們得做一些操作讓用戶知道有設備可以連接,總不能有設備連接,我們什么也不告訴用戶,這就不合理吧....因此我們在這一步是需要給用戶反饋信息的...讓用戶知道下一步應該做什么...這一部分倒是很簡單,沒復雜的東西..
//→_→ 第四部分... private final BroadcastReceiver mReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); //獲取當前正在執行的動作... if (BluetoothDevice.ACTION_FOUND.equals(action)) //正在搜索過程... { // 通過EXTRA_DEVICE附加域來得到一個BluetoothDevice設備 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // 如果這個設備是不曾配對過的,添加到list列表 if (device.getBondState() != BluetoothDevice.BOND_BONDED) { list.add(new ChatMessage(device.getName() + "\n" + device.getAddress(), false)); clientAdapter.notifyDataSetChanged(); mListView.setSelection(list.size() - 1); } } else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) //搜索結束后的過程... { setProgressBarIndeterminateVisibility(false); //這步是如果設備過多是否顯示滾動條... if (mListView.getCount() == 0) { list.add(new ChatMessage("沒有發現藍牙設備", false)); clientAdapter.notifyDataSetChanged(); mListView.setSelection(list.size() - 1); } } } };
第五部分就是線程部分了,所有的線程部分...涉及UI的更新,數據信息的顯示,將數據進行發送,接收服務器返回的數據信息...這步是實現數據傳遞的關鍵...
//→_→ 第五部分... private Handler LinkDetectedHandler = new Handler() { @Override public void handleMessage(Message msg) { //這步多了一個判斷..判斷的是ListView保存的數據是我們要傳輸給服務端的數據,還是那些我們定義好的提示數據... if(msg.what==1) { list.add(new ChatMessage((String)msg.obj, true)); } else { list.add(new ChatMessage((String)msg.obj, false)); } clientAdapter.notifyDataSetChanged(); mListView.setSelection(list.size() - 1); } }; // Handler更新UI... // 當連接上服務器的時候才可以選擇發送數據和斷開連接,並且要對界面進行刷新操作... private Handler refreshUI = new Handler() { public void handleMessage(Message msg) { if (msg.what == 0) { disconnect.setEnabled(true); sendButton.setEnabled(true); editText.setEnabled(true); } } }; // 開啟客戶端連接服務端,一個新的線程... private class ClientThread extends Thread { @Override public void run() { // TODO Auto-generated method stub if (device != null) { try { /* 下面這步也是關鍵,我們如果想要連接服務器,我們需要調用方法createRfcommSocketToServiceRecord * 參數00001101-0000-1000-8000-00805F9B34FB表示的是默認的藍牙串口...通過傳遞參數調用方法, * 會返回給我們一個套接字..這一步就是獲取套接字,實現連接的過程... * * */ socket = device.createRfcommSocketToServiceRecord(UUID.fromString("00001101-0000-1000-8000-00805F9B34FB")); // 連接 Message msg = new Message(); msg.obj = "請稍候,正在連接服務器: "+ BluetoothMsg.BlueToothAddress; msg.what = 0; LinkDetectedHandler.sendMessage(msg); //調用線程,顯示msg信息... // 通過socket連接服務器,正式形成連接...這是一個阻塞過程,直到連接建立或者連接失效... socket.connect(); //如果實現了連接,那么服務端和客戶端就共享一個RFFCOMM信道... Message msg2 = new Message(); msg2.obj = "已經連接上服務端!可以發送信息"; msg2.what = 0; LinkDetectedHandler.sendMessage(msg2); //調用線程,顯示msg信息... // 如果連接成功了...這步就會執行...更新UI界面...否則走catch(IOException e) Message uiMessage = new Message(); uiMessage.what = 0; refreshUI.sendMessage(uiMessage); // 可以開啟讀數據線程 mReadThread = new ReadThread(); mReadThread.start(); } catch (IOException e) { // TODO Auto-generated catch block // socket.connect()連接失效 Message msg = new Message(); msg.obj = "連接服務端異常!斷開連接重新試一試。"; msg.what = 0; LinkDetectedHandler.sendMessage(msg); } } } } // 通過socket獲取InputStream流.. private class ReadThread extends Thread { @Override public void run() { // TODO Auto-generated method stub byte[] buffer = new byte[1024]; int bytes; InputStream is = null; try { is = socket.getInputStream(); //獲取服務器發過來的所有字節... } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } while(true) { try {//讀取過程,將數據信息保存在ListView中... if ((bytes = is.read(buffer)) > 0) { byte[] data = new byte[bytes]; for (int i = 0; i < data.length; i++) { data[i] = buffer[i]; } String s = new String(data); Message msg = new Message(); msg.obj = s; msg.what = 1; //這里的meg.what=1...表示的是服務器發送過來的數據信息.. LinkDetectedHandler.sendMessage(msg); } } catch (IOException e) { // TODO Auto-generated catch block try { is.close(); } catch (IOException e1) { // TODO Auto-generated catch block e1.printStackTrace(); } break; } } } } //這一步表示的是發送數據的過程... private void sendMessageHandler(String msg) { if (socket == null) { Toast.makeText(mContext, "沒有可用的連接", Toast.LENGTH_SHORT).show(); return; } //如果連接上了,那么獲取輸出流... try { OutputStream os = socket.getOutputStream(); os.write(msg.getBytes());//獲取所有的自己然后往外發送... } catch (IOException e) { // TODO Auto-generated catch block e.printStackTrace(); } list.add(new ChatMessage(msg, false)); //將數據存放到list中 clientAdapter.notifyDataSetChanged(); mListView.setSelection(list.size() - 1); }
第六部分就是一個停止服務的一個過程,就不細說了,第七部分就是一個掃描的過程,掃描附近的設別...
// →_→ 第七部分... // 掃描設備 private void scanDevice() { // TODO Auto-generated method stub if (mBluetoothAdapter.isDiscovering()) { //如果正在處於掃描過程... mBluetoothAdapter.cancelDiscovery(); //取消掃描... } else { list.clear(); clientAdapter.notifyDataSetChanged(); // 每次掃描前都先判斷一下是否存在已經配對過的設備 Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices(); if (pairedDevices.size() > 0) { //如果存在配對過的設備,那么就直接遍歷集合,然后顯示.. for (BluetoothDevice device : pairedDevices) { list.add(new ChatMessage(device.getName() + "\n" + device.getAddress(), true)); clientAdapter.notifyDataSetChanged(); mListView.setSelection(list.size() - 1); } } else { //如果沒有就進行添加... list.add(new ChatMessage("No devices have been paired", true)); clientAdapter.notifyDataSetChanged(); mListView.setSelection(list.size() - 1); } /* 開始搜索 */ mBluetoothAdapter.startDiscovery(); } }
第八部分為連接過程做了一些初始化的工作,獲取其他設備的物理地址,通過物理地址實現連接...至於第九部分就是銷過程了,第一部分就是變量的定義過程...就沒什么好說的了...
//→_→ 第八部分... @Override public void onItemClick(AdapterView<?> arg0, View arg1, int arg2, long arg3) { // TODO Auto-generated method stub ChatMessage item = list.get(arg2); //item保存着message和一個boolean數值... String info = item.getMessage(); //單純獲取message的信息... String address = info.substring(info.length() - 17);//獲取MAC地址...其實就是硬件地址...因為連接設別必然從物理地址下手... BluetoothMsg.BlueToothAddress = address;//賦值 // 停止掃描 // BluetoothAdapter.startDiscovery()很耗資源,在嘗試配對前必須中止它 mBluetoothAdapter.cancelDiscovery(); // 通過Mac地址去嘗試連接一個設備, device = mBluetoothAdapter.getRemoteDevice(BluetoothMsg.BlueToothAddress); mClientThread = new ClientThread(); mClientThread.start(); //開啟新的線程...開始連接...這里只是做了一些初始化的工作..連接過程還是ClientThread線程... BluetoothMsg.isOpen = true; }
xml文件我就不貼了,直接放一個源碼吧...這個源碼包含一個客戶端,一個服務端...(注意,這個測試需要在兩個真機上測試,模擬器是沒有作用的...)
源碼地址:http://files.cnblogs.com/files/RGogoing/Bluetooth.zip