今晚整理下,實驗室沒開門,只好在一教將就一下了
關于藍牙,看了好些天,但是看完后想想也沒啥,都是谷歌做好了的東西,我們只要用用API就ok了,哎。
首先,如果是互相傳遞數據的,兩部android設備各自都必須充當兩種角色。
1、服務端 2、客戶端。
其實也不難理解,畢竟通信是兩者之間建立的,而且必須實現收發并用。所以理所當然了,客戶端發送消息給服務端。
兩部設備是通過使用相同的UUID建立起一個Rfcomm什么的通道,這個通道連接兩臺設備以供數據的傳遞。
當然要如何建立呢?(我也不知道)
我們先分析客戶端,他是通過Socket的一個主動連接函數connect()來請求服務端的連接(服務端接收到請求..才會有數據傳遞 后面再說),那么這個socket是怎樣來的呢?
是通過device.createRfcommSocketToServiceRecord(UUID);來的,這個device是由你相連服務端的地址得到的,通過藍牙適配器mBluetoothAdapter.getRemoteDevice(address);來的。address又是怎么來的呢? 是通過掃描附近藍牙,被廣播接收器接收到的。
好的整理一下,就是通過廣播接收器掃描到附近的藍牙設備(當然機智的你肯定準備好了兩臺設備) 然后能通過掃描到的設備得到他們的地址。通過這個地址就能實例化出device
然后Socket也就出來了。最后通過Socket.getOutputStream() 得到輸出流,想輸出流內寫入數據 即可完成客戶端的任務。
//以下是客戶端負責發送消息的代碼(布局和manifest文件自己添加以下,很簡單)
package com.example.single_bt1;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;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.Toast;import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;public class AsClient extends Activity implements OnItemClickListener {private static final String TAG = "MainActivity";// 本地藍牙適配器private BluetoothAdapter mBluetoothAdapter;// 列表private ListView lvDevices;// 存儲搜索到的藍牙private List<String> bluetoothDevices = new ArrayList<String>();// listview的adapterprivate ArrayAdapter<String> arrayAdapter;// UUID.randomUUID()隨機獲取UUIDprivate final UUID MY_UUID = UUID.fromString("db764ac8-4b08-7f25-aafe-59d03c27bae3");// 連接對象的名稱private final String NAME = "LGL";// 這里本身即是服務端也是客戶端,需要如下類private BluetoothSocket clientSocket;private BluetoothDevice device;// 輸出流_客戶端需要往服務端輸出private OutputStream os;private EditText et;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);initView();}private void initView() {// 獲取本地藍牙適配器mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();// 判斷手機是否支持藍牙if (mBluetoothAdapter == null) {Toast.makeText(this, "設備不支持藍牙", Toast.LENGTH_SHORT).show();finish();}// 判斷是否打開藍牙if (!mBluetoothAdapter.isEnabled()) {// 彈出對話框提示用戶是后打開Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(intent, 1);// 不做提示,強行打開
// mBluetoothAdapter.enable();}et = (EditText) findViewById(R.id.edit_input2);// 初始化listviewlvDevices = (ListView) findViewById(R.id.lvDevices);lvDevices.setOnItemClickListener(this);// 獲取已經配對的設備Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();// 判斷是否有配對過的設備if (pairedDevices.size() > 0) {for (BluetoothDevice device : pairedDevices) {// 遍歷到列表中bluetoothDevices.add("已配對\n" + device.getName() + ":"+ device.getAddress());}}// adapterarrayAdapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, android.R.id.text1,bluetoothDevices);lvDevices.setAdapter(arrayAdapter);//啟動服務/*** 異步搜索藍牙設備——廣播接收*/// 找到設備的廣播IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);// 注冊廣播registerReceiver(receiver, filter);// 搜索完成的廣播filter = new IntentFilter(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);// 注冊廣播registerReceiver(receiver, filter);}@Overrideprotected void onDestroy() {super.onDestroy();unregisterReceiver(receiver);}// 廣播接收器private final BroadcastReceiver receiver = new BroadcastReceiver() {@Overridepublic void onReceive(Context context, Intent intent) {// 收到的廣播類型String action = intent.getAction();// 發現設備的廣播if (BluetoothDevice.ACTION_FOUND.equals(action)) {// 從intent中獲取設備BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);// 判斷是否配對過if (device.getBondState() != BluetoothDevice.BOND_BONDED) {// 添加到列表bluetoothDevices.add("未配對\n" + device.getName() + ":"+ device.getAddress());arrayAdapter.notifyDataSetChanged();}// 搜索完成} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {// 關閉進度條setProgressBarIndeterminateVisibility(true);setTitle("搜索完成!");}}};// 客戶端@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position,long id) {// 先獲得藍牙的地址和設備名String s = arrayAdapter.getItem(position);// 單獨解析地址String address = s.substring(s.indexOf(":") + 1).trim();// 主動連接藍牙try {// 判斷是否在搜索,如果在搜索,就取消搜索if (mBluetoothAdapter.isDiscovering()) {mBluetoothAdapter.cancelDiscovery();}try {// 獲得遠程設備device = mBluetoothAdapter.getRemoteDevice(address);Log.e(TAG, "device:" + device);clientSocket = device.createRfcommSocketToServiceRecord(MY_UUID);// 連接clientSocket.connect();// 獲得輸出流os = clientSocket.getOutputStream();// 判斷是否可以獲得if (device == null) {// 獲得遠程設備device = mBluetoothAdapter.getRemoteDevice(address);Log.e(TAG, "device:" + device);}// 開始連接if (clientSocket == null) {clientSocket = device.createRfcommSocketToServiceRecord(MY_UUID);// 連接clientSocket.connect();// 獲得輸出流os = clientSocket.getOutputStream();}} catch (Exception e) {}// 如果成功獲得輸出流if (os != null) {
// os.write("Hello Bluetooth!".getBytes());os.write(et.getText().toString().getBytes("GBK"));Log.e(TAG, "write");et.setText("");}} catch (Exception e) {}}}
接下來就是服務端了,服務端相比來說就稍微省事一點了,坐在那里等人來請求,所以他要一直在那里等,言下之意就是一個耗時操作,所以放在一個新的線程中是自然的事情。通過ServerScoket的accept()會產生一個socket負責與客戶端的socket通信, 那么這個serversocket哪來的呢,直接上代碼吧:
serverSocket = mBluetoothAdapter?.listenUsingRfcommWithServiceRecord(NAME, MY_UUID); name是自己定義的,隨便寫就好(String類型)
然后就是通過serverSocket.getInputStream() 得到輸入流,就能讀出數據了。
package com.example.single_bt2_server;import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothServerSocket;
import android.bluetooth.BluetoothSocket;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;public class MainActivity extends Activity {private static final String TAG = "MainActivity";// 本地藍牙適配器private BluetoothAdapter mBluetoothAdapter;// UUID.randomUUID()隨機獲取UUIDprivate final UUID MY_UUID = UUID.fromString("db764ac8-4b08-7f25-aafe-59d03c27bae3");// 連接對象的名稱private final String NAME = "LGL";//線程類的實例private AcceptThread ac;// private EditText edit_Get;private ListView list_Get;private List<String> content = new ArrayList<String>();private ArrayAdapter<String> adapter;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.received);
// edit_Get = (EditText) findViewById(R.id.edit_get);initView();}private void initView() {list_Get = (ListView) findViewById(R.id.list_get);adapter = new ArrayAdapter<String>(MainActivity.this,android.R.layout.simple_list_item_1,content);list_Get.setAdapter(adapter);// 獲取本地藍牙適配器mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();// 判斷手機是否支持藍牙if (mBluetoothAdapter == null) {Toast.makeText(this, "設備不支持藍牙", Toast.LENGTH_SHORT).show();finish();}// 判斷是否打開藍牙if (!mBluetoothAdapter.isEnabled()) {// 彈出對話框提示用戶是后打開Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(intent, 1);// 不做提示,強行打開
// mBluetoothAdapter.enable();}ac = new AcceptThread();ac.start();}// 服務端,需要監聽客戶端的線程類private Handler handler = new Handler() {public void handleMessage(Message msg) {Toast.makeText(MainActivity.this, String.valueOf(msg.obj),Toast.LENGTH_SHORT).show();String result = String.valueOf(msg.obj);
// edit_Get.setText(String.valueOf(msg.obj));content.add(result);adapter.notifyDataSetChanged();Log.e(TAG, msg.obj + ":服務端");super.handleMessage(msg);}};// 線程服務類private class AcceptThread extends Thread {private BluetoothServerSocket serverSocket;private BluetoothSocket socket;// 輸入 輸出流private OutputStream os;private InputStream is;public AcceptThread() {try {serverSocket = mBluetoothAdapter.listenUsingRfcommWithServiceRecord(NAME, MY_UUID);} catch (IOException e) {// TODO Auto-generated catch blocke.printStackTrace();}}@Overridepublic void run() {// 截獲客戶端的藍牙消息try {socket = serverSocket.accept(); // 如果阻塞了,就會一直停留在這里is = socket.getInputStream();os = socket.getOutputStream();while (true) {synchronized (MainActivity.this) {byte[] tt = new byte[is.available()];if (tt.length > 0) {is.read(tt, 0, tt.length);Message msg = new Message();msg.obj = new String(tt, "GBK");Log.e(TAG, msg.obj + ":客戶端");handler.sendMessage(msg);}}}} catch (Exception e) {e.printStackTrace();Log.e(TAG, e.getMessage());}}}}至于兩者都有的角色 讓我放到文件中吧,是網上參考
總結
以上是生活随笔為你收集整理的Android手机蓝牙互联,并传递数据。的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。