作业题目:
根据课内的学习网址进行蓝牙通信的简要设计与开发。
https://developer.android.google.cn/guide/topics/connectivity/bluetooth
http://www.android-doc.com/guide/topics/connectivity/bluetooth.html
https://www.jianshu.com/p/8fbbc6723a7c
https://blog.csdn.net/weixin_39079048/article/details/78923669
一、新建工程BlueTooth,在AndroidManifest.xml中添加权限申请
<uses-permission android:name="android.permission.BLUETOOTH" />
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
二、设计界面activity_main
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<Button
android:id="@+id/btn_openBT"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/open_bt"/>
<Button
android:layout_marginTop="10dp"
android:id="@+id/btn_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/search"/>
<TextView
android:layout_marginTop="10dp"
android:id="@+id/text_state"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/connect_state"/>
<Button
android:layout_marginTop="10dp"
android:id="@+id/btn_send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/send_msg"/>
<TextView
android:layout_marginTop="10dp"
android:id="@+id/text_msg"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ListView
android:layout_marginTop="10dp"
android:id="@+id/listView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</LinearLayout>
三、bluetooth_device_list_item的设计
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="horizontal" android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="58dp"
android:padding="5dp">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:id="@+id/device_name"
android:gravity="center_vertical"
android:textColor="#000"/>
<TextView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/device_info"
android:gravity="center_vertical|right"
android:textColor="#000"/>
</LinearLayout>
三、MainActivity的编写
package com.example.bluetooth;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothServerSocket;
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 androidx.appcompat.app.AppCompatActivity;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Set;
import java.util.UUID;
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
private BluetoothAdapter bTAdatper;
private ListView listView;
private BlueToothDeviceAdapter adapter;
private TextView text_state;
private TextView text_msg;
private final int BUFFER_SIZE = 1024;
private static final String NAME = "BT_DEMO";
private static final UUID BT_UUID = UUID.fromString("02001101-0001-1000-8080-00805F9BA9BA");
private ConnectThread connectThread;
private ListenerThread listenerThread;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initView();
bTAdatper = BluetoothAdapter.getDefaultAdapter();
initReceiver();
listenerThread = new ListenerThread();
listenerThread.start();
}
private void initView() {
findViewById(R.id.btn_openBT).setOnClickListener(this);
findViewById(R.id.btn_search).setOnClickListener(this);
findViewById(R.id.btn_send).setOnClickListener(this);
text_state = (TextView) findViewById(R.id.text_state);
text_msg = (TextView) findViewById(R.id.text_msg);
listView = (ListView) findViewById(R.id.listView);
adapter = new BlueToothDeviceAdapter(getApplicationContext(), R.layout.bluetooth_device_list_item);
listView.setAdapter(adapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (bTAdatper.isDiscovering()) {
bTAdatper.cancelDiscovery();
}
BluetoothDevice device = (BluetoothDevice) adapter.getItem(position);
//连接设备
connectDevice(device);
}
});
}
private void initReceiver() {
//注册广播
IntentFilter filter = new IntentFilter();
filter.addAction(BluetoothDevice.ACTION_FOUND);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_STARTED);
filter.addAction(BluetoothAdapter.ACTION_DISCOVERY_FINISHED);
registerReceiver(mReceiver, filter);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_openBT:
openBlueTooth();
break;
case R.id.btn_search:
searchDevices();
break;
case R.id.btn_send:
if (connectThread != null) {
connectThread.sendMsg("这是蓝牙发送过来的消息");
}
break;
}
}
/**
* 开启蓝牙
*/
private void openBlueTooth() {
if (bTAdatper == null) {
Toast.makeText(this, "当前设备不支持蓝牙功能", Toast.LENGTH_SHORT).show();
}
if (!bTAdatper.isEnabled()) {
/* Intent i = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivity(i);*/
bTAdatper.enable();
}
//开启被其它蓝牙设备发现的功能
if (bTAdatper.getScanMode() != BluetoothAdapter.SCAN_MODE_CONNECTABLE_DISCOVERABLE) {
Intent i = new Intent(BluetoothAdapter.ACTION_REQUEST_DISCOVERABLE);
//设置为一直开启
i.putExtra(BluetoothAdapter.EXTRA_DISCOVERABLE_DURATION, 0);
startActivity(i);
}
}
/**
* 搜索蓝牙设备
*/
private void searchDevices() {
if (bTAdatper.isDiscovering()) {
bTAdatper.cancelDiscovery();
}
getBoundedDevices();
bTAdatper.startDiscovery();
}
/**
* 获取已经配对过的设备
*/
private void getBoundedDevices() {
//获取已经配对过的设备
Set<BluetoothDevice> pairedDevices = bTAdatper.getBondedDevices();
//将其添加到设备列表中
if (pairedDevices.size() > 0) {
for (BluetoothDevice device : pairedDevices) {
adapter.add(device);
}
}
}
/**
* 连接蓝牙设备
*/
private void connectDevice(BluetoothDevice device) {
text_state.setText(getResources().getString(R.string.connecting));
try {
//创建Socket
BluetoothSocket socket = device.createRfcommSocketToServiceRecord(BT_UUID);
//启动连接线程
connectThread = new ConnectThread(socket, true);
connectThread.start();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
//取消搜索
if (bTAdatper != null && bTAdatper.isDiscovering()) {
bTAdatper.cancelDiscovery();
}
//注销BroadcastReceiver,防止资源泄露
unregisterReceiver(mReceiver);
}
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
BluetoothDevice device = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
//避免重复添加已经绑定过的设备
if (device.getBondState() != BluetoothDevice.BOND_BONDED) {
adapter.add(device);
adapter.notifyDataSetChanged();
}
} else if (BluetoothAdapter.ACTION_DISCOVERY_STARTED.equals(action)) {
Toast.makeText(MainActivity.this, "开始搜索", Toast.LENGTH_SHORT).show();
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
Toast.makeText(MainActivity.this, "搜索完毕", Toast.LENGTH_SHORT).show();
}
}
};
/**
* 连接线程
*/
private class ConnectThread extends Thread {
private BluetoothSocket socket;
private boolean activeConnect;
InputStream inputStream;
OutputStream outputStream;
private ConnectThread(BluetoothSocket socket, boolean connect) {
this.socket = socket;
this.activeConnect = connect;
}
@Override
public void run() {
try {
//如果是自动连接 则调用连接方法
if (activeConnect) {
socket.connect();
}
text_state.post(new Runnable() {
@Override
public void run() {
text_state.setText(getResources().getString(R.string.connect_success));
}
});
inputStream = socket.getInputStream();
outputStream = socket.getOutputStream();
byte[] buffer = new byte[BUFFER_SIZE];
int bytes;
while (true) {
//读取数据
bytes = inputStream.read(buffer);
if (bytes > 0) {
final byte[] data = new byte[bytes];
System.arraycopy(buffer, 0, data, 0, bytes);
text_msg.post(new Runnable() {
@Override
public void run() {
text_msg.setText(getResources().getString(R.string.get_msg)+new String(data));
}
});
}
}
} catch (IOException e) {
e.printStackTrace();
text_state.post(new Runnable() {
@Override
public void run() {
text_state.setText(getResources().getString(R.string.connect_error));
}
});
}
}
/**
* 发送数据
*
* @param msg
*/
public void sendMsg(final String msg) {
byte[] bytes = msg.getBytes();
if (outputStream != null) {
try {
//发送数据
outputStream.write(bytes);
text_msg.post(new Runnable() {
@Override
public void run() {
text_msg.setText(getResources().getString(R.string.send_msgs)+msg);
}
});
} catch (IOException e) {
e.printStackTrace();
text_msg.post(new Runnable() {
@Override
public void run() {
text_msg.setText(getResources().getString(R.string.send_msg_error)+msg);
}
});
}
}
}
}
/**
* 监听线程
*/
private class ListenerThread extends Thread {
private BluetoothServerSocket serverSocket;
private BluetoothSocket socket;
@Override
public void run() {
try {
serverSocket = bTAdatper.listenUsingRfcommWithServiceRecord(
NAME, BT_UUID);
while (true) {
//线程阻塞,等待别的设备连接
socket = serverSocket.accept();
text_state.post(new Runnable() {
@Override
public void run() {
text_state.setText(getResources().getString(R.string.connecting));
}
});
connectThread = new ConnectThread(socket, false);
connectThread.start();
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
四、BlueToothDeviceAdapter的编写
package com.example.bluetooth;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.TextView;
public class BlueToothDeviceAdapter extends ArrayAdapter<BluetoothDevice> {
private final LayoutInflater mInflater;
private int mResource;
public BlueToothDeviceAdapter(Context context, int resource) {
super(context, resource);
mInflater = LayoutInflater.from(context);
mResource = resource;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = mInflater.inflate(mResource, parent, false);
}
TextView name = (TextView) convertView.findViewById(R.id.device_name);
TextView info = (TextView) convertView.findViewById(R.id.device_info);
BluetoothDevice device = getItem(position);
name.setText(device.getName());
info.setText(device.getAddress());
return convertView;
}
}
附上dimens、colors、strings三个values内的xml文件
<?xml version="1.0" encoding="utf-8"?>
<resources>
<!-- Default screen margins, per the Android Design guidelines. -->
<dimen name="activity_horizontal_margin">16dp</dimen>
<dimen name="activity_vertical_margin">16dp</dimen>
</resources>
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
</resources>
<resources>
<string name="app_name">Bluetooth</string>
<string name="open_bt">打开蓝牙</string>
<string name="search">搜索设备</string>
<string name="send_msg">发送消息</string>
<string name="connect_error">连接失败</string>
<string name="connect_success">连接成功</string>
<string name="connecting">连接中</string>
<string name="connect_state">连接状态</string>
<string name="send_msgs">发送数据:</string>
<string name="send_msg_error">发送数据失败:</string>
<string name="get_msg">获取到数据:</string>
</resources>
下载到两个手机后,首先两个手机事先需要在设置->蓝牙那连接一次,让对方进入自己的已配对设备名单,然后运行app,结果如图: