啦啦畢業(yè)了,畢業(yè)前要寫(xiě)畢業(yè)設(shè)計(jì),需要寫(xiě)一個(gè)簡(jiǎn)單的藍(lán)牙APP進(jìn)行交互,通過(guò)參考網(wǎng)上資料,問(wèn)題順利搞定,下面小編把具體實(shí)現(xiàn)思路分享給大家,供大家參考。
1、Android藍(lán)牙編程
藍(lán)牙3.0及以下版本編程需要使用UUID,UUID是通用唯一識(shí)別碼(Universally Unique Identifier),這是一個(gè)軟件構(gòu)建的標(biāo)準(zhǔn),也是被開(kāi)源基金會(huì)組織應(yīng)用在分布式計(jì)算環(huán)境領(lǐng)域的一部分。在藍(lán)牙3.0及下一版本中,UUID被用于唯一標(biāo)識(shí)一個(gè)服務(wù),比如文件傳輸服務(wù),串口服務(wù)、打印機(jī)服務(wù)等,如下:
#藍(lán)牙串口服務(wù) SerialPortServiceClass_UUID = '{00001101-0000-1000-8000-00805F9B34FB}' LANAccessUsingPPPServiceClass_UUID = '{00001102-0000-1000-8000-00805F9B34FB}'#撥號(hào)網(wǎng)絡(luò)服務(wù) DialupNetworkingServiceClass_UUID = '{00001103-0000-1000-8000-00805F9B34FB}'#信息同步服務(wù) IrMCSyncServiceClass_UUID = '{00001104-0000-1000-8000-00805F9B34FB}' SDP_OBEXObjectPushServiceClass_UUID = '{00001105-0000-1000-8000-00805F9B34FB}'#文件傳輸服務(wù) OBEXFileTransferServiceClass_UUID = '{00001106-0000-1000-8000-00805F9B34FB}' IrMCSyncCommandServiceClass_UUID = '{00001107-0000-1000-8000-00805F9B34FB}'藍(lán)牙的連接有主從設(shè)備,提供服務(wù)的可以認(rèn)為是從設(shè)備。主設(shè)備通過(guò)UUID訪問(wèn)從設(shè)備提供具有相同UUID的服務(wù),從而建立客服端―服務(wù)器(C/S)模式。
2、編程步驟
Android使用藍(lán)牙,需要獲得權(quán)限,藍(lán)牙權(quán)限獲得代碼如下:
<!-- 藍(lán)牙權(quán)限 --><uses-permission android:name="android.permission.BLUETOOTH"/><uses-permission android:name="android.permission.BLUETOOTH_ADMIN"/>
獲取本地藍(lán)牙適配器,如果藍(lán)牙未開(kāi)啟,開(kāi)啟藍(lán)牙設(shè)備:
bluetoothAdapter = BluetoothAdapter.getDefaultAdapter();if (bluetoothAdapter == null) {// Device does not support Bluetoothreturn;}// 開(kāi)啟藍(lán)牙int REQUEST_ENABLE_BT = 1;if (!bluetoothAdapter.isEnabled()) {Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(intent, REQUEST_ENABLE_BT);}搜索已配對(duì)的藍(lán)牙設(shè)備,并添加到已配對(duì)列表中:
// 查詢(xún)配對(duì)設(shè)備List<String> devices = new ArrayList<String>();Set<BluetoothDevice> bondedDevices = bluetoothAdapter.getBondedDevices();for (BluetoothDevice device : bondedDevices) {devices.add(device.getName() + "-" + device.getAddress());}搜索未配對(duì)藍(lán)牙設(shè)備,并添加到未配對(duì)列表:
mBluetoothAdapter.startDiscovery();//開(kāi)始收索 搜索接收函數(shù): final BroadcastReceiver mReceiver = new BroadcastReceiver() {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 BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE); // Add the name and address to an array adapter to show in a ListView mArrayAdapter.add(device.getName() + "/n" + device.getAddress()); }}};// 收索接收函數(shù)需要注冊(cè): // Register the BroadcastReceiver IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND); registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy如果是服務(wù)器端,需要建立監(jiān)聽(tīng),注意監(jiān)聽(tīng)的是某個(gè)服務(wù)的UUID,服務(wù)器監(jiān)聽(tīng)類(lèi)如下:
private class ConnectThread extends Thread {private final String MY_UUID = "00001101-0000-1000-8000-00805F9B34FB";private final BluetoothSocket socket;private final BluetoothDevice device;public ConnectThread(BluetoothDevice device) {this.device = device;BluetoothSocket tmp = null;try {tmp = device.createRfcommSocketToServiceRecord(UUID.fromString(MY_UUID));} catch (IOException e) {e.printStackTrace();}this.socket = tmp;}public void run() {bluetoothAdapter.cancelDiscovery();try {socket.connect();connectedThread = new ConnectedThread(socket);connectedThread.start();} catch (IOException e) {try {socket.close();} catch (IOException ee) {ee.printStackTrace();}return;}//manageConnectedSocket(socket);}public void cancel() {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}客戶(hù)端與服務(wù)器端建立連接成功后,需要ConnectedThread類(lèi)接收發(fā)送數(shù)據(jù):
// 客戶(hù)端與服務(wù)器建立連接成功后,用ConnectedThread收發(fā)數(shù)據(jù)private class ConnectedThread extends Thread {private final BluetoothSocket socket;private final InputStream inputStream;private final OutputStream outputStream;public ConnectedThread(BluetoothSocket socket) {this.socket = socket;InputStream input = null;OutputStream output = null;try {input = socket.getInputStream();output = socket.getOutputStream();} catch (IOException e) {e.printStackTrace();}this.inputStream = input;this.outputStream = output;}public void run() {byte[] buff = new byte[1024];int bytes;while (true) {try {bytes = inputStream.read(buff);String str = new String(buff, "ISO-8859-1");str = str.substring(0, bytes);Log.e("recv", str);} catch (IOException e) {e.printStackTrace();break;}}}public void write(byte[] bytes) {try {outputStream.write(bytes);} catch (IOException e) {e.printStackTrace();}}public void cancel() {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}到此為止就是藍(lán)牙開(kāi)發(fā)的大致步驟,其中沒(méi)有涉及到藍(lán)牙客戶(hù)端建立連接類(lèi),不過(guò)可查閱BLE和經(jīng)典藍(lán)牙Android開(kāi)發(fā)。
3、畢設(shè)藍(lán)牙APP介紹
畢設(shè)藍(lán)牙APP需要接收單片機(jī)通過(guò)藍(lán)牙模塊發(fā)送上來(lái)的數(shù)據(jù),并且藍(lán)牙APP也可以給單片機(jī)發(fā)送數(shù)據(jù)來(lái)進(jìn)行控制。頁(yè)面布局如下,一個(gè)是整體頁(yè)面,一個(gè)是設(shè)置頁(yè)面,測(cè)試手機(jī)是魅藍(lán)note。因?yàn)楫呍O(shè)做的是十字路口紅綠燈控制系統(tǒng),所有頁(yè)面布局有4個(gè)LED燈,分別代表路口的4個(gè)紅綠燈,會(huì)根據(jù)時(shí)間不同顯示不同的顏色(紅/綠/黃),并且會(huì)顯示倒計(jì)時(shí),最后來(lái)一張紅綠燈系統(tǒng)整體圖。



activity_main.xml文件如下:
<?xml version="1.0" encoding="utf-8"?><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"android:layout_height="wrap_content" android:paddingLeft="@dimen/activity_horizontal_margin"android:paddingRight="@dimen/activity_horizontal_margin"android:paddingTop="@dimen/activity_vertical_margin"android:paddingBottom="@dimen/activity_vertical_margin" tools:context=".MainActivity"><LinearLayoutandroid:id="@+id/linear_layout_top"android:layout_alignParentTop="true"android:layout_width="match_parent"android:layout_height="40dp"><TextViewandroid:id="@+id/notice_view"android:layout_width="0dp"android:layout_height="40dp"android:text="藍(lán)牙未開(kāi)啟"android:layout_weight="3"/><TextViewandroid:id="@+id/notice_recv_view"android:layout_width="0dp"android:layout_height="30dp"android:layout_weight="3"/><TextViewandroid:id="@+id/notice_send_view"android:layout_width="0dp"android:layout_height="30dp"android:layout_weight="3"/><Buttonandroid:id="@+id/turn_on_off"android:layout_width="0dp"android:layout_height="40dp"android:layout_weight="2"android:text="ON"/></LinearLayout><TextViewandroid:id="@+id/led1"android:layout_centerHorizontal="true"android:layout_below="@+id/linear_layout_top"android:layout_width="40dp"android:layout_height="20dp"android:gravity="center"android:text="LED1"/><TextViewandroid:id="@+id/led0"android:layout_centerHorizontal="true"android:layout_below="@+id/led1"android:layout_width="40dp"android:layout_height="20dp"android:gravity="center"android:text="+"/><TextViewandroid:id="@+id/led3"android:layout_below="@+id/led1"android:layout_toLeftOf="@+id/led1"android:layout_width="40dp"android:layout_height="20dp"android:gravity="center"android:text="LED3"/><TextViewandroid:id="@+id/led2"android:layout_centerHorizontal="true"android:layout_below="@+id/led3"android:layout_width="40dp"android:layout_height="20dp"android:gravity="center"android:text="LED2"/><TextViewandroid:id="@+id/led4"android:layout_below="@+id/led1"android:layout_toRightOf="@+id/led1"android:layout_width="40dp"android:layout_height="20dp"android:gravity="center"android:text="LED4"/><ScrollViewandroid:id="@+id/scroll_view"android:layout_below="@+id/led2"android:layout_above="@+id/linear_layout_bottom"android:layout_width="match_parent"android:layout_height="match_parent"><TextViewandroid:id="@+id/recv_view"android:text=""android:layout_width="wrap_content"android:layout_height="wrap_content" /></ScrollView><LinearLayoutandroid:id="@+id/linear_layout_bottom"android:layout_alignParentBottom="true"android:layout_width="match_parent"android:layout_height="50dp"><Buttonandroid:id="@+id/clear_recv_view"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:text="clear" /><EditTextandroid:id="@+id/send_text"android:layout_width="0dp"android:layout_height="wrap_content"android:layout_weight="3"android:hint="輸入框,默認(rèn)@#結(jié)尾"/><Buttonandroid:id="@+id/send"android:layout_width="0dp"android:layout_height="match_parent"android:layout_weight="1"android:text="send" /></LinearLayout></RelativeLayout>
MainActivity.java文件如下:
package com.luoxn28.bluetooth;import android.bluetooth.BluetoothAdapter;import android.bluetooth.BluetoothDevice;import android.bluetooth.BluetoothSocket;import android.content.Intent;import android.graphics.Color;import android.os.Bundle;import android.os.Message;import android.support.v7.app.ActionBarActivity;import android.view.Menu;import android.view.MenuItem;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.ScrollView;import android.widget.TextView;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.Set;import java.util.UUID;public class MainActivity extends ActionBarActivity implements View.OnClickListener {public static final int RECV_VIEW = 0;public static final int NOTICE_VIEW = 1;private BluetoothAdapter bluetoothAdapter = null;private ConnectThread connectThread = null;private ConnectedThread connectedThread = null;private TextView noticeView = null;private Button turnOnOff = null;private TextView led0, led1, led2, led3, led4;ScrollView scrollView = null;private TextView recvView = null;private Button clearRecvView = null;private EditText sendText = null;private Button send = null;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);// 獲取BluetoothAdapterbluetoothAdapter = BluetoothAdapter.getDefaultAdapter();if (bluetoothAdapter == null) {// Device does not support Bluetoothreturn;}// 注冊(cè)監(jiān)聽(tīng)事件noticeView = (TextView) findViewById(R.id.notice_view);turnOnOff = (Button) findViewById(R.id.turn_on_off);led0 = (TextView) findViewById(R.id.led0);led1 = (TextView) findViewById(R.id.led1);led2 = (TextView) findViewById(R.id.led2);led3 = (TextView) findViewById(R.id.led3);led4 = (TextView) findViewById(R.id.led4);scrollView = (ScrollView) findViewById(R.id.scroll_view);recvView = (TextView) findViewById(R.id.recv_view);clearRecvView = (Button) findViewById(R.id.clear_recv_view);sendText = (EditText) findViewById(R.id.send_text);send = (Button) findViewById(R.id.send);turnOnOff.setOnClickListener(this);clearRecvView.setOnClickListener(this);send.setOnClickListener(this);if (!bluetoothAdapter.isEnabled()) {noticeView.setText("藍(lán)牙未開(kāi)啟");}else {noticeView.setText("藍(lán)牙已開(kāi)啟");}noticeView.setBackgroundColor(Color.GRAY);led0.setBackgroundColor(Color.GRAY);led1.setBackgroundColor(Color.GRAY);led2.setBackgroundColor(Color.GRAY);led3.setBackgroundColor(Color.GRAY);led4.setBackgroundColor(Color.GRAY);}private boolean isOn = false;@Overridepublic void onClick(View view) {switch (view.getId()) {case R.id.turn_on_off: // 發(fā)送'0'或者'1'都可以if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) {Toast.makeText(this, "藍(lán)牙未開(kāi)啟", Toast.LENGTH_SHORT).show();break;}if (connectedThread == null) {Toast.makeText(this, "未連接設(shè)備", Toast.LENGTH_SHORT).show();break;}String turn_string = "1@#";connectedThread.write(turn_string.getBytes());if (isOn == false) {isOn = true; // 打開(kāi)了turnOnOff.setText("OFF");led1.setText("");led2.setText("");led3.setText("");led4.setText("");}else {isOn = false; // 關(guān)閉了turnOnOff.setText("ON");led1.setText("LED1");led2.setText("LED2");led3.setText("LED3");led4.setText("LED4");}break;case R.id.clear_recv_view: // 清空接收框recvView.setText("");break;case R.id.send: // 發(fā)送數(shù)據(jù),默認(rèn)以"@#"結(jié)尾if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) {Toast.makeText(this, "藍(lán)牙未開(kāi)啟", Toast.LENGTH_SHORT).show();return;}if (connectedThread == null) {Toast.makeText(this, "未連接設(shè)備", Toast.LENGTH_SHORT).show();break;}String inputText = sendText.getText().toString() + "@#"; // 發(fā)送給單片機(jī)數(shù)據(jù)以"@#結(jié)尾",這樣單片機(jī)知道一條數(shù)據(jù)發(fā)送結(jié)束//Toast.makeText(MainActivity.this, inputText, Toast.LENGTH_SHORT).show();connectedThread.write(inputText.getBytes());break;default:break;}}private android.os.Handler handler = new android.os.Handler() {public void handleMessage(Message msg) {Bundle bundle = null;switch (msg.what) {case RECV_VIEW:if (isOn == false) {isOn = true;turnOnOff.setText("OFF");}bundle = msg.getData();String recv = bundle.getString("recv");recvView.append(recv + "/n");scrollView.fullScroll(ScrollView.FOCUS_DOWN); // 滾動(dòng)到底部if (recv.isEmpty() || recv.contains(" ") || recv.contains("#")) {break;}int num = Integer.valueOf(recv) / 2; // 0-60sif (num <= 20) {led1.setText("");led2.setText("");led3.setText("");led4.setText("");led1.setBackgroundColor(Color.RED);led2.setBackgroundColor(Color.RED);led3.setBackgroundColor(Color.GREEN);led4.setBackgroundColor(Color.GREEN);}else if (num < 30) {int n = 30 - num;led1.setText("" + n);led2.setText("" + n);if (num < 28) {led3.setBackgroundColor(Color.GREEN);led4.setBackgroundColor(Color.GREEN);}else {led3.setBackgroundColor(Color.YELLOW);led4.setBackgroundColor(Color.YELLOW);}}else if (num <= 50) {led1.setText("");led2.setText("");led3.setText("");led4.setText("");led1.setBackgroundColor(Color.GREEN);led2.setBackgroundColor(Color.GREEN);led3.setBackgroundColor(Color.RED);led4.setBackgroundColor(Color.RED);}else {int n = 60 - num;led3.setText("" + n);led4.setText("" + n);if (num < 58) {led1.setBackgroundColor(Color.GREEN);led2.setBackgroundColor(Color.GREEN);}else {led1.setBackgroundColor(Color.YELLOW);led2.setBackgroundColor(Color.YELLOW);}}break;case NOTICE_VIEW:bundle = msg.getData();String notice = bundle.getString("notice");noticeView.setText(notice);break;default:break;}}};@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.menu_main, menu);return true;}@Overridepublic boolean onOptionsItemSelected(MenuItem item) {int id = item.getItemId();if (id == R.id.start_bluetooth) {if (bluetoothAdapter != null) {// 開(kāi)啟藍(lán)牙int REQUEST_ENABLE_BT = 1;if (!bluetoothAdapter.isEnabled()) {Intent intent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);startActivityForResult(intent, REQUEST_ENABLE_BT);noticeView.setText("開(kāi)啟藍(lán)牙成功");//Toast.makeText(this, "開(kāi)啟藍(lán)牙成功", Toast.LENGTH_SHORT).show();} else {Toast.makeText(this, "藍(lán)牙已開(kāi)啟", Toast.LENGTH_SHORT).show();}}return true;}else if (id == R.id.show_devices) {if (bluetoothAdapter != null) {if (!bluetoothAdapter.isEnabled()) {Toast.makeText(this, "藍(lán)牙未開(kāi)啟", Toast.LENGTH_SHORT).show();return true;}// 查詢(xún)配對(duì)設(shè)備List<String> devices = new ArrayList<String>();Set<BluetoothDevice> bondedDevices = bluetoothAdapter.getBondedDevices();for (BluetoothDevice device : bondedDevices) {devices.add(device.getName() + "-" + device.getAddress());}StringBuilder text = new StringBuilder();for (String device : devices) {text.append(device + "/n");}Toast.makeText(this, text, Toast.LENGTH_SHORT).show();}return true;}else if (id == R.id.find_devices) {Toast.makeText(this, "該功能暫時(shí)不可用", Toast.LENGTH_SHORT).show();}else if (id == R.id.connect_devices) {if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) {Toast.makeText(this, "藍(lán)牙未開(kāi)啟", Toast.LENGTH_SHORT).show();return true;}// 查詢(xún)配對(duì)設(shè)備 建立連接,只能連接第一個(gè)配對(duì)的設(shè)備List<String> devices = new ArrayList<String>();Set<BluetoothDevice> bondedDevices = bluetoothAdapter.getBondedDevices();for (BluetoothDevice device : bondedDevices) {connectThread = new ConnectThread(device);connectThread.start();//Toast.makeText(this, "連接成功", Toast.LENGTH_SHORT).show();break;}}return super.onOptionsItemSelected(item);}private class ConnectThread extends Thread {private final String MY_UUID = "00001101-0000-1000-8000-00805F9B34FB";private final BluetoothSocket socket;private final BluetoothDevice device;public ConnectThread(BluetoothDevice device) {this.device = device;BluetoothSocket tmp = null;try {tmp = device.createRfcommSocketToServiceRecord(UUID.fromString(MY_UUID));} catch (IOException e) {e.printStackTrace();}this.socket = tmp;}public void run() {bluetoothAdapter.cancelDiscovery();try {socket.connect();connectedThread = new ConnectedThread(socket);connectedThread.start();} catch (IOException e) {try {socket.close();} catch (IOException ee) {ee.printStackTrace();}return;}//manageConnectedSocket(socket);}public void cancel() {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}// 客戶(hù)端與服務(wù)器建立連接成功后,用ConnectedThread收發(fā)數(shù)據(jù)private class ConnectedThread extends Thread {private final BluetoothSocket socket;private final InputStream inputStream;private final OutputStream outputStream;public ConnectedThread(BluetoothSocket socket) {this.socket = socket;InputStream input = null;OutputStream output = null;try {input = socket.getInputStream();output = socket.getOutputStream();} catch (IOException e) {e.printStackTrace();}this.inputStream = input;this.outputStream = output;}public void run() {StringBuilder recvText = new StringBuilder();byte[] buff = new byte[1024];int bytes;Bundle tmpBundle = new Bundle();Message tmpMessage = new Message();tmpBundle.putString("notice", "連接成功");tmpMessage.what = NOTICE_VIEW;tmpMessage.setData(tmpBundle);handler.sendMessage(tmpMessage);while (true) {try {bytes = inputStream.read(buff);String str = new String(buff, "ISO-8859-1");str = str.substring(0, bytes);// 收到數(shù)據(jù),單片機(jī)發(fā)送上來(lái)的數(shù)據(jù)以"#"結(jié)束,這樣手機(jī)知道一條數(shù)據(jù)發(fā)送結(jié)束//Log.e("read", str);if (!str.endsWith("#")) {recvText.append(str);continue;}recvText.append(str.substring(0, str.length() - 1)); // 去除'#'Bundle bundle = new Bundle();Message message = new Message();bundle.putString("recv", recvText.toString());message.what = RECV_VIEW;message.setData(bundle);handler.sendMessage(message);recvText.replace(0, recvText.length(), "");} catch (IOException e) {e.printStackTrace();break;}}}public void write(byte[] bytes) {try {outputStream.write(bytes);} catch (IOException e) {e.printStackTrace();}}public void cancel() {try {socket.close();} catch (IOException e) {e.printStackTrace();}}}}menu_main.xml文件如下:
<menu xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools" tools:context=".MainActivity"><itemandroid:id="@+id/show_devices"android:title="@string/show_devices"android:orderInCategory="100"app:showAsAction="never" /><itemandroid:id="@+id/start_bluetooth"android:title="@string/start_bluetooth"android:orderInCategory="100"app:showAsAction="never" /><itemandroid:id="@+id/find_devices"android:title="@string/find_devices"android:orderInCategory="100"app:showAsAction="never" /><itemandroid:id="@+id/connect_devices"android:title="@string/connect_devices"android:orderInCategory="100"app:showAsAction="never" /></menu>
strings.xml文件如下:
<resources><string name="app_name">BlueTooth</string><string name="action_settings">Settings</string><string name="start_bluetooth">開(kāi)啟藍(lán)牙</string><string name="show_devices">查詢(xún)配對(duì)設(shè)備</string><string name="find_devices">搜索設(shè)備</string><string name="connect_devices">連接設(shè)備</string></resources>
到這里整個(gè)APP已經(jīng)開(kāi)發(fā)完成,親測(cè)可用,如果有什么錯(cuò)誤,歡迎評(píng)論指正談?wù)揯_^。
到此,本文全部?jī)?nèi)容就給大家介紹完了,親自測(cè)試過(guò),代碼安全可靠,放心實(shí)用,如果有任何問(wèn)題歡迎給我留言,小編會(huì)及時(shí)回復(fù)的!
新聞熱點(diǎn)
疑難解答
圖片精選
網(wǎng)友關(guān)注