Skip to content

Commit

Permalink
Fix closing of connection
Browse files Browse the repository at this point in the history
+ Tested multiple cases (including edufolly#60)
+ Fix try-catch for connecting inside `ChatPage` of example app
+ Minor updated debug log at disconnecting in platform code
+ `cancel` on `BluetoothConnection` is deprecated now, use `close` instead. 
  It was stupid to name `cancel` something that `close`s (it was even documented that way, lol).
- `cancel` on subscription of `input.listen` does not close connection (from now?)
- I think it might prevent easily detectable disconnection side ("was it by remote or locally")
  • Loading branch information
AgainPsychoX committed Aug 19, 2019
1 parent 12ef426 commit 3807530
Show file tree
Hide file tree
Showing 3 changed files with 48 additions and 26 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -1143,14 +1143,14 @@ protected void onDisconnected(boolean byRemote) {
@Override
public void run() {
if (byRemote) {
Log.d(TAG, "Connection onDisconnected by remote");
Log.d(TAG, "onDisconnected by remote (id: " + id + ")");
if (readSink != null) {
readSink.endOfStream();
readSink = null;
}
}
else {
Log.d(TAG, "Connection onDisconnected by local");
Log.d(TAG, "onDisconnected by local (id: " + id + ")");
}
}
});
Expand Down
28 changes: 15 additions & 13 deletions example/lib/ChatPage.dart
Original file line number Diff line number Diff line change
Expand Up @@ -37,21 +37,23 @@ class _ChatPage extends State<ChatPage> {
@override
void initState() {
super.initState();
try {
BluetoothConnection.toAddress(widget.server.address).then((_connection) {
print('Connected to the device');
connection = _connection;
setState(() {
isConnecting = false;
});

connection.input.listen(_onDataReceived).onDone(() {
print('Disconnected by remote request');
});

BluetoothConnection.toAddress(widget.server.address).then((_connection) {
print('Connected to the device');
connection = _connection;
setState(() {
isConnecting = false;
});
} catch (exception) {

connection.input.listen(_onDataReceived).onDone(() {
if (this.mounted) {
setState(() {});
}
});
}).catchError((error) {
print('Cannot connect, exception occured');
}
print(error);
});
}

@override
Expand Down
42 changes: 31 additions & 11 deletions lib/BluetoothConnection.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,24 @@
part of flutter_bluetooth_serial;

/// Represents Bluetooth connection to remote device.
/// Represents ongoing Bluetooth connection to remote device.
class BluetoothConnection {
// Note by PsychoX at 2019-08-19 while working on issue #60:
// Fixed and then tested whole thing multiple times:
// - [X] basic `connect`, use `output`/`input` and `disconnect` by local scenario,
// - [X] fail on connecting to device that isn't listening,
// - [X] working `output` if no `listen`ing to `input`,
// - [X] closing by local if no `input` written,
// - [X] closing by local if no `listen`ing to `input` (this was the #60),
// - [X] closing by remote if no `input` written,
// - [X] closing by remote if no `listen`ing to `input`,
// It works, but library user is notifed either by error on `output.add` or
// by observing `connection.isConnected`. In "normal" conditions user can
// listen to `input` even just for the `onDone` to proper detect closing.
//

/// This ID identifies real full `BluetoothConenction` object on platform side code.
final int _id;

final EventChannel _readChannel;
StreamSubscription<Uint8List> _readStreamSubscription;
StreamController<Uint8List> _readStreamController;
Expand All @@ -31,14 +45,12 @@ class BluetoothConnection {
this._id = id,
this._readChannel = EventChannel('${FlutterBluetoothSerial.namespace}/read/$id')
{
_readStreamController = StreamController<Uint8List>(onCancel: () {
cancel();
});
_readStreamController = StreamController<Uint8List>();

_readStreamSubscription = _readChannel.receiveBroadcastStream().cast<Uint8List>().listen(
_readStreamController.add,
onError: _readStreamController.addError,
onDone: _readStreamController.close,
onDone: this.close,
);

input = _readStreamController.stream;
Expand All @@ -61,16 +73,24 @@ class BluetoothConnection {


/// Closes connection (rather immediately), in result should also disconnect.
Future<void> cancel() async {
await output.close();
await _readStreamController.close();
await _readStreamSubscription.cancel();
Future<void> close() {
return Future.wait([
output.close(),
_readStreamSubscription.cancel(),
(!_readStreamController.isClosed)
? _readStreamController.close()
: Future.value(/* Empty future */)
], eagerError: true);
}

/// Closes connection (rather immediately), in result should also disconnect.
@Deprecated('Use `close` instead')
Future<void> cancel() => this.close();

/// Closes connection (rather gracefully), in result should also disconnect.
Future<void> finish() async {
await output.allSent;
await cancel();
close();
}

}
Expand Down

0 comments on commit 3807530

Please sign in to comment.