Android Studio 开发(四)–蓝牙通信
本次Github代码仓库 --crcr1013/BlueToothDemo
文章目录
- Android Studio 开发(四)--蓝牙通信
- 一、成果要求
- 二、关键步骤
- 1、工程结构
- 2、清单文件注册权限
- 3、准备设计资源
- 4、设计布局
- 5.编写蓝牙服务
- 6.启动项目
- 三、结果测试
一、成果要求
进行蓝牙通信的简要设计与开发。
二、关键步骤
1、工程结构
新建相应的活动组件、布局文件、准备好相应资源,确定整体架构。
(主活动组件MainActivity被重命名为BluetoothChat,它是蓝牙会话的主Activity组件程序。)
2、清单文件注册权限
<uses-permission android:name="android.permission.BLUETOOTH_ADMIN" />
<uses-permission android:name="android.permission.BLUETOOTH" />
3、准备设计资源
在文件res/values/strings.xml里,添加程序运行过程中的状态描述文本及配色代码等,其代码如下:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">蓝牙Demo</string>
<string name="send">发送</string>
<string name="not_connected">你没有链接一个设备</string>
<string name="bt_not_enabled_leaving">蓝牙不可用,离开聊天室</string>
<string name="title_connecting">链接中...</string>
<string name="title_connected_to">连接到:</string>
<string name="title_not_connected">无链接</string>
<string name="scanning">蓝牙设备搜索中...</string>
<string name="select_device">选择一个好友链接</string>
<string name="none_paired">没有配对好友</string>
<string name="none_found">附近没有发现好友</string>
<string name="title_paired_devices">已配对好友</string>
<string name="title_other_devices">其它可连接好友</string>
<string name="button_scan">搜索好友</string>
<string name="connect">我的好友</string>
<string name="discoverable">设置在线</string>
<string name="back">退出</string>
<string name="startVideo">开始聊天</string>
<string name="stopVideo">结束聊天</string>
</resources>
4、设计布局
在默认的主布局文件activity_main.xml里,添加1个Toolbar控件,其内包含2个水平的TextView控件;在Toolbar控件的下方添加1个ListView控件,用于显示聊天内容;最后在ListView控件的下方添加水平放置的1个EditText控件和一个Button控件。使用垂直线性布局并嵌套水平线性布局实现的代码如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/bg01">
<!--新版Android支持的Toolbar,对标题栏布局-->
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<TextView
android:id="@+id/title_left_text"
style="?android:attr/windowTitleStyle"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_weight="1"
android:gravity="left"
android:ellipsize="end"
android:singleLine="true" />
<TextView
android:id="@+id/title_right_text"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_weight="1"
android:ellipsize="end"
android:gravity="right"
android:singleLine="true"
android:textColor="#fff" />
</LinearLayout>
</android.support.v7.widget.Toolbar>
<ListView android:id="@+id/in"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:stackFromBottom="true"
android:transcriptMode="alwaysScroll"
android:layout_weight="1" />
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<EditText android:id="@+id/edit_text_out"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="bottom" />
<Button android:id="@+id/button_send"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/send"/>
</LinearLayout>
</LinearLayout>
5.编写蓝牙服务
1、编写用于蓝牙会话的服务组件ChatService,本质上是一个工具类,其文件代码如下:
(仅展示部分代码,完整代码可在github上查看)
/*
本程序ChatService是蓝牙会话的服务程序
定义了3个内部类:AcceptThread(接受新连接)、ConnectThread(发出连接)和ConnectedThread (已连接)
*/
public class ChatService {
//本应用的主Activity组件名称
private static final String NAME = "BluetoothChat";
// UUID:通用唯一识别码,是一个128位长的数字,一般用十六进制表示
//算法的核心思想是结合机器的网卡、当地时间、一个随机数来生成
//在创建蓝牙连接
private static final UUID MY_UUID = UUID.fromString("fa87c0d0-afac-11de-8a39-0800200c9a66");
private final BluetoothAdapter mAdapter;
private final Handler mHandler;
private AcceptThread mAcceptThread;
private ConnectThread mConnectThread;
private ConnectedThread mConnectedThread;
private int mState;
public static final int STATE_NONE = 0;
public static final int STATE_LISTEN = 1;
public static final int STATE_CONNECTING = 2;
public static final int STATE_CONNECTED = 3;
//构造方法,接收UI主线程传递的对象
public ChatService(Context context, Handler handler) {
//构造方法完成蓝牙对象的创建
mAdapter = BluetoothAdapter.getDefaultAdapter();
mState = STATE_NONE;
mHandler = handler;
}
private synchronized void setState(int state) {
mState = state;
mHandler.obtainMessage(BluetoothChat.MESSAGE_STATE_CHANGE, state, -1).sendToTarget();
}
public synchronized int getState() {
return mState;
}
public synchronized void start() {
if (mConnectThread != null) {
mConnectThread.cancel();
mConnectThread = null;
}
if (mConnectedThread != null) {
mConnectedThread.cancel();
mConnectedThread = null;
}
if (mAcceptThread == null) {
mAcceptThread = new AcceptThread();
mAcceptThread.start();
}
setState(STATE_LISTEN);
}
...
2、设计供主Activity使用的菜单文件res/menu/optionmenu.xml、选择好友(即已经配对过的蓝牙设备)的界面布局文件devicelist.xml。
**菜单文件option_menu.xml的代码如下:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android/apk/res/android">
<item android:id="@+id/scan"
android:icon="@android:drawable/ic_menu_myplaces"
android:title="@string/connect" />
<item android:id="@+id/discoverable"
android:icon="@android:drawable/ic_menu_view"
android:title="@string/discoverable" />
<item android:id="@+id/back"
android:icon="@android:drawable/ic_menu_close_clear_cancel"
android:title="@string/back" />
</menu>
**选择好友界面的布局文件device_list.xml的代码如下
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:id="@+id/title_paired_devices"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/title_paired_devices"
android:visibility="gone"
android:background="#666"
android:textColor="#fff"
android:paddingLeft="5dp" />
<ListView android:id="@+id/paired_devices"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1" />
<TextView android:id="@+id/title_new_devices"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/title_other_devices"
android:visibility="gone"
android:background="#666"
android:textColor="#fff"
android:paddingLeft="5dp" />
<!--android:visibility="gone"表示不占空间的隐藏,invisible是占空间-->
<ListView android:id="@+id/new_devices"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="2" />
<Button android:id="@+id/button_scan"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/button_scan" />
</LinearLayout>
3、 编写Activity组件DeviceList,实现选取与之会话的蓝牙设备,其文件代码如下:
/*
本程序供菜单项主界面的选项菜单“我的好友”调用,用于:
(1)显示已配对的好友列表;
(2)搜索可配对的好友进行配对
(3)新选择并配对的蓝牙设备将刷新好友列表
注意:发现新的蓝牙设备并请求配对时,需要对应接受
关键技术:动态注册一个广播接收者,处理蓝牙设备扫描的结果
*/
public class DeviceList extends AppCompatActivity {
private BluetoothAdapter mBtAdapter;
private ArrayAdapter<String> mPairedDevicesArrayAdapter;
private ArrayAdapter<String> mNewDevicesArrayAdapter;
public static String EXTRA_DEVICE_ADDRESS = "device_address"; //Mac地址
//定义广播接收者,用于处理扫描蓝牙设备后的结果
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) {
mNewDevicesArrayAdapter.add(device.getName() + "\n" + device.getAddress());
}
} else if (BluetoothAdapter.ACTION_DISCOVERY_FINISHED.equals(action)) {
if (mNewDevicesArrayAdapter.getCount() == 0) {
String noDevices = getResources().getText(R.string.none_found).toString();
mNewDevicesArrayAdapter.add(noDevices);
}
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.device_list);
//在被调用活动里,设置返回结果码
setResult(Activity.RESULT_CANCELED);
init(); //活动界面
}
......
4、编写蓝牙会话的主Activity组件程序BluetoothChat:
(不同的SDK API对权限的赋予要求不同,可增加动态赋予权限以及检查权限是否被赋予的函数,具体见github完整代码)
public class BluetoothChat extends AppCompatActivity {
public static final int MESSAGE_STATE_CHANGE = 1;
public static final int MESSAGE_READ = 2;
public static final int MESSAGE_WRITE = 3;
public static final int MESSAGE_DEVICE_NAME = 4;
public static final int MESSAGE_TOAST = 5;
public static final String DEVICE_NAME = "device_name";
public static final String TOAST = "toast";
private static final int REQUEST_CONNECT_DEVICE = 1; //请求连接设备
private static final int REQUEST_ENABLE_BT = 2;
private TextView mTitle;
private ListView mConversationView;
private EditText mOutEditText;
private Button mSendButton;
private String mConnectedDeviceName = null;
private ArrayAdapter<String> mConversationArrayAdapter;
private StringBuffer mOutStringBuffer;
private BluetoothAdapter mBluetoothAdapter = null;
private ChatService mChatService = null;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
getSupportActionBar().hide(); //隐藏标题栏
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this,new String[]{Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
}
}
Toolbar toolbar = findViewById(R.id.toolbar);
//创建选项菜单
toolbar.inflateMenu(R.menu.option_menu);
//选项菜单监听
toolbar.setOnMenuItemClickListener(new MyMenuItemClickListener());
mTitle = findViewById(R.id.title_left_text);
mTitle.setText(R.string.app_name);
mTitle = findViewById(R.id.title_right_text);
// 得到本地蓝牙适配器
checkBlePermission();
checkBleDevice();
mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
Toast.makeText(this, "蓝牙不可用", Toast.LENGTH_LONG).show();
finish();
return;
}
if (!mBluetoothAdapter.isEnabled()) { //若当前设备蓝牙功能未开启
Intent enableIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableIntent, REQUEST_ENABLE_BT); //
} else {
if (mChatService == null) {
setupChat(); //创建会话
}
}
}
6.启动项目
三、结果测试
生成apk包,安装到两个真机上进行测试。
1、生成release安装包
2、打开两个真机的蓝牙,进行配对
3、将该程序安装到两个真机上
在两个真机上均点击设置在线,允许蓝牙权限打开。
3、互相发送消息,并确认收到
Android Studio 打包APK(详细版)
更多推荐
## Android Studio 开发(四)--蓝牙通信
发布评论