Flutter Camera for Android will throw exception after some time - flutter

I am currently building this camera screen widget that will navigate to a different screen when a driver license barcode is detected.
My app flow is like this:
Screen 1 Widget -> Camera Screen Widget -> Screen 2 Widget (Screen 2 widget has a button to go back to Screen 1 Widget).
The flow will work fine close to 10 times but then it will always crash on the Camera Screen Widget.
Here's the exception being thrown:
I/Camera (24242): closeCaptureSession
E/AndroidRuntime(24242): FATAL EXCEPTION: pool-89-thread-1
E/AndroidRuntime(24242): Process: com.example.visitor_checkin_app, PID: 24242
E/AndroidRuntime(24242): java.lang.IllegalStateException: Session has been closed; further changes are illegal.
E/AndroidRuntime(24242): at android.hardware.camera2.impl.CameraCaptureSessionImpl.checkNotClosed(CameraCaptureSessionImpl.java:886)
E/AndroidRuntime(24242): at android.hardware.camera2.impl.CameraCaptureSessionImpl.setRepeatingRequest(CameraCaptureSessionImpl.java:303)
E/AndroidRuntime(24242): at io.flutter.plugins.camera.Camera.refreshPreviewCaptureSession(Camera.java:434)
E/AndroidRuntime(24242): at io.flutter.plugins.camera.Camera.access$600(Camera.java:83)
E/AndroidRuntime(24242): at io.flutter.plugins.camera.Camera$2.onConfigured(Camera.java:373)
E/AndroidRuntime(24242): at android.hardware.camera2.impl.CallbackProxies$SessionStateCallbackProxy.lambda$onConfigured$0$CallbackProxies$SessionStateCallbackProxy(CallbackProxies.java:53)
E/AndroidRuntime(24242): at android.hardware.camera2.impl.-$$Lambda$CallbackProxies$SessionStateCallbackProxy$soW0qC12Osypoky6AfL3P2-TeDw.run(Unknown Source:4)
E/AndroidRuntime(24242): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
E/AndroidRuntime(24242): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
E/AndroidRuntime(24242): at java.lang.Thread.run(Thread.java:923)
Flutter version: 2.5.1
Camera version: 0.9.4
Android minSDK version: 27
Below is the code:
import 'dart:async';
import 'package:camera/camera.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:google_ml_kit/google_ml_kit.dart';
class CameraView extends StatefulWidget {
CameraView(
{Key? key,
this.initialDirection = CameraLensDirection.back})
: super(key: key);
static const CAMERAVIEW_ROUTE = "/cameraview";
final String title = "Barcode Scanner";
final CameraLensDirection initialDirection;
#override
_CameraViewState createState() => _CameraViewState();
}
class _CameraViewState extends State<CameraView> {
BarcodeScanner barcodeScanner = GoogleMlKit.vision.barcodeScanner(const [
BarcodeFormat.pdf417
]);
bool isBusy = false;
CameraController? _controller;
int _cameraIndex = 0;
#override
void initState() {
super.initState();
for (var i = 0; i < cameras.length; i++) {
if (cameras[i].lensDirection == widget.initialDirection) {
_cameraIndex = i;
break;
}
}
_startLiveFeed();
isBusy = false;
}
#override
void dispose() {
_stopLiveFeed();
barcodeScanner.close();
super.dispose();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title)
),
body: _body()
);
}
Widget _body() {
Widget body = _liveFeedBody();
return body;
}
Widget _liveFeedBody() {
if (_controller?.value.isInitialized == false) {
return Container();
}
return Container(
color: Colors.black,
child: Stack(
fit: StackFit.expand,
children: <Widget>[
CameraPreview(_controller!)
],
),
);
}
Future _startLiveFeed() async {
final camera = cameras[_cameraIndex];
_controller = CameraController(
camera,
ResolutionPreset.high,
enableAudio: false,
);
_controller?.initialize().then((_) {
if (!mounted) {
return;
}
_controller?.startImageStream(_processCreateInputImage);
if (mounted) {
setState(() {});
}
});
}
Future _stopLiveFeed() async {
await _controller?.stopImageStream();
await _controller?.dispose();
_controller = null;
}
Future _processBarCodeImage(InputImage inputImage) async {
final barcodes = await barcodeScanner.processImage(inputImage);
if (barcodes.length > 0) {
for (var i = 0; i < barcodes.length; ++i) {
Barcode bcode = barcodes[i];
if (bcode.type == BarcodeType.driverLicense) {
BarcodeDriverLicense bcodeDL = bcode.value as BarcodeDriverLicense;
String scannedName = bcodeDL.lastName! + ", " + bcodeDL.firstName!;
Navigator.of(context).popAndPushNamed(
AnotherScreen.ANOTHER_SCREEN_ROUTE,
arguments: ScannedInfoArguments(
scannedName));
break;
}
}
}
}
Future _processCreateInputImage(CameraImage image) async {
if (isBusy) return;
isBusy = true;
final WriteBuffer allBytes = WriteBuffer();
for (Plane plane in image.planes) {
allBytes.putUint8List(plane.bytes);
}
final bytes = allBytes.done().buffer.asUint8List();
final Size imageSize =
Size(image.width.toDouble(), image.height.toDouble());
final camera = cameras[_cameraIndex];
final imageRotation =
InputImageRotationMethods.fromRawValue(camera.sensorOrientation) ??
InputImageRotation.Rotation_0deg;
final inputImageFormat =
InputImageFormatMethods.fromRawValue(image.format.raw) ??
InputImageFormat.NV21;
final planeData = image.planes.map(
(Plane plane) {
return InputImagePlaneMetadata(
bytesPerRow: plane.bytesPerRow,
height: plane.height,
width: plane.width,
);
},
).toList();
final inputImageData = InputImageData(
size: imageSize,
imageRotation: imageRotation,
inputImageFormat: inputImageFormat,
planeData: planeData,
);
final inputImage =
InputImage.fromBytes(bytes: bytes, inputImageData: inputImageData);
await _processBarCodeImage(inputImage);
isBusy = false;
}
}
Looking forward for inputs and/or solutions to solve this.
Thank you

Related

when i click the floating action button this error pops up on the red screen what i want is it need to show up camera and recogonize text

'import 'package:flutter/material.dart';
import 'package:google_mlkit_text_recognition/google_mlkit_text_recognition.dart';
import 'camera.dart';
import 'package:tooler_noturk/functions/text_painter.dart';
class TextRecognizerView extends StatefulWidget {
#override
State<TextRecognizerView> createState() => _TextRecognizerViewState();
}
class _TextRecognizerViewState extends State<TextRecognizerView> {
final TextRecognizer _textRecognizer =
TextRecognizer(script: TextRecognitionScript.chinese);
bool _canProcess = true;
bool _isBusy = false;
CustomPaint? _customPaint;
String? _text;
#override
void dispose() async {
_canProcess = false;
_textRecognizer.close();
super.dispose();
}
#override
Widget build(BuildContext context) {
return CameraView(
title: 'Text Detector',
customPaint: _customPaint,
text: _text,
onImage: (inputImage) {
processImage(inputImage);
},
);
}
Future<void> processImage(InputImage inputImage) async {
if (!_canProcess) return;
if (_isBusy) return;
_isBusy = true;
setState(() {
_text = '';
});
final recognizedText = await _textRecognizer.processImage(inputImage);
if (recognizedText != null) {
final painter = TextRecognizerPainter(
recognizedText,
inputImage.inputImageData!.size,
inputImage.inputImageData!.imageRotation);
_customPaint = CustomPaint(painter: painter);
} else {
_customPaint = null;
}
_isBusy = false;
if (mounted) {
setState(() {});
}
}
}
CircleAvatar(
radius: 25,
child: FloatingActionButton(`your text`
onPressed: (() {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) =\>
TextRecognizerView()),
);
}),
child: const Icon(Icons.scanner),
),)'
The method 'any' was called on null.
Receiver: null
Tried calling: any(Closure: (dynamic) => bool)
The relevant error-causing widget was
TextRecognizerView`
when i click the floating action button it shows this error so what i want is when i click the floating action button it need to open camera and recogonize text using google mlkit text recogonition

Flutter Shared Preference : How to save the Stateful widget to the device (lines are drawn by CustomPainter and stylus)

I'm making a e-book application and user can draw lines on the WorkbookDrawingPage Widget by Stack layer.
I want to make the drawn lines saved to the device and books by using shared preference. I tried to use a Json encoding, but couldn't apply to my code.
How to save List<Object> to SharedPreferences in Flutter?
Here's my code
WorkbookViewPage ( PdfViewer and DrawingPage widget)
class WorkbookViewPage extends StatefulWidget {
String downloadedURL;
String workbookName;
WorkbookViewPage(this.downloadedURL, this.workbookName, {super.key});
#override
State<WorkbookViewPage> createState() => _WorkbookViewPageState();
}
class _WorkbookViewPageState extends State<WorkbookViewPage> {
/// Widget Key
GlobalKey _viewKey = GlobalKey();
final GlobalKey<SfPdfViewerState> _pdfViewerKey = GlobalKey();
/// Controller
PdfViewerController _pdfViewerController = PdfViewerController();
ScrollController _scrollController = ScrollController();
/// Variables
int _lastClosedPage = 1;
int _currentPage = 1;
bool _memoMode = false;
int drawingPage = 1;
bool isPenTouched = false;
/// pen size control widget Entry
bool isOverlayVisible = false;
OverlayEntry? entry;
/// Hide Overlay Widget
void hideOverlay() {
entry?.remove();
entry = null;
isOverlayVisible = false;
}
/// Count the Total Pages of the Workbook
int _countTotalPages(){
int _totalPages = _pdfViewerController.pageCount;
return _totalPages;
}
/// get Last closed page of workbook
void _loadLastClosedPage() async {
final pagePrefs = await SharedPreferences.getInstance();
_lastClosedPage = pagePrefs.getInt('${widget.workbookName}') ?? 1;
}
#override
void initState() {
super.initState();
// Load Pdf with landScape Mode
SystemChrome.setPreferredOrientations([DeviceOrientation.landscapeLeft]);
_pdfViewerController = PdfViewerController();
String workbookName = '${widget.workbookName}';
_loadLastClosedPage();
_countTotalPages();
print("======== Loaded workbook name = ${workbookName} ==========");
}
#override
Widget build(BuildContext context) {
/// Drawing Provider
var p = context.read<DrawingProvider>();
/// set _lastClosedPage
void countLastClosedPage() async {
final pagePrefs = await SharedPreferences.getInstance();
setState(() {
pagePrefs.setInt('${widget.workbookName}', _lastClosedPage);
_lastClosedPage = (pagePrefs.getInt('${widget.workbookName}') ?? 1);
});
}
return Scaffold(
appBar: AppBar(
centerTitle: true,
backgroundColor: Colors.white,
elevation: 1,
),
body: Stack(
children: [
InteractiveViewer(
panEnabled: _memoMode ? false : true,
scaleEnabled: _memoMode ? false : true,
maxScale: 3,
child: Stack(
children: [
IgnorePointer(
ignoring: true,
child: SfPdfViewer.network(
widget.downloadedURL,
controller: _pdfViewerController,
key: _pdfViewerKey,
pageLayoutMode: PdfPageLayoutMode.single,
enableDoubleTapZooming: false,
// Save the last closed page number
onPageChanged: (details) {
_lastClosedPage = details.newPageNumber;
_currentPage = details.newPageNumber;
countLastClosedPage();
},
onDocumentLoaded: (details) {
_pdfViewerController.jumpToPage(_lastClosedPage);
_pdfViewerController.zoomLevel = 0;
print("totalpages = ${_countTotalPages().toInt()}");
},
canShowScrollHead: false,
),
),
SingleChildScrollView(
physics: NeverScrollableScrollPhysics(),
controller: _scrollController,
scrollDirection: Axis.horizontal,
child: WorkbookDrawingPage(widget.workbookName, _countTotalPages().toInt(),),
),
],
),
),
WorkbookDawingPage.dart
class WorkbookDrawingPage extends StatefulWidget {
String workbookName;
int countTotalPages;
WorkbookDrawingPage(this.workbookName, this.countTotalPages,{super.key});
#override
State<WorkbookDrawingPage> createState() => _WorkbookDrawingPageState();
}
class _WorkbookDrawingPageState extends State<WorkbookDrawingPage> {
// OverlayEntry widget key
GlobalKey _overlayViewKey = GlobalKey();
Key _viewKey = UniqueKey();
// pen size control widget Entry
bool isOverlayVisible = false;
OverlayEntry? entry;
#override
void initState() {
super.initState();
}
#override
Widget build(BuildContext context) {
var p = context.read<DrawingProvider>();
void hideOverlay() {
entry?.remove();
entry = null;
isOverlayVisible = false;
}
return Container(
width: MediaQuery.of(context).size.width * (widget.countTotalPages),
height: MediaQuery.of(context).size.height * 1,
child: CustomPaint(
painter: DrawingPainter(p.lines),
child: Listener(
behavior: HitTestBehavior.translucent,
// Draw lines when stylus hit the screen
onPointerDown: (s) async {
if (s.kind == PointerDeviceKind.stylus) {
setState(() {
p.penMode ? p.penDrawStart(s.localPosition) : null;
p.highlighterMode
? p.highlighterDrawStart(s.localPosition)
: null;
p.eraseMode ? p.erase(s.localPosition) : null;
});
}
/// Stylus with button pressed touched the Screen
else if (s.kind == PointerDeviceKind.stylus ||
s.buttons == kPrimaryStylusButton) {
setState(() {
p.changeEraseModeButtonClicked = true;
});
}
},
onPointerMove: (s) {
if (s.kind == PointerDeviceKind.stylus) {
setState(() {
p.penMode ? p.penDrawing(s.localPosition) : null;
p.highlighterMode
? p.highlighterDrawing(s.localPosition)
: null;
p.eraseMode ? p.erase(s.localPosition) : null;
});
} else if (s.kind == PointerDeviceKind.stylus ||
s.buttons == kPrimaryStylusButton) {
setState(() {
p.changeEraseModeButtonClicked = true;
});
}
},
),
),
);
}
}
The application uses provider for drawing lines and here's provider class
Drawing Provider
Class DrawingProvider extends ChangeNotifier {
/// line List **/
final lines = <List<DotInfo>>[];
Color _selectedColor = Colors.black;
Color get selectedColor => _selectedColor;
/** function method to change Color **/
set changeColor(Color color) {
_selectedColor = color;
notifyListeners();
}
/** Mode Selection **/
bool _penMode = false;
bool get penMode => _penMode;
bool _highlighterMode = false;
bool get highlighterMode => _highlighterMode;
bool _eraseMode = false;
bool get eraseMode => _eraseMode;
bool _memoMode = false;
bool get memoMode => _memoMode;
set changeEraseModeButtonClicked(bool eraseMode) {
eraseMode = true;
_eraseMode = eraseMode;
print("eraseMode가 On ");
notifyListeners();
}
/** 지우개 선택 모드 **/
void changeEraseMode() {
_eraseMode = !_eraseMode;
print("eraseMode is : ${eraseMode}");
_penMode = false;
_highlighterMode = false;
notifyListeners();
}
/** 일반 펜 선택 모드 **/
void changePenMode() {
_penMode = !_penMode;
// _selectedColor = _selectedColor.withOpacity(1);
print("penMode is called : ${penMode} ");
_eraseMode = false;
_highlighterMode = false;
notifyListeners();
}
/** 형광펜 선택 모드 **/
void changeHighlighterMode() {
_highlighterMode = !_highlighterMode;
// _selectedColor = _selectedColor.withOpacity(0.3);
print("Highlighter Mode : ${highlighterMode}");
_eraseMode = false;
_penMode = false;
_opacity = 0.3;
notifyListeners();
}
/** Pen Draw Start **/
void penDrawStart(Offset offset) async {
var oneLine = <DotInfo>[];
oneLine.add(DotInfo(offset, penSize, _selectedColor,));
lines.add(oneLine);
notifyListeners();
}
/** Pen Drawing **/
void penDrawing(Offset offset) {
lines.last.add(DotInfo(offset, penSize, _selectedColor));
notifyListeners();
}
/** highlighter Start **/
void highlighterDrawStart(Offset offset) {
var oneLine = <DotInfo>[];
oneLine
.add(DotInfo(offset, highlighterSize, _selectedColor.withOpacity(0.3),));
lines.add(oneLine);
notifyListeners();
}
/** 터치 후 형광 펜 그리기 **/
void highlighterDrawing(Offset offset) {
lines.last
.add(DotInfo(offset, highlighterSize, _selectedColor.withOpacity(0.3)));
notifyListeners();
}
/** 선 지우기 메서드 **/
void erase(Offset offset) {
final eraseRange = 15;
for (var oneLine in List<List<DotInfo>>.from(lines)) {
for (var oneDot in oneLine) {
if (sqrt(pow((offset.dx - oneDot.offset.dx), 2) +
pow((offset.dy - oneDot.offset.dy), 2)) <
eraseRange) {
lines.remove(oneLine);
break;
}
}
}
notifyListeners();
}
}
and the Dotinfo save the information of the lines
DotInfo.dart
class DotInfo {
final Offset offset;
final double size;
final Color color;
DotInfo(this.offset, this.size, this.color);
}
in the WorkbookDrawingPage.dart , CustomPaint.painter method get DrawingPainter Class
DrawingPainter.dart
class DrawingPainter extends CustomPainter {
final List<List<DotInfo>> lines;
DrawingPainter(this.lines);
#override
void paint(Canvas canvas, Size size) {
for (var oneLine in lines) {
Color? color;
double? size;
var path = Path();
var l = <Offset>[];
for (var oneDot in oneLine) {
color ??= oneDot.color;
size ??= oneDot.size;
l.add(oneDot.offset);
}
path.addPolygon(l, false);
canvas.drawPath(
path,
Paint()
..color = color!
..strokeWidth = size!
..strokeCap = StrokeCap.round
..style = PaintingStyle.stroke
..isAntiAlias = true
..strokeJoin = StrokeJoin.round);
}
}
#override
bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}
The Drawing function is related to the provider.
I have no idea how to save the drawn lines into the device. My idea was saving the WorkbookDrawingPage widget itself to the device by using shared preference but, shared preference only can save Int, String, double... so, I tried to encode the DotInfo Class but it cannot be encoded because constructors value is not initialized in the DotInfo Class.
how to save the drawn lines to the device and make them pair with the book?
is saving the widget to the device is possible?? or can you give me any hint or answer?

Range Error (Index) Flutter GETX : invalid value

Here I have an error when I fetch data, I take a reference from youtube then I apply and use data from local but when I run it I get an error as I described. here is my source code
Controller.dart
class ProdukKonvensionalController extends GetxController {
var konvenList = <ProdukKonvenModel>[].obs;
var isLoading = true.obs;
#override
void onInit() {
super.onInit();
fetchKonven();
}
Future<void> fetchKonven() async {
final response =
await http.get(Uri.parse('http://192.168.100.207:8080/konven'));
if (response.statusCode == 200) {
ProdukKonvenModel _produkkonvenModel =
ProdukKonvenModel.fromJson(jsonDecode(response.body));
konvenList.add(ProdukKonvenModel(
kategoriNama: _produkkonvenModel.kategoriNama,
kategoriId: _produkkonvenModel.kategoriId,
kontenId: _produkkonvenModel.kontenId,
kontenMenu: _produkkonvenModel.kontenMenu,
kontenParent: _produkkonvenModel.kontenParent,
kontenUrl: _produkkonvenModel.kontenUrl,
));
isLoading.value = true;
} else {
Get.snackbar("Error Loading Data",
'Server Responded: ${response.statusCode}:${response.reasonPhrase.toString()}');
}
}
}
PageView.dart
class ProdukKonvensionalPage extends StatelessWidget {
const ProdukKonvensionalPage({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
final _controller = Get.find<ProdukKonvensionalController>();
return Scaffold(
body: SingleChildScrollView(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Text('${_controller.konvenList[0].kategoriNama}'),
],
)),
);
}
}
and the following shows an error
try this
var konvenList = <ProdukKonvenModel>[].obs;
var isLoading = true.obs;
#override
void onInit() {
super.onInit();
fetchKonven();
}
Future<void> fetchKonven() async {
final response = await http.get(Uri.parse('http://192.168.100.207:8080/konven'));
if (response.statusCode == 200) {
ProdukKonvenModel _produkkonvenModel =
ProdukKonvenModel.fromJson(jsonDecode(response.body));
_produkkonvenModel.forEach((element) => konvenList.add(element));
isLoading.value = true;
} else {
Get.snackbar("Error Loading Data",
'Server Responded:
${response.statusCode}:${response.reasonPhrase.toString()}');
}
}
}

getting the pages multible times from infinite scroll pagination package

im building an app that gets data from api and the api has pages so i used the infinite scroll pagination package but when the data appears , the first page data appears and when i scroll down the first page appears two times and the second page appears ,
when i scroll again , the first and second page appears with the third page etc
this is the code im using
import 'dart:async';
import 'package:MyCima/models/films_data_model.dart';
import 'package:MyCima/services/services.dart';
import 'package:flutter/material.dart';
import 'films_card.dart';
import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart';
class ShowsListDesign extends StatefulWidget {
final String filterName;
const ShowsListDesign(this.filterName, {Key? key}) : super(key: key);
#override
_ShowsListDesignState createState() => _ShowsListDesignState();
}
class _ShowsListDesignState extends State<ShowsListDesign> {
final ServicesClass _servicesClass = ServicesClass();
FilmsDataModel modelClass = FilmsDataModel();
final PagingController _pagingController = PagingController(firstPageKey: 1);
#override
void initState() {
_pagingController.addPageRequestListener((pageKey) {
_fetchPage(pageKey);
});
super.initState();
}
Future<void> _fetchPage(int pageKey) async {
try {
final List newItems =
await _servicesClass.getFilms('posts/$pageKey/${widget.filterName}');
final isLastPage = newItems.length < 20;
if (isLastPage) {
_pagingController.appendLastPage(newItems);
} else {
final nextPageKey = pageKey + 1;
_pagingController.appendPage(newItems, nextPageKey);
}
} catch (error) {
_pagingController.error = error;
}
}
#override
Widget build(BuildContext context) => PagedGridView(
pagingController: _pagingController,
builderDelegate: PagedChildBuilderDelegate(
itemBuilder: (BuildContext context, item, int index) {
modelClass = FilmsDataModel.fromJson(item);
return FilmsCard(
key: UniqueKey(),
image: modelClass.thumbUrl,
title: modelClass.title,
year: modelClass.year,
id: modelClass.id,
);
}),
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
maxCrossAxisExtent: 250,
crossAxisSpacing: 24,
mainAxisSpacing: 24,
childAspectRatio: (2 / 3),
),
);
#override
void dispose() {
_pagingController.dispose();
super.dispose();
}
}
I think your mistake is from
"final isLastPage = newItems.length < 20;"
you comparison is from the new data fetched and not the total amount of posts fetched since the first time.
and be sure that your request give you the good response
this is my fetchPage
Future<void> fetchPage(int pageKey) async {
try {
final newPage = await _presenter.getWithPagination(pageKey, 10);
final previouslyFetchedWordCount =
_pagingController.itemList?.length ?? 0;
final isLastPage = newPage.isLastPage(previouslyFetchedWordCount);
final newItems = newPage.itemList;
if (isLastPage) {
_pagingController.appendLastPage(newItems);
} else {
final nextPageKey = pageKey + 1;
_pagingController.appendPage(newItems, nextPageKey);
}
} catch (error) {
_pagingController.error = error;
}

Flutter web - Geolocator not working when uploaded to server

everyone.
I'm trying to develop a PWA with flutter 2.2.1 that shows a map using Mapbox_gl and displays the user current location using Geolocator.
So far everything works as expected while debuging the app, but when I run:
flutter build
or
flutter build --release
and then run
firebase deploy
the site gets uploaded, the map shows as intended and it asks for permissions but the user's location is never shown and Google Chrome's Console throws this error:
Uncaught TypeError: m.gfR is not a function
at Object.avh (main.dart.js:20405)
at main.dart.js:65755
at aiD.a (main.dart.js:5853)
at aiD.$2 (main.dart.js:34394)
at ahm.$1 (main.dart.js:34386)
at Rx.o1 (main.dart.js:35356)
at adi.$0 (main.dart.js:34770)
at Object.tQ (main.dart.js:5975)
at a5.mn (main.dart.js:34687)
at ada.$0 (main.dart.js:34731)
Here's the code I'm using on flutter:
mapbox.dart
import 'dart:async';
import 'dart:io';
import 'dart:math';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:geolocator/geolocator.dart';
import 'package:kkc/main.dart';
import 'package:mapbox_gl/mapbox_gl.dart';
import 'package:kkc/services/location_service.dart';
class Mapbox extends StatefulWidget {
const Mapbox();
#override
State createState() => MapboxState();
}
class MapboxState extends State<Mapbox> {
final Random _rnd = new Random();
Position? _currentLocation;
LatLng _currentCoordinates = new LatLng(0,0);
final List<_PositionItem> _positionItems = <_PositionItem>[];
StreamSubscription<Position>? _positionStreamSubscription;
late MapboxMapController _mapController;
List<Marker> _markers = [];
List<_MarkerState> _markerStates = [];
CameraPosition _kInitialPosition = CameraPosition(
target: LatLng(19.4274418, -99.1682147),
zoom: 18.0,
tilt: 70,
);
void _addMarkerStates(_MarkerState markerState) {
_markerStates.add(markerState);
}
void _onMapCreated(MapboxMapController controller) {
_mapController = controller;
controller.addListener(() {
if (controller.isCameraMoving) {
_updateMarkerPosition();
}
});
}
void _onStyleLoadedCallback() {
_updateMarkerPosition();
}
void _onCameraIdleCallback() {
_updateMarkerPosition();
}
void _updateMarkerPosition() {
final coordinates = <LatLng>[];
for (final markerState in _markerStates) {
coordinates.add(markerState.getCoordinate());
}
_mapController.toScreenLocationBatch(coordinates).then((points) {
_markerStates.asMap().forEach((i, value) {
_markerStates[i].updatePosition(points[i]);
});
});
}
void _addMarker(Point<double> point, LatLng coordinates) {
setState(() {
_markers.add(Marker(_rnd.nextInt(100000).toString(), coordinates, point, _addMarkerStates));
});
}
#override
void initState() {
super.initState();
_getCurrentLocation();
}
#override
void dispose() {
super.dispose();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: Stack(children: [
MapboxMap(
accessToken: Kukulcan.MAPBOX_ACCESS_TOKEN,
trackCameraPosition: true,
onMapCreated: _onMapCreated,
onCameraIdle: _onCameraIdleCallback,
onStyleLoadedCallback: _onStyleLoadedCallback,
initialCameraPosition: _kInitialPosition,
),
IgnorePointer(
ignoring: true,
child: Stack(
children: _markers,
))
]),
);
}
void _getCurrentLocation() async {
_currentLocation = await LocationService.startLocationService();
_currentCoordinates = new LatLng(_currentLocation!.latitude,_currentLocation!.longitude);
await _mapController.animateCamera(CameraUpdate.newLatLng(_currentCoordinates));
_addMarker(new Point(1, 1), _currentCoordinates);
if (_positionStreamSubscription == null) {
final positionStream = Geolocator.getPositionStream();
_positionStreamSubscription = positionStream.handleError((error) {
_positionStreamSubscription?.cancel();
_positionStreamSubscription = null;
}).listen((position) => setState(() => _positionItems.add(
_PositionItem(_PositionItemType.position, position.toString()))));
_positionStreamSubscription?.pause();
}
}
}
class Marker extends StatefulWidget {
final Point _initialPosition;
LatLng _coordinate;
final void Function(_MarkerState) _addMarkerState;
Marker(
String key, this._coordinate, this._initialPosition, this._addMarkerState)
: super(key: Key(key));
#override
State<StatefulWidget> createState() {
final state = _MarkerState(_initialPosition);
_addMarkerState(state);
return state;
}
}
class _MarkerState extends State with TickerProviderStateMixin {
final _iconSize = 80.0;
Point _position;
_MarkerState(this._position);
#override
Widget build(BuildContext context) {
var ratio = 1.0;
//web does not support Platform._operatingSystem
if (!kIsWeb) {
// iOS returns logical pixel while Android returns screen pixel
ratio = Platform.isIOS ? 1.0 : MediaQuery.of(context).devicePixelRatio;
}
return Positioned(
left: _position.x / ratio - _iconSize / 2,
top: _position.y / ratio - _iconSize / 2,
child: Image.asset('assets/img/pin.png', height: _iconSize));
}
void updatePosition(Point<num> point) {
setState(() {
_position = point;
});
}
LatLng getCoordinate() {
return (widget as Marker)._coordinate;
}
}
enum _PositionItemType {
permission,
position,
}
class _PositionItem {
_PositionItem(this.type, this.displayValue);
final _PositionItemType type;
final String displayValue;
}
Does anyone have an idea on what's the problem?
Cheers!
Anyway the solution i found is to use --no-sound-null-safety argument as stated by geolocat documentation
I quote:
NOTE: due to a bug in the dart:html library the web version of the Geolocator plugin does not work with sound null safety enabled and compiled in release mode. Running the App in release mode with sound null safety enabled results in a Uncaught TypeError (see issue #693). The current workaround would be to build your App with sound null safety disabled in release mode: