Describe the bug
Firstly, thank you for your time :)
Crash when executing
broadcast.ready.whenComplete(broadcast.start)
.whenComplete(() => setState(() => /*...*/));
in callback onChange
of Widget Switch
,~~ along with package Camera
.~~
Crashed with widget:
StreamBuilder<BonsoirBroadcastEvent>(
stream: broadcast?.eventStream,
builder: (context, snapshot) {
if (snapshot.data?.type ==
BonsoirBroadcastEventType.BROADCAST_STARTED) {
var port = snapshot.data?.service?.port;
return Text("Service running at port: $port");
}
return SizedBox();
},
)
~~
Here's the log:
java.lang.RuntimeException: Methods marked with @UiThread must be executed on the main thread. Current thread: NsdManager
at io.flutter.embedding.engine.FlutterJNI.ensureRunningOnMainThread(FlutterJNI.java:1415)
at io.flutter.embedding.engine.FlutterJNI.dispatchPlatformMessage(FlutterJNI.java:1036)
at io.flutter.embedding.engine.dart.DartMessenger.send(DartMessenger.java:282)
at io.flutter.embedding.engine.dart.DartExecutor$DefaultBinaryMessenger.send(DartExecutor.java:452)
at io.flutter.embedding.engine.dart.DartExecutor.send(DartExecutor.java:212)
at io.flutter.plugin.common.EventChannel$IncomingStreamRequestHandler$EventSinkImplementation.success(EventChannel.java:251)
at fr.skyost.bonsoir.broadcast.BonsoirRegistrationListener.onServiceRegistered(BonsoirRegistrationListener.kt:65)
at android.net.nsd.NsdManager$ServiceHandler.handleMessage(NsdManager.java:439)
at android.os.Handler.dispatchMessage(Handler.java:106)
at android.os.Looper.loop(Looper.java:236)
at android.os.HandlerThread.run(HandlerThread.java:67)
2022-04-19 19:30:17.118 8176-8176/com.**.** D/DecorView[]: onWindowFocusChanged hasWindowFocus false
2022-04-19 19:30:17.119 8176-8176/com.**.** I/DecorView: showOrHideHighlightView: hasFocus=false; winMode=4; isMrgNull=false
2022-04-19 19:30:17.179 8176-8267/com.**.** I/Process: Sending signal. PID: 8176 SIG: 9
To Reproduce
Steps to reproduce the behavior:
The code crashed: (might be some help)
import 'package:bonsoir/bonsoir.dart';
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
List<CameraDescription>? cameras;
/// main.dart
void main() {
// ...
initCameras();
runApp(const MyApp());
}
/// end of main.dart
Future<String?> initCameras() async {
cameras = await availableCameras();
if (cameras!.isEmpty) {
return null;
} else if (cameras!.length == 1) {
return "camera";
} else {
return "${cameras!.length}x-camera";
}
}
class CameraDemoPage extends StatefulWidget {
const CameraDemoPage({Key? key}) : super(key: key);
@override
_CameraDemoPageState createState() => _CameraDemoPageState();
}
class _CameraDemoPageState extends State<CameraDemoPage>
with WidgetsBindingObserver {
bool _switchingOn = false;
BonsoirService service = const BonsoirService(
name: 'streamlab2',
type: '_stream-lab2._tcp',
port: 11451,
);
late BonsoirBroadcast broadcast;
final _uriTextController = TextEditingController();
int _cameraId = 0;
CameraController? _cameraController;
Future<void>? _initializeControllerFuture;
@override
void initState() {
super.initState();
// broadcast = BonsoirBroadcast(service: service);
// broadcast!.ready.whenComplete(broadcast!.start);
if (cameras != null) {
onNewCameraSelected(cameras![_cameraId]);
}
}
@override
void didChangeAppLifecycleState(AppLifecycleState state) {
// App state changed before we got the chance to initialize.
if (_cameraController == null || !_cameraController!.value.isInitialized) {
return;
}
if (state == AppLifecycleState.inactive) {
_cameraController?.dispose();
} else if (state == AppLifecycleState.resumed) {
if (_cameraController != null) {
onNewCameraSelected(_cameraController!.description);
}
}
}
@override
void dispose() {
_cameraController?.dispose();
broadcast?.stop();
super.dispose();
}
@override
Widget build(BuildContext context) {
return Scaffold(
body: Padding(
padding: const EdgeInsets.all(24),
child: Column(
children: [
Expanded(
// CAMERA 0
child: Padding(
padding: const EdgeInsets.all(10),
child: Stack(
alignment: AlignmentDirectional.bottomStart,
children: [
// Overlapping Tips
Padding(
padding: const EdgeInsets.all(5),
child: StreamBuilder<BonsoirBroadcastEvent>(
stream: broadcast?.eventStream,
builder: (context, snapshot) {
if (snapshot.data?.type ==
BonsoirBroadcastEventType.BROADCAST_STARTED) {
var port = snapshot.data?.service?.port;
return Text("Service running at port: $port");
}
return SizedBox();
},
)),
Container(
color: Colors.grey,
child: FutureBuilder<void>(
future: _initializeControllerFuture,
builder: (context, snapshot) {
if (snapshot.connectionState ==
ConnectionState.done) {
// If the Future is complete, display the preview.
return CameraPreview(_cameraController!);
} else {
// Otherwise, display a loading indicator.
return const Center(
child: CircularProgressIndicator(),
);
}
},
)),
]),
),
),
Row(
children: [
Expanded(
child: TextField(
decoration: const InputDecoration(
icon: Icon(Icons.link_rounded), hintText: "video uri"),
controller: _uriTextController,
),
),
Column(
children: [
Row(
children: [
Switch.adaptive(
value: !broadcast.isStopped,
onChanged: (switchOn) {
if (_switchingOn) {
return;
}
if (switchOn) {
_switchingOn = true;
broadcast = BonsoirBroadcast(service: service);
broadcast!.ready
.whenComplete(broadcast!.start)
.whenComplete(() =>
setState(() => _switchingOn = false));
} else {
broadcast
?.stop()
.whenComplete(() => setState(() {}));
}
},
),
const Text("Stream"),
],
),
// MaterialButton(
// onPressed: () {
// setState(() {
// _isStreaming = !_isStreaming;
// });
//
// },
// child: const Text("Stream"),
// elevation: _isStreaming ? 0.8 : 2,
// ),
],
)
],
),
Expanded(
child: Padding(
padding: const EdgeInsets.all(10),
child: Container(
color: Colors.grey,
),
),
)
],
),
),
);
}
void onNewCameraSelected(CameraDescription description) async {
final previousCameraController = _cameraController;
// Instantiating the camera controller
final CameraController cameraController = CameraController(
description,
ResolutionPreset.high,
imageFormatGroup: ImageFormatGroup.jpeg,
);
// Dispose the previous controller
await previousCameraController?.dispose();
// Replace with the new controller
if (mounted) {
setState(() {
_cameraController = cameraController;
});
}
// Update UI if controller updated
cameraController.addListener(() {
if (mounted) setState(() {});
});
// Initialize controller
try {
_initializeControllerFuture = cameraController.initialize();
await _initializeControllerFuture;
} on CameraException catch (e) {
assert(() {
print('Error initializing camera: $e');
return true;
}());
}
}
}
Expected behavior
A clear and concise description of what you expected to happen.
Screenshots
If applicable, add screenshots to help explain your problem.
ENV
[✓] Flutter (Channel beta, 2.13.0-0.1.pre, on macOS 12.0.1 21A559 darwin-arm,
locale en-CN)
...
[✓] Android Studio (version 2021.1)
Test device: some tablet with Android 12