Flutter Admob's widget get error when setState is call - flutter

I have a problem with Admob's widgets.
I am developing a new feature for a flutter app that contains an Admob banner widget.
But when I setState the value of another widget, the Admob Widget gets an error.
I am using :google_mobile_ads: ^0.11.0+1
The banner is build like so:
#override
void initState() {
setState(() {
_adBanner = createBannerAd();
});
super.initState();
}
#override
void dispose() {
_adBanner.dispose();
super.dispose();
}
And the widget is display like this:
Container(
margin: EdgeInsets.only(bottom: myPercent(2, screenHeight)),
child: FutureBuilder(
future: _adBanner.load(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Container(
margin: EdgeInsets.only(bottom: 3),
width: myPercent(95, screenWidth),
height: myPercent(6, screenHeight),
alignment: Alignment.center,
child: AdWidget(
ad: _adBanner,
),
);
}
return Container();
}),
The log error catch :
flutter: click
flutter: ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
flutter: The following assertion was thrown building AdWidget(dirty, state: _AdWidgetState#a1afb):
flutter: This AdWidget is already in the Widget tree
flutter: If you placed this AdWidget in a list, make sure you create a new instance in the builder function
flutter: with a unique ad object.
flutter: Make sure you are not using the same ad object in more than one AdWidget.
flutter:
flutter: The relevant error-causing widget was:
flutter: AdWidget file:///Users/sofian/Work/Personal/Mobile/WhatUDo/what_u_do/lib/views/idea.dart:295:34
flutter:
flutter: When the exception was thrown, this was the stack:
flutter: #0 _AdWidgetState.build (package:google_mobile_ads/src/ad_containers.dart:372:7)
flutter: #1 StatefulElement.build (package:flutter/src/widgets/framework.dart:4825:27)
flutter: #2 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4708:15)
flutter: #3 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4880:11)
flutter: #4 BuildOwner._runWithCurrentBuildTarget (package:flutter/src/widgets/framework.dart:2708:15)
flutter: #5 Element.rebuild (package:flutter/src/widgets/framework.dart:4407:12)
flutter: #6 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4687:5)
flutter: #7 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4871:11)
flutter: #8 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4682:5)
flutter: ... Normal element mounting (10 frames)
flutter: #18 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3660:14)
flutter: #19 Element.updateChild (package:flutter/src/widgets/framework.dart:3422:20)
flutter: #20 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4733:16)
flutter: #21 BuildOwner._runWithCurrentBuildTarget (package:flutter/src/widgets/framework.dart:2708:15)
flutter: #22 Element.rebuild (package:flutter/src/widgets/framework.dart:4407:12)
flutter: #23 StatelessElement.update (package:flutter/src/widgets/framework.dart:4789:5)
flutter: #24 Element.updateChild (package:flutter/src/widgets/framework.dart:3412:15)
flutter: #25 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4733:16)
flutter: #26 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4880:11)
flutter: #27 BuildOwner._runWithCurrentBuildTarget (package:flutter/src/widgets/framework.dart:2708:15)
flutter: #28 Element.rebuild (package:flutter/src/widgets/framework.dart:4407:12)
flutter: #29 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2813:33)
flutter: #30 WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:899:21)
flutter: #31 RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:320:5)
flutter: #32 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1119:15)
flutter: #33 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1057:9)
flutter: #34 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:973:5)
flutter: #38 _invoke (dart:ui/hooks.dart:157:10)
flutter: #39 PlatformDispatcher._drawFrame (dart:ui/platform_dispatcher.dart:253:5)
flutter: #40 _drawFrame (dart:ui/hooks.dart:120:31)
flutter: (elided 3 frames from dart:async)

As from question and error log, seems like you are trying to fresh screen/widget using setState but not the actual ad based container widget - still you are getting this error.
If I understood correctly.. then issue is about ad widget is trying to rebuild on setState call with older ad object but it expect new ad object everytime new build. So, avoid those kind of widget build if that's not required.
create a seprate ad based container widget like AppXyzAdWidget and move the ad's parent container code and other ad related code inside the new widget and use the newly created ad based widget on your screen.
This way you can decouple your screen without ad related things then after setState will not reload your ad and their widget just only refresh your content.

Calling setState() causes the widget to rebuild, so your FutureBuilder() widget fires the future task again. This is why you're seeing this error.
You need to remove FutureBuilder() and move your future task to initState():
// ...
// Some code
#override
void initState() {
setState(() {
_adBanner = createBannerAd();
});
_adBanner.load().whenComplete(() {
if (this.mounted) {
setState(() {
_showAdBanner = true;
});
}
});
super.initState();
}
#override
void dispose() {
_adBanner.dispose();
super.dispose();
}
// ...
// Some code
You can also have boolean to make the AdWidget() appear when the future task is complete:
bool _showAdBanner = false;
// ...
// Some code
_showAdBanner
? Container(
margin: EdgeInsets.only(bottom: 3),
width: myPercent(95, screenWidth),
height: myPercent(6, screenHeight),
alignment: Alignment.center,
child: AdWidget(
ad: _adBanner,
),
)
: Container()
// ...
// Some code

According to the google ads package example
googleads-mobile-flutter
You have to use didChangeDependencies
class BannarAdWidget extends StatefulWidget {
const BannarAdWidget({Key? key}) : super(key: key);
#override
State<BannarAdWidget> createState() => _BannarAdWidgetState();
}
class _BannarAdWidgetState extends State<BannarAdWidget> {
BannerAd? _bannerAd;
bool _bannerAdIsLoaded = false;
#override
void didChangeDependencies() {
// Create the ad objects and load ads.
_bannerAd = BannerAd(
size: AdSize.banner,
request: const AdRequest(),
adUnitId: AdmobHelper.bannerAdUnitId,
listener: BannerAdListener(
onAdLoaded: (Ad ad) {
print('$BannerAd loaded.');
setState(() => _bannerAdIsLoaded = true);
},
onAdFailedToLoad: (Ad ad, LoadAdError error) {
print('$BannerAd failedToLoad: $error');
ad.dispose();
},
onAdOpened: (Ad ad) => print('$BannerAd onAdOpened.'),
onAdClosed: (Ad ad) => print('$BannerAd onAdClosed.'),
),
)..load();
super.didChangeDependencies();
}
#override
void dispose() {
_bannerAd?.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
final BannerAd? bannerAd = _bannerAd;
if (_bannerAdIsLoaded && bannerAd != null) {
return SizedBox(
height: bannerAd.size.height.toDouble(),
width: bannerAd.size.width.toDouble(),
child: AdWidget(ad: bannerAd),
);
} else {
return const SizedBox.shrink();
}
}
class AdmobHelper {
static String get bannerAdUnitId {
if (Platform.isAndroid) {
return "ca-app-pub-3940256099942544/6300978111";
} else if (Platform.isIOS) {
return "ca-app-pub-3940256099942544/2934735716";
} else {
throw UnsupportedError('Unsupported platform');
}
}
}

Can you remove initState code and initialize _adBanner in your build function like this ?
#override
Widget build(BuildContext context) {
_adBanner = createBannerAd();
return Container(
margin: EdgeInsets.only(bottom: myPercent(2, screenHeight)),
child: FutureBuilder(
future: _adBanner.load(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
return Container(
margin: EdgeInsets.only(bottom: 3),
width: myPercent(95, screenWidth),
height: myPercent(6, screenHeight),
alignment: Alignment.center,
child: AdWidget(
ad: _adBanner,
),
);
}
return Container();
});
}

Related

The following _CastError was thrown building FutureBuilder<WebViewController>

I made program using flutter webview
I have error with _FutureBuilderState<WebViewController
What I want to do make the reload button as FloatingActionButton
I guess this error is relevant with future async function, but I am not sure where to fix.
══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
The following _CastError was thrown building FutureBuilder<WebViewController>(dirty, state:
_FutureBuilderState<WebViewController>#54b59):
Null check operator used on a null value
The relevant error-causing widget was:
FutureBuilder<WebViewController>
FutureBuilder:file:///Users/whitebear/MyCode/httproot/guessdrawing_flutter/lib/main.dart:305:12
When the exception was thrown, this was the stack:
#0 NavigationControls.build.<anonymous closure> (package:flutterweb/main.dart:311:59)
#1 _FutureBuilderState.build (package:flutter/src/widgets/async.dart:782:55)
#2 StatefulElement.build (package:flutter/src/widgets/framework.dart:4782:27)
#3 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4665:15)
#4 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4840:11)
#5 Element.rebuild (package:flutter/src/widgets/framework.dart:4355:5)
#6 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:4643:5)
#7 StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:4831:11)
#8 ComponentElement.mount (package:flutter/src/widgets/framework.dart:4638:5)
... Normal element mounting (29 frames)
#37 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3673:14)
#38 MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6333:36)
#39 MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6344:32)
... Normal element mounting (21 frames)
#60 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3673:14)
#61 MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6333:36)
#62 MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6344:32)
... Normal element mounting (116 frames)
#178 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3673:14)
#179 MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6333:36)
#180 MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6344:32)
... Normal element mounting (173 frames)
#353 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3673:14)
#354 MultiChildRenderObjectElement.inflateWidget (package:flutter/src/widgets/framework.dart:6333:36)
#355 MultiChildRenderObjectElement.mount (package:flutter/src/widgets/framework.dart:6344:32)
... Normal element mounting (371 frames)
#726 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3673:14)
#727 Element.updateChild (package:flutter/src/widgets/framework.dart:3425:18)
#728 RenderObjectToWidgetElement._rebuild (package:flutter/src/widgets/binding.dart:1198:16)
#729 RenderObjectToWidgetElement.mount (package:flutter/src/widgets/binding.dart:1167:5)
#730 RenderObjectToWidgetAdapter.attachToRenderTree.<anonymous closure> (package:flutter/src/widgets/binding.dart:1112:18)
#731 BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2573:19)
#732 RenderObjectToWidgetAdapter.attachToRenderTree (package:flutter/src/widgets/binding.dart:1111:13)
#733 WidgetsBinding.attachRootWidget (package:flutter/src/widgets/binding.dart:944:7)
#734 WidgetsBinding.scheduleAttachRootWidget.<anonymous closure> (package:flutter/src/widgets/binding.dart:924:7)
(elided 11 frames from class _RawReceivePortImpl, class _Timer, dart:async, and dart:async-patch)
my code is here.
class NavigationControls extends StatelessWidget {
const NavigationControls(this._webViewControllerFuture)
: assert(_webViewControllerFuture != null);
final Future<WebViewController> _webViewControllerFuture;
#override
Widget build(BuildContext context) {
return FutureBuilder<WebViewController>(
future: _webViewControllerFuture,
builder:
(BuildContext context, AsyncSnapshot<WebViewController> snapshot) {
final bool webViewReady =
snapshot.connectionState == ConnectionState.done;
final WebViewController controller = snapshot.data!;
//return IconButton(
return FloatingActionButton(
child: const Icon(Icons.replay),
onPressed: !webViewReady
? null
: () {
controller.reload();
},
);
},
);
}
NavigationControls is called here.
class WebViewExample extends StatefulWidget {
#override
_WebViewExampleState createState() => _WebViewExampleState();
}
class _WebViewExampleState extends State<WebViewExample> {
final Completer<WebViewController> _controller =
Completer<WebViewController>();
#override
void initState() {
super.initState();
if (Platform.isAndroid) WebView.platform = SurfaceAndroidWebView();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text(''),iew.
backgroundColor: Colors.white.withOpacity(0.0),
elevation: 0.0,
),
extendBodyBehindAppBar:true,
body: Builder(builder: (BuildContext context) {
return WebView(
javascriptMode: JavascriptMode.unrestricted,
onWebViewCreated: (WebViewController webViewController) {
_controller.complete(webViewController);
webViewController.loadUrl(
'https://example.com',
);
},
onProgress: (int progress) {
print("WebView is loading (progress : $progress%)");
},
javascriptChannels: <JavascriptChannel>{
_toasterJavascriptChannel(context),
},
navigationDelegate: (NavigationRequest request) {
if (request.url.startsWith('https://www.youtube.com/')) {
print('blocking navigation to $request}');
return NavigationDecision.prevent;
}
print('allowing navigation to $request');
return NavigationDecision.navigate;
},
onPageStarted: (String url) {
print('Page started loading: $url');
},
onPageFinished: (String url) {
print('Page finished loading: $url');
},
gestureNavigationEnabled: true,
);
}),
floatingActionButton:NavigationControls(_controller.future),
);
}
JavascriptChannel _toasterJavascriptChannel(BuildContext context) {
return JavascriptChannel(
name: 'Toaster',
onMessageReceived: (JavascriptMessage message) {
// ignore: deprecated_member_use
Scaffold.of(context).showSnackBar(
SnackBar(content: Text(message.message)),
);
});
}
}
The error is exactly at main.dart:305:12.
The only null check operator I can see in your code is:
final WebViewController controller = snapshot.data!;
So try changing your FAB to something like:
final bool webViewReady =
snapshot.connectionState == ConnectionState.done;
return FloatingActionButton(
child: const Icon(Icons.replay),
onPressed: !webViewReady
? null
: () {
snapshot.data!.reload();
},
This way you are not casting the type as non null before its used

Bottom navigation bar stopped working ScrollController attached to multiple scroll views pagecontroller.jumpTo error

'package:flutter/src/widgets/scroll_controller.dart': Failed assertion: line 113 pos 12: '_positions.length == 1': ScrollController attached to multiple scroll views.
After that error bottom navigation bar stop changing the current page's of pageview.
PageController pageController;
class MainController extends StatefulWidget {
#override
_MainControllerState createState() => _MainControllerState();
}
class _MainControllerState extends State<MainController>
with TickerProviderStateMixin {
#override
void initState() {
// TODO: implement initState
super.initState();
pageController = PageController(initialPage: 0, keepPage: true);
}
#override
void dispose() {
// TODO: implement dispose
super.dispose();
pageController.dispose();
}
PagesList() {
return BlocBuilder<BottomnavbarcubitCubit, BottomnavbarcubitState>(
builder: (context, state) {
return Scaffold(
body: PageView(
allowImplicitScrolling: true,
controller: pageController,
onPageChanged: (int index) => state.currentIndex = index,
children: [
NotificationsScreen(),
NotificationsScreen(),
NotificationsScreen(),
NotificationsScreen(),
],
),
bottomNavigationBar: NormalNavBar(),
);
},
);
}
}
Bottomnavbar's onTap func that creates error
try {
if (pageController.hasClients)
await pageController.animateToPage(state.currentIndex,
duration: Duration(milliseconds: 500),
curve: Curves.elasticOut);
} catch (err) {
print(err);
}
E/flutter (30081): #18 GestureBinding._handlePointerEvent
package:flutter/…/gestures/binding.dart:295
E/flutter (30081): #19 GestureBinding._flushPointerEventQueue
package:flutter/…/gestures/binding.dart:240
E/flutter (30081): #20 GestureBinding._handlePointerDataPacket
package:flutter/…/gestures/binding.dart:213
E/flutter (30081): #21 _rootRunUnary (dart:async/zone.dart:1206:13)
E/flutter (30081): #22 _CustomZone.runUnary (dart:async/zone.dart:1100:19)
E/flutter (30081): #23 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1005:7)
E/flutter (30081): #24 _invoke1 (dart:ui/hooks.dart:265:10)
E/flutter (30081): #25 _dispatchPointerDataPacket (dart:ui/hooks.dart:174:5)
It occurs when the data fetching from firestore is cancelled. Then bottom navigation bar not work until restart app.

Error with IBM Visual Recognition Classification with Flutter

I am trying to take an image and send it to IBM Watson to classify it into one of 3 custom classifiers. Below is all my code.
import 'dart:io';
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'package:flutter_ibm_watson/flutter_ibm_watson.dart';
import 'package:ibm_visual_recog_img_file/connection.dart';
import 'package:ourearth2020/screens/Community.dart';
import 'package:path/path.dart';
import 'dart:async';
import 'package:image_picker/image_picker.dart';
import 'package:flutter_speed_dial/flutter_speed_dial.dart';
import 'package:path_provider/path_provider.dart';
class VisualPage extends StatefulWidget {
#override
_VisualPageState createState() => _VisualPageState();
}
class _VisualPageState extends State<VisualPage> {
CameraController _controller;
List cameras;
String path;
var galleryImage;
CameraDescription cameraDescription;
Future initCamera() async {
cameras = await availableCameras();
var frontCamera = cameras.first;
_controller = CameraController(frontCamera, ResolutionPreset.high);
try {
await _controller.initialize();
} catch (e) {}
print('Controller Is Init:' + _controller.value.isInitialized.toString());
displayPreview();
}
bool displayPreview() {
if (_controller == null || !_controller.value.isInitialized) {
return false;
} else {
return true;
}
}
Future getImageFromGallery() async {
var image = await ImagePicker.pickImage(source: ImageSource.gallery);
setState(() {
galleryImage = image;
});
print('GALLERY IMAGE' + galleryImage.toString());
return galleryImage;
}
#override
void dispose() {
// Dispose of the controller when the widget is disposed.
_controller.dispose();
super.dispose();
}
#override
void initState() {
super.initState();
print('Running');
initCamera();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Stack(children: [
displayPreview()
? AspectRatio(
aspectRatio: MediaQuery.of(context).size.width /
MediaQuery.of(context).size.height,
child: CameraPreview(_controller),
)
: Container(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.yellow),
),
),
Positioned(
top: MediaQuery.of(context).size.height - 120,
child: GestureDetector(
onTap: () async {
await getImageFromGallery();
Navigator.push(context, MaterialPageRoute(builder: (context) =>
DisplayPicture(image: galleryImage)
));
},
child: Icon(
Icons.image,
color: Colors.white,
size: 60,
)),
),
Positioned(
top: MediaQuery.of(context).size.height - 120,
left: MediaQuery.of(context).size.width / 2.2,
child: GestureDetector(
behavior: HitTestBehavior.translucent,
child: Container(
child: Icon(
Icons.camera,
color: Colors.white,
size: 60,
)),
onTap: () async {
final path = (await getTemporaryDirectory()).path +
'${DateTime.now()}.png';
try {
await _controller.takePicture(path);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
DisplayPicture(imagePath: path)));
} catch (e) {
print('EEEE' + e);
}
}))
]));
}
}
class DisplayPicture extends StatelessWidget {
String imagePath;
File image;
String _text;
// File file = File(imagePath)
DisplayPicture({this.imagePath, this.image});
visualImageClassifier(File image) async{
IamOptions options = await IamOptions(iamApiKey: "NRDjngCby2d-pSHOPyWQJxhuB6vOY2uOTCX6KV2BCfwB", url: "https://api.us-south.visual-recognition.watson.cloud.ibm.com/instances/ef286f4e-84c7-44e0-b63d-a6a49a142a30").build();
VisualRecognition visualRecognition = new VisualRecognition(iamOptions: options, language: Language.ENGLISH); // Language.ENGLISH is language response
ClassifiedImages classifiedImages = await visualRecognition.classifyImageFile(image.path);
print(classifiedImages.getImages()[0].getClassifiers()[0]
.getClasses()[0]
.className);
// print("${image.toString()}");
// print('ACCESS'+options.accessToken);
//print(options);
//print("${image.path}");
//print('CLASSIFICATION'+classifiedImages.customClasses.toString()); // StreamBuilder(
// stream: StreamMyClassifier(
// image,
// 'NRDjngCby2d-pSHOPyWQJxhuB6vOY2uOTCX6KV2BCfwB', 'CompostxLandfillxRecycle_2056123069'),
// builder: (context, snapshot) {
// if (snapshot.hasData) {
// _text = snapshot.data;
// print(_text);
// }
// else {
// print('NO DATA AVAILABLE');
// }
//
// }
// );
}
#override
Widget build(BuildContext context) {
return Scaffold(body:Stack(children:[Center(child:image==null?Image.file(File(imagePath)):Image.file(image)),Positioned(
top: MediaQuery.of(context).size.height/2,
child: FloatingActionButton(onPressed:() async{
await visualImageClassifier(image==null?File(imagePath):image);
},
child:Icon(Icons.arrow_right)),
)]));
}
}
The image is successfully displayed on my screen but once I send it through the visualRecognition.classifyImageFile(....); it gives me an error saying I can not use image because it only supports String. I converted it to String but it gives me the error below.
[ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: FileSystemException: Cannot retrieve length of file, path = 'File: '/data/user/0/com.example.ourearth2020/cache2020-09-17 18:50:16.530957.png'' (OS Error: No such file or directory, errno = 2)
E/flutter (17606): #0 _File.length.<anonymous closure> (dart:io/file_impl.dart:366:9)
E/flutter (17606): #1 _rootRunUnary (dart:async/zone.dart:1198:47)
E/flutter (17606): #2 _CustomZone.runUnary (dart:async/zone.dart:1100:19)
E/flutter (17606): #3 _FutureListener.handleValue (dart:async/future_impl.dart:143:18)
E/flutter (17606): #4 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:696:45)
E/flutter (17606): #5 Future._propagateToListeners (dart:async/future_impl.dart:725:32)
E/flutter (17606): #6 Future._completeWithValue (dart:async/future_impl.dart:529:5)
E/flutter (17606): #7 Future._asyncCompleteWithValue.<anonymous closure> (dart:async/future_impl.dart:567:7)
E/flutter (17606): #8 _rootRun (dart:async/zone.dart:1190:13)
E/flutter (17606): #9 _CustomZone.run (dart:async/zone.dart:1093:19)
E/flutter (17606): #10 _CustomZone.runGuarded (dart:async/zone.dart:997:7)
E/flutter (17606): #11 _CustomZone.bindCallbackGuarded.<anonymous closure> (dart:async/zone.dart:1037:23)
E/flutter (17606): #12 _microtaskLoop (dart:async/schedule_microtask.dart:41:21)
E/flutter (17606): #13 _startMicrotaskLoop (dart:async/schedule_microtask.dart:50:5)
E/flutter (17606):
Some of the questions I have: Can I get the confidence score using this? The last time I tried using those statements to classify the image it used a general classifier(if I input an image of a skyscraper it told me skyscraper) so how can I have it classify with my 3 classifiers?
Btw I already set up the IBM Cloud and it is fully functional. The library that I found from pub.dev is here https://pub.dev/packages/flutter_ibm_watson
EDIT error code for getImages() method
[ERROR:flutter/lib/ui/ui_dart_state.cc(166)] Unhandled Exception: NoSuchMethodError: The method 'getImages' was called on null.
E/flutter (31403): Receiver: null
E/flutter (31403): Tried calling: getImages()
E/flutter (31403): #0 Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
E/flutter (31403): #1 DisplayPicture.visualImageClassifier (package:ourearth2020/screens/VisualPage.dart:147:30)
E/flutter (31403): <asynchronous suspension>
E/flutter (31403): #2 DisplayPicture.build.<anonymous closure> (package:ourearth2020/screens/VisualPage.dart:177:15)
E/flutter (31403): #3 _InkResponseState._handleTap (package:flutter/src/material/ink_well.dart:992:19)
E/flutter (31403): #4 _InkResponseState.build.<anonymous closure> (package:flutter/src/material/ink_well.dart:1098:38)
E/flutter (31403): #5 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:184:24)
E/flutter (31403): #6 TapGestureRecognizer.handleTapUp (package:flutter/src/gestures/tap.dart:524:11)
E/flutter (31403): #7 BaseTapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:284:5)
E/flutter (31403): #8 BaseTapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:219:7)
E/flutter (31403): #9 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:477:9)
E/flutter (31403): #10 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:78:12)
E/flutter (31403): #11 PointerRouter._dispatchEventToRoutes.<anonymous closure> (package:flutter/src/gestures/pointer_router.dart:124:9)
E/flutter (31403): #12 _LinkedHashMapMixin.forEach (dart:collection-patch/compact_hash.dart:377:8)
E/flutter (31403): #13 PointerRouter._dispatchEventToRoutes (package:flutter/src/gestures/pointer_router.dart:122:18)
E/flutter (31403): #14 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:108:7)
E/flutter (31403): #15 GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:220:19)
E/flutter (31403): #16 GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:200:22)
E/flutter (31403): #17 GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:158:7)
E/flutter (31403): #18 GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:104:7)
E/flutter (31403): #19 GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:88:7)
E/flutter (31403): #20 _rootRunUnary (dart:async/zone.dart:1206:13)
E/flutter (31403): #21 _CustomZone.runUnary (dart:async/zone.dart:1100:19)
E/flutter (31403): #22 _CustomZone.runUnaryGuarded (dart:async/zone.dart:1005:7)
E/flutter (31403): #23 _invoke1 (dart:ui/hooks.dart:283:10)
E/flutter (31403): #24 _dispatchPointerDataPacket (dart:ui/hooks.dart:192:5)
E/flutter (31403):
You can copy past run full code below
You can see confidence score in working demo below
please change image.toString() to image.path because image is File
from
ClassifiedImages classifiedImages = await visualRecognition.classifyImageFile(image.toString());
to
ClassifiedImages classifiedImages = await visualRecognition.classifyImageFile(image.path);
working demo
working demo 2 for CameraPreview
I/flutter (31132): living room
full code
import 'package:camera/camera.dart';
import 'package:flutter/material.dart';
import 'dart:io';
import 'package:flutter_ibm_watson/flutter_ibm_watson.dart';
import 'package:image_picker/image_picker.dart';
import 'package:path_provider/path_provider.dart';
class VisualPage extends StatefulWidget {
#override
_VisualPageState createState() => _VisualPageState();
}
class _VisualPageState extends State<VisualPage> {
CameraController _controller;
List cameras;
String path;
var galleryImage;
CameraDescription cameraDescription;
Future initCamera() async {
cameras = await availableCameras();
var frontCamera = cameras.first;
_controller = CameraController(frontCamera, ResolutionPreset.high);
try {
await _controller.initialize();
} catch (e) {}
print('Controller Is Init:' + _controller.value.isInitialized.toString());
displayPreview();
setState(() {});
}
bool displayPreview() {
if (_controller == null || !_controller.value.isInitialized) {
return false;
} else {
return true;
}
}
Future getImageFromGallery() async {
var image = await ImagePicker.pickImage(source: ImageSource.gallery);
setState(() {
galleryImage = image;
});
print('GALLERY IMAGE' + galleryImage.toString());
return galleryImage;
}
#override
void dispose() {
// Dispose of the controller when the widget is disposed.
_controller.dispose();
super.dispose();
}
#override
void initState() {
super.initState();
print('Running');
initCamera();
}
#override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
body: Stack(children: [
displayPreview()
? AspectRatio(
aspectRatio: MediaQuery.of(context).size.width /
MediaQuery.of(context).size.height,
child: CameraPreview(_controller),
)
: Container(
child: CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(Colors.yellow),
),
),
Positioned(
top: MediaQuery.of(context).size.height - 120,
child: GestureDetector(
onTap: () async {
await getImageFromGallery();
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
DisplayPicture(image: galleryImage)));
},
child: Icon(
Icons.image,
color: Colors.white,
size: 60,
)),
),
Positioned(
top: MediaQuery.of(context).size.height - 120,
left: MediaQuery.of(context).size.width / 2.2,
child: GestureDetector(
behavior: HitTestBehavior.translucent,
child: Container(
child: Icon(
Icons.camera,
color: Colors.white,
size: 60,
)),
onTap: () async {
final path = (await getTemporaryDirectory()).path +
'${DateTime.now()}.png';
try {
await _controller.takePicture(path);
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
DisplayPicture(imagePath: path)));
} catch (e) {
print('EEEE' + e);
}
}))
]));
}
}
class DisplayPicture extends StatelessWidget {
String imagePath;
File image;
String _text;
// File file = File(imagePath)
DisplayPicture({this.imagePath, this.image});
visualImageClassifier(File image) async {
IamOptions options = await IamOptions(
iamApiKey: "NRDjngCby2d-pSHOPyWQJxhuB6vOY2uOTCX6KV2BCfwB",
url:
"https://api.us-south.visual-recognition.watson.cloud.ibm.com/instances/ef286f4e-84c7-44e0-b63d-a6a49a142a30")
.build();
VisualRecognition visualRecognition = new VisualRecognition(
iamOptions: options,
language: Language.ENGLISH); // Language.ENGLISH is language response
ClassifiedImages classifiedImages =
await visualRecognition.classifyImageFile(image.path);
print(classifiedImages
.getImages()[0]
.getClassifiers()[0]
.getClasses()[0]
.className);
// print("${image.toString()}");
// print('ACCESS'+options.accessToken);
//print(options);
//print("${image.path}");
//print('CLASSIFICATION'+classifiedImages.customClasses.toString()); // StreamBuilder(
// stream: StreamMyClassifier(
// image,
// 'NRDjngCby2d-pSHOPyWQJxhuB6vOY2uOTCX6KV2BCfwB', 'CompostxLandfillxRecycle_2056123069'),
// builder: (context, snapshot) {
// if (snapshot.hasData) {
// _text = snapshot.data;
// print(_text);
// }
// else {
// print('NO DATA AVAILABLE');
// }
//
// }
// );
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Stack(children: [
Center(
child:
image == null ? Image.file(File(imagePath)) : Image.file(image)),
Positioned(
top: MediaQuery.of(context).size.height / 2,
child: FloatingActionButton(
onPressed: () async {
await visualImageClassifier(
image == null ? File(imagePath) : image);
},
child: Icon(Icons.arrow_right)),
)
]));
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: VisualPage(),
);
}
}

How to correctly mock NavigatorObserver in Flutter with Mockito?

I have a test where I'm trying to observe the behaviour of the [Navigator] when the app navigates from contacts_footer.dart to create_and_edit_contact.dart (push) and back (pop). Using verify from the Mockito package, I can successfully verify that the push behaviour works however, verifying the pop behaviour fails. The function _navigateToBack works as expected and testing for widgets that appear only in the contacts_footer.dart is successful, but observing the pop behaviour fails.
contacts_footer.dart
class ContactsFooter extends StatelessWidget {
static const navigateToEditPage = Key('navigateEdit');
const ContactsFooter({
Key key,
}) : super(key: key);
#override
Widget build(BuildContext context) {
return BottomAppBar(
color: Color.fromRGBO(244, 244, 244, 1),
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
IconButton(
icon: Icon(Icons.edit),
onPressed: () {
Provider.of<Contacts>(context).setEditMode(true);
Navigator.of(context).push(MaterialPageRoute(
builder: (context) => CreateAndEditContact()));
},
key: ContactsFooter.navigateToEditPage,
)
],
),
);
}
}
create_and_edit_contact.dart
class CreateAndEditContact extends StatefulWidget {
static const routeName = 'edit-contact';
static var editOrCreateDetails = Key('editOrCreate');
#override
_CreateAndEditContactState createState() => _CreateAndEditContactState();
}
class _CreateAndEditContactState extends State<CreateAndEditContact> {
...
Widget build(BuildContext context) {
_isEditMode = Provider.of<Contacts>(context).isEditMode;
...
return Scaffold (
..
RaisedButton(key: CreateAndEditContact.editOrCreateDetails,
onPressed: () {
....
if (_isEditMode) {
print(true);
Provider.of<Contacts>(context)
.updateContact(context,formData, _selectedContact.vUuid)
.then((data) {
Navigator.of(context).pop();
});
} else {
print(false);
Provider.of<Contacts>(context)
.createContact(context,formData)
.then((data) {
Navigator.of(context).pop();
}).catchError(
(error) => showDialog(
context: context,
builder: (context) => ErrorDialog(
error.toString(),
),
),
);
}
},
child: Text(
'Sumbit',
style: TextStyle(color: Colors.white),
),
color: Theme.of(context).accentColor,
),
)
}
}
test file .
group('EditPage navigation tests', () {
NavigatorObserver mockObserver;
setUp(() {
mockObserver = MockNavigatorObserver();
});
Future<Null> _buildMainPage(WidgetTester tester) async {
await tester.pumpWidget(MaterialApp(
home: Scaffold(
body: Builder(
builder: (context) => Center(
child: MultiProvider(
providers: [
ChangeNotifierProvider<Contacts>(create: (_) => Contacts()),
],
child: Builder(
builder: (_) => MaterialApp(home: ContactsFooter(),
),
);,
),
),
),
/// This mocked observer will now receive all navigation events
/// that happen in our app.
navigatorObservers: <NavigatorObserver>[mockObserver],
));
/// The tester.pumpWidget() call above just built our app widget
/// and triggered the pushObserver method on the mockObserver once.
}
Future<Null> _navigateToDetailsPage(WidgetTester tester) async {
/// Tap the button which should navigate to the edit details page.
/// By calling tester.pumpAndSettle(), we ensure that all animations
/// have completed before we continue further.
await tester.tap(find.byKey(ContactsFooter.navigateToEditPage));
await tester.pumpAndSettle();
}
Future<Null> _navigateToBack(WidgetTester tester) async {
await tester.tap(find.byKey(CreateAndEditContact.editOrCreateDetails));
int num = await tester.pumpAndSettle();
print(num);
}
testWidgets(
'when tapping "navigate to edit details" button, should navigate to details page',
(WidgetTester tester) async {
await _buildMainPage(tester);
//CreateAndEditContact widget not present on screen as push event is not triggered yet
expect(find.byType(CreateAndEditContact), findsNothing);
//Trigger push event
await _navigateToDetailsPage(tester);
// By tapping the button, we should've now navigated to the edit details
// page. The didPush() method should've been called...
final Route pushedRoute =
verify(mockObserver.didPush(captureAny, any)).captured.single;
print(pushedRoute);
// there should be a CreateAndEditContact page present in the widget tree...
var createAndEdit = find.byType(CreateAndEditContact);
expect(createAndEdit, findsOneWidget);
await _navigateToBack(tester);
verify(mockObserver.didPop(any, any));
expect(find.byType(CreateAndEditContact), findsNothing);
expect(find.byKey(ContactsFooter.navigateToEditPage), findsWidgets);
});
}
All the expect statements execute correctly. However verify(mockObserver.didPop(any, any)); results in an exception as if [NavigatorObserver] did not recognize the pop behaviour.
>(RouteSettings("/", null), animation: AnimationController#1a3c6(⏭ 1.000; paused; for MaterialPageRoute<dynamic>(/)))
5
══╡ EXCEPTION CAUGHT BY FLUTTER TEST FRAMEWORK ╞════════════════════════════════════════════════════
The following TestFailure object was thrown running a test:
No matching calls. All calls: MockNavigatorObserver.navigator,
MockNavigatorObserver._navigator==NavigatorState#36772(tickers: tracking 1 ticker), [VERIFIED]
MockNavigatorObserver.didPush(MaterialPageRoute<dynamic>(RouteSettings("/", null), animation:
AnimationController#1a3c6(⏭ 1.000; paused; for MaterialPageRoute<dynamic>(/))), null)
(If you called `verify(...).called(0);`, please instead use `verifyNever(...);`.)
When the exception was thrown, this was the stack:
#0 fail (package:test_api/src/frontend/expect.dart:153:30)
#1 _VerifyCall._checkWith (package:mockito/src/mock.dart:648:7)
#2 _makeVerify.<anonymous closure> (package:mockito/src/mock.dart:935:18)
#3 main.<anonymous closure>.<anonymous closure> (file:///Users/calvin.gonsalves/Projects/Flutter/Dec23-2019/cmic_mobile_field/test/main_widget_test.dart:316:13)
<asynchronous suspension>
#4 testWidgets.<anonymous closure>.<anonymous closure> (package:flutter_test/src/widget_tester.dart:124:25)
#5 TestWidgetsFlutterBinding._runTestBody (package:flutter_test/src/binding.dart:696:19)
<asynchronous suspension>
#8 TestWidgetsFlutterBinding._runTest (package:flutter_test/src/binding.dart:679:14)
#9 AutomatedTestWidgetsFlutterBinding.runTest.<anonymous closure> (package:flutter_test/src/binding.dart:1050:24)
#15 AutomatedTestWidgetsFlutterBinding.runTest (package:flutter_test/src/binding.dart:1047:15)
#16 testWidgets.<anonymous closure> (package:flutter_test/src/widget_tester.dart:121:22)
#17 Declarer.test.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:171:27)
<asynchronous suspension>
#18 Invoker.waitForOutstandingCallbacks.<anonymous closure> (package:test_api/src/backend/invoker.dart:242:15)
#23 Invoker.waitForOutstandingCallbacks (package:test_api/src/backend/invoker.dart:239:5)
#24 Declarer.test.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/declarer.dart:169:33)
#29 Declarer.test.<anonymous closure> (package:test_api/src/backend/declarer.dart:168:13)
#30 Invoker._onRun.<anonymous closure>.<anonymous closure>.<anonymous closure>.<anonymous closure> (package:test_api/src/backend/invoker.dart:392:25)
#44 _Timer._runTimers (dart:isolate-patch/timer_impl.dart:384:19)
#45 _Timer._handleMessage (dart:isolate-patch/timer_impl.dart:418:5)
#46 _RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:174:12)
(elided 28 frames from class _FakeAsync, package dart:async, package dart:async-patch, and package stack_trace)
The test description was:
when tapping "navigate to edit details" button, should navigate to details page
════════════════════════════════════════════════════════════════════════════════════════════════════
Test failed. See exception logs above.
The test description was: when tapping "navigate to edit details" button, should navigate to details page
✖ EditPage navigation tests when tapping "navigate to edit details" button, should navigate to details page
I referred https://iirokrankka.com/2018/08/22/writing-widget-tests-for-navigation-events/
The issue seems to be caused by Navigator lacking context - usually provided by MaterialApp in this case. As you've mentioned in the comments, moving navigatorObservers inside MaterialApp solves the issue. Another workaround is to use navigatorKey to directly manage Navigator without obtaining it first from a BuildContext. See this similar Stack Overflow post on how you can utilize navigatorKey.

How infinite scroll Flutter over REST pagination with provider?

I created a flutter project with provider package
Previously it had run well using ScopedModel following this sample project.
I want to implement v3 provider with the same logic,
// main.dart
#override
Widget build(BuildContext context) {
return MultiProvider(
providers: [
ChangeNotifierProvider(builder: (context) => NoteContentModel()),
],
...
home: NoteContentPage(),
),
);
}
// note_content_model.dart
class NoteContentModel extends ChangeNotifier {
final _pageSize = 30;
List<Content> _content = [];
bool _isLoading = false;
int _totalResults;
int _totalPages;
bool _hasMorePages = true;
String _placeName;
bool _isLoadingMore = false;
// .. other setter getter
int getNoteCount() => _content.length;
Future<dynamic> _getData([int page = 1]) async {
var res = await http.get(getUrl(page));
return jsonDecode(res.body);
}
Future getNoteContent([int page = 1]) async {
if (page == 1) {
_isLoading = true;
_content.clear();
} else {
_isLoadingMore = true;
}
notifyListeners();
var responseData = await _getData();
List noteContent = responseData['content'];
noteContent.forEach((content) {
_content.add(Content.fromJson(content));
});
_totalResults = responseData['total_count'];
_totalPages = responseData['page_count'];
if (responseData['page_number'] == totalPages) {
_hasMorePages = false;
}
if (page == 1) {
_isLoading = false;
} else {
_isLoadingMore = false;
}
notifyListeners();
}
}
// note_content_page.dart
class NoteContentPage extends StatefulWidget {
#override
_NoteContentPageState createState() => _NoteContentPageState();
}
class _NoteContentPageState extends State<NoteContentPage> {
int page = 1;
ScrollController controller;
void _scrollListener() {
final NoteContentModel noteModel = Provider.of<NoteContentModel>(context);
if (controller.position.pixels == controller.position.maxScrollExtent) {
if (!noteModel.isLoadingMore && noteModel.hasMorePages) {
page++;
print("Current page: $page");
noteModel.getNoteContent(page);
}
}
}
#override
void initState() {
super.initState();
controller = new ScrollController()..addListener(_scrollListener);
}
#override
void dispose() {
super.dispose();
controller.dispose();
}
#override
Widget build(BuildContext context) {
final NoteContentModel noteModel = Provider.of<NoteContentModel>(context);
// Call initiate first page
noteModel.getNoteContent(page);
return Scaffold(
appBar: AppBar(title: Text("Test")),
body: CustomScrollView(
controller: controller,
slivers: <Widget>[
noteModel.isLoading
? SliverFillRemaining(
child: Center(
child: CircularProgressIndicator(),
),
)
: SliverList(
delegate: SliverChildBuilderDelegate(
(context, index) {
if (index == noteModel.getNoteCount()) {
if (noteModel.hasMorePages) {
print("here1");
return Padding(
padding: const EdgeInsets.symmetric(vertical: 16.0),
child: Center(child: CircularProgressIndicator()),
);
}
return Container();
} else {
return Column(
children: <Widget>[
Padding(
padding: const EdgeInsets.all(16.0),
child: Text(noteModel.content[index].title),
// child: Text("test"),
),
],
);
}
},
childCount: noteModel.getNoteCount(),
),
)
],
),
);
}
}
I always got this message loop markNeedsBuild() called during build end trace error
I/flutter ( 2525): ══╡ EXCEPTION CAUGHT BY FOUNDATION LIBRARY ╞════════════════════════════════════════════════════════
I/flutter ( 2525): The following assertion was thrown while dispatching notifications for NoteContentModel:
I/flutter ( 2525): setState() or markNeedsBuild() called during build.
I/flutter ( 2525): This ListenableProvider<NoteContentModel> widget cannot be marked as needing to build because the
...
I/flutter ( 2525): #0 Element.markNeedsBuild.<anonymous closure> (package:flutter/src/widgets/framework.dart:3670:11)
I/flutter ( 2525): #1 Element.markNeedsBuild (package:flutter/src/widgets/framework.dart:3685:6)
I/flutter ( 2525): #2 State.setState (package:flutter/src/widgets/framework.dart:1161:14)
I/flutter ( 2525): #3 __BuilderListenableDelegate&BuilderStateDelegate&_ListenableDelegateMixin.startListening.<anonymous closure> (package:provider/src/listenable_provider.dart:186:36)
I/flutter ( 2525): #4 ChangeNotifier.notifyListeners (package:flutter/src/foundation/change_notifier.dart:206:21)
I/flutter ( 2525): #5 NoteContentModel.getNoteContent (package:paging_provider/providers/note_content_model.dart:42:5)
I/flutter ( 2525): <asynchronous suspension>
I/flutter ( 2525): #6 _NoteContentPageState.build (package:paging_provider/pages/note_content_page.dart:44:15)
I/flutter ( 2525): #7 StatefulElement.build (package:flutter/src/widgets/framework.dart:4012:27)
I/flutter ( 2525): #8 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3924:15)
I/flutter ( 2525): #9 Element.rebuild (package:flutter/src/widgets/framework.dart:3721:5)
I/flutter ( 2525): #10 ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3907:5)
...
// This trace always loop on app running
I/flutter ( 2525): Another exception was thrown: setState() or markNeedsBuild() called during build....
so that's all, any response will be appreciated.
You must wrap your functions in addPostFrameCallback():
So the call is submitted after the build function finish it work and draw widgets over screen
//Change
noteModel.getNoteContent(page);
//To
WidgetsBinding.instance.addPostFrameCallback((_) => noteModel.getNoteContent(page);
);
Hope this answer being valuable for someone.