Flutter如何实现蓝牙设备选中后自动连接、打印完成后自动断开
Flutter蓝牙热敏打印机自动连接/断开实现方案
以下是针对你需求的最小改动方案,所有修改位置都做了标注:
一、核心修改点
1. 下拉选中设备自动连接
找到DropdownButton组件的onChanged回调,修改为选中设备后直接触发连接逻辑,同时先断开已有连接避免冲突。
同时优化_connect、_disconnect方法为异步,确保状态同步正确。
2. 打印完成自动断开
修改打印按钮的点击回调,等待打印任务完成后延迟几秒(确保打印机接收完所有数据)再自动触发断开操作。
二、修改后的完整代码
import 'dart:io'; import 'dart:typed_data'; import 'package:blue_thermal_printer_example/testprint.dart'; import 'package:flutter/material.dart'; import 'dart:async'; import 'package:blue_thermal_printer/blue_thermal_printer.dart'; import 'package:flutter/services.dart'; import 'package:path_provider/path_provider.dart'; void main() => runApp(const MyApp()); class MyApp extends StatefulWidget { const MyApp({super.key}); @override _MyAppState createState() => _MyAppState(); } class _MyAppState extends State<MyApp> { final BlueThermalPrinter bluetooth = BlueThermalPrinter.instance; List<BluetoothDevice> _devices = []; BluetoothDevice? _device; bool _connected = false; String? pathImage; late TestPrint testPrint; @override void initState() { super.initState(); initPlatformState(); initSavetoPath(); testPrint = TestPrint(); } Future<void> initSavetoPath() async { const filename = 'yourlogo.png'; var bytes = await rootBundle.load("assets/images/yourlogo.png"); String dir = (await getApplicationDocumentsDirectory()).path; writeToFile(bytes, '$dir/$filename'); setState(() { pathImage = '$dir/$filename'; }); } Future<void> initPlatformState() async { bool isConnected = await bluetooth.isConnected; List<BluetoothDevice> devices = []; try { devices = await bluetooth.getBondedDevices(); } on PlatformException catch (e) { show('获取设备列表失败:$e'); } bluetooth.onStateChanged().listen((state) { if (!mounted) return; switch (state) { case BlueThermalPrinter.CONNECTED: setState(() { _connected = true; }); break; case BlueThermalPrinter.DISCONNECTED: setState(() { _connected = false; }); break; default: print(state); break; } }); if (!mounted) return; setState(() { _devices = devices; }); if (isConnected) { setState(() { _connected = true; }); } } @override Widget build(BuildContext context) { return MaterialApp( home: Scaffold( appBar: AppBar( title: const Text('蓝牙热敏打印机'), ), body: Container( child: Padding( padding: const EdgeInsets.all(8.0), child: ListView( children: <Widget>[ Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.start, children: <Widget>[ const SizedBox( width: 10, ), const Text( '选择设备:', style: TextStyle( fontWeight: FontWeight.bold, ), ), const SizedBox( width: 30, ), Expanded( // 下拉选择自动连接修改点 child: DropdownButton<BluetoothDevice>( isExpanded: true, items: _getDeviceItems(), onChanged: (value) async { setState(() => _device = value); if (_connected) { await _disconnect(); } _connect(); }, value: _device, hint: const Text('请选择打印机'), ), ), ], ), const SizedBox( height: 10, ), Row( crossAxisAlignment: CrossAxisAlignment.center, mainAxisAlignment: MainAxisAlignment.end, children: <Widget>[ ElevatedButton( style: ElevatedButton.styleFrom(backgroundColor: Colors.brown), onPressed: () { initPlatformState(); }, child: const Text( '刷新设备', style: TextStyle(color: Colors.white), ), ), const SizedBox( width: 20, ), ElevatedButton( style: ElevatedButton.styleFrom( backgroundColor: _connected ? Colors.red : Colors.green), onPressed: _connected ? _disconnect : _connect, child: Text( _connected ? '断开连接' : '手动连接', style: const TextStyle(color: Colors.white), ), ), ], ), Padding( padding: const EdgeInsets.only(left: 10.0, right: 10.0, top: 50), child: ElevatedButton( style: ElevatedButton.styleFrom(backgroundColor: Colors.brown), // 打印完成自动断开修改点 onPressed: () async { if (_device == null) { show('请先选择打印机'); return; } if (!_connected) { show('打印机未连接'); return; } if (pathImage == null) { show('资源加载中,请稍后再试'); return; } // 等待打印完成,需确保TestPrint的sample方法是异步返回Future await testPrint.sample(pathImage!); // 延迟2秒确保数据传输完成,可根据打印内容长度调整 await Future.delayed(const Duration(seconds: 2)); await _disconnect(); show('打印完成,已自动断开连接'); }, child: const Text('打印测试', style: TextStyle(color: Colors.white)), ), ), ], ), ), ), ), ); } List<DropdownMenuItem<BluetoothDevice>> _getDeviceItems() { List<DropdownMenuItem<BluetoothDevice>> items = []; if (_devices.isEmpty) { items.add(const DropdownMenuItem( value: null, child: Text('暂无可用设备'), )); } else { for (var device in _devices) { items.add(DropdownMenuItem( value: device, child: Text(device.name ?? '未知设备'), )); } } return items; } // 优化后的连接方法 Future<void> _connect() async { if (_device == null) { show('未选择任何设备'); return; } bool isConnected = await bluetooth.isConnected; if (!isConnected) { try { await bluetooth.connect(_device!); if (mounted) { setState(() => _connected = true); } show('连接成功'); } catch (e) { if (mounted) { setState(() => _connected = false); } show('连接失败:$e'); } } } // 优化后的断开方法 Future<void> _disconnect() async { await bluetooth.disconnect(); if (mounted) { setState(() => _connected = false); } } Future<void> writeToFile(ByteData data, String path) { final buffer = data.buffer; return File(path).writeAsBytes( buffer.asUint8List(data.offsetInBytes, data.lengthInBytes)); } Future show( String message, { Duration duration = const Duration(seconds: 3), }) async { await Future.delayed(const Duration(milliseconds: 100)); if (mounted) { ScaffoldMessenger.of(context).showSnackBar( SnackBar( content: Text( message, style: const TextStyle( color: Colors.white, ), ), duration: duration, ), ); } } }
三、注意事项
- 请确保
TestPrint类中的sample方法为异步方法,返回Future<void>,否则无法正确等待打印完成,示例如下:
// TestPrint类中的sample方法修改示例 Future<void> sample(String pathImage) async { // 原有打印逻辑,所有调用blue_thermal_printer的方法前加await await BlueThermalPrinter.instance.printNewLine(); await BlueThermalPrinter.instance.printImage(pathImage); // ...其他打印逻辑 }
- 打印后的延迟时间可根据实际打印内容长度调整,打印二维码、长文本时建议调长到3-5秒
- 已适配空安全语法,如果你使用的是旧版Flutter可移除空安全相关符号(
?、!、late、super.key)
内容的提问来源于stack exchange,提问作者Newbie
相关产品推荐
相关产品推荐

