Unexpected "uncaught" exception passed to `onError` of `runZonedGuarded()` despite `try`/`catch` - flutter

Given the following complete minimal example run on Flutter 3.7.3 and Dart 2.19.2:
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
void main() {
WidgetsFlutterBinding.ensureInitialized();
runZonedGuarded(() {
runApp(const MyApp());
}, (error, stack) {
print('onError: $error\n$stack');
});
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
#override Widget build(BuildContext context) => const MaterialApp(home: MyHomePage());
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
#override State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final http.Client _httpClient = http.Client();
#override
void initState() {
super.initState();
request().then((value) => print('then')).catchError((error) => print('catchError'));
}
Future<void> request() async {
try {
var request = http.Request('POST', Uri.parse('http://192.168.0.1'));
await _httpClient.send(request);
}
catch (error) {
print('catch: $error');
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: const Center(
child: Text('Push the button'),
),
floatingActionButton: FloatingActionButton(
onPressed: () => _httpClient.close(), // this leads to the exceptions
child: const Icon(Icons.add),
),
);
}
}
When the "+" button on the UI is pressed, a SocketException is both passed to the onError callback of the runZonedGuarded() and also the catch block of the HTTP request.
The console output is:
Restarted application in 720ms.
flutter: onError: SocketException: Connection attempt cancelled, host: 192.168.0.1, port: 80
#0 _NativeSocket.startConnect (dart:io-patch/socket_patch.dart:694:35)
#1 _RawSocket.startConnect (dart:io-patch/socket_patch.dart:1855:26)
#2 RawSocket.startConnect (dart:io-patch/socket_patch.dart:27:23)
#3 Socket._startConnect (dart:io-patch/socket_patch.dart:2078:22)
#4 Socket.startConnect (dart:io/socket.dart:763:21)
#5 _ConnectionTarget.connect (dart:_http/http_impl.dart:2466:20)
#6 _HttpClient._getConnection.connect (dart:_http/http_impl.dart:2906:12)
#7 _HttpClient._getConnection (dart:_http/http_impl.dart:2911:12)
#8 _HttpClient._openUrl (dart:_http/http_impl.dart:2766:12)
#9 _HttpClient.openUrl (dart:_http/http_impl.dart:2604:7)
#10 IOClient.send
#11 _MyHomePageState.request
#12 _MyHomePageState.initState
#13 StatefulElement._firstBuild
#14 ComponentElement.mount
--- 8< ---
#384 Element.inflateWidget (package:flutter/src/widgets/framework.dart:3953:16)<…>
flutter: catch: Connection attempt cancelled, host: 192.168.0.1, port: 80
flutter: then
What I would like to know is...
Why are two apparently identical exceptions raised rather than one? (The two exception objects have different identity hash codes, but otherwise appear equivalent.)
Why, if the exception passed to onError is considered uncaught, does the stack trace for that very exception clearly show the try/catch block as an ancestor?
How can I catch the uncaught exception? So that it can be dealt with and not be uncaught?
Note: It's intentional for this demonstration that the HTTP request and subsequent client closure results in a SocketException. I'm not asking why this results in a SocketException. I'm asking why there are two exceptions, one of which is considered uncaught, despite the use of try/catch.
Note 2: Run on iOS device.

Related

Flutter HTTPS Server on Mobile Phone

Hi I am trying to run a server locally on the device and access via a webview - but having issue accessing the files - specially te certs on the mobile device. Here is my code:
import 'dart:io';
import 'package:flutter/material.dart' hide Router;
import 'package:shelf/shelf.dart';
import 'package:shelf/shelf_io.dart';
import 'package:shelf_router/src/router.dart';
import 'package:webview_flutter/webview_flutter.dart';
Future<void> main() async {
await startServer();
runApp(const MyApp());
}
// Configure routes.
final _router = Router()
..get('/', _rootHandler)
..get('/www/<message>', _echoHandler);
Response _rootHandler(Request req) {
return Response.ok('Hello, World!\n');
}
Response _echoHandler(Request request) {
final message = request.params['message'];
return Response.ok('$message\n');
}
SecurityContext getSecurityContext() {
// Bind with a secure HTTPS connection
final chain =
Platform.script.resolve('certificates/server_chain.pem').toFilePath();
final key =
Platform.script.resolve('certificates/server_key.pem').toFilePath();
return SecurityContext()
..useCertificateChain(chain)
..usePrivateKey(key, password: 'dartdart');
}
startServer() async {
final ip = InternetAddress.anyIPv4;
// Configure a pipeline that logs requests.
final _handler = Pipeline().addMiddleware(logRequests()).addHandler(_router);
// For running in containers, we respect the PORT environment variable.
final port = int.parse(Platform.environment['PORT'] ?? '443');
final server =
await serve(_handler, ip, port, securityContext: getSecurityContext());
print('Server listening on port ${server.port}');
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Server Bind Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Server Bind'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
void initState() {
super.initState();
if (Platform.isAndroid) WebView.platform = AndroidWebView();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: WebView(
initialUrl:
'http://127.0.0.1:8888', //'http://${server.address.host}:${server.port}/index.html',
),
),
);
}
}
Here is the error I get:
[VERBOSE-2:ui_dart_state.cc(209)] Unhandled Exception: FileSystemException: Cannot open file, path = '/certificates/server_chain.pem' (OS Error: No such file or directory, errno = 2)
#0 _File.throwIfError (dart:io/file_impl.dart:635:7)
#1 _File.openSync (dart:io/file_impl.dart:479:5)
#2 _File.readAsBytesSync (dart:io/file_impl.dart:539:18)
#3 _SecurityContext.useCertificateChain (dart:io-patch/secure_socket_patch.dart:236:40)
#4 getSecurityContext (package:server_demo/main.dart:34:5)
#5 startServer (package:server_demo/main.dart:49:67)
#6 main (package:server_demo/main.dart:11:9)
#7 _runMainZoned.<anonymous closure>.<anonymous closure> (dart:ui/hooks.dart:145:25)
#8 _rootRun (dart:async/zone.dart:1428:13)
#9 _CustomZone.run (dart:async/zone.dart:1328:19)
#10 _runZoned (dart:async/zone.dart:1863:10)
#11 runZonedGuarded (dart:async/zone.dart:1851:12)
#12 _runMainZoned.<anonymous closure> (dart:ui/hooks.dart:141:5)
#13 _delayEntrypointInv<…>
Assuming your certificate chain is located in assets/localhost.crt, the private key in assets/localhost.key and the assets folder listed under assets in your pubspec.yaml.
You can try with the following code:
void init() async {
var chain =
utf8.encode(await rootBundle.loadString('assets/localhost.crt'));
var key = utf8.encode(await rootBundle.loadString('assets/localhost.key'));
var context = SecurityContext()
..useCertificateChainBytes(chain)
..usePrivateKeyBytes(key);
var server =
await HttpServer.bindSecure(InternetAddress.anyIPv6, 443, context);
await server.forEach((HttpRequest request) {
request.response.statusCode = HttpStatus.ok;
request.response.write('Hello World!');
request.response.close();
});
}
The problem you are having is derived from how a dart script accesses other files vs how flutter packages and access files in the application bundle. Accessing them as assets in the bundle and passing them to the SecurityContext as Bytes did the trick for me.

Binding has not yet been initialized. When Using isloates

** I am creating google map location app
I tried to resolve my self but i am not able to fix this bug
Please help me to fix this bug
i am getting error when i create isolate for get location
I have used packages
google_maps_flutter: ^2.1.8
geocoding: ^2.0.4
geolocator: ^8.2.1
flutter_bloc: ^8.0.1
**
i got error
> Restarted application in 2,738ms.
D/MapsInitializer( 6872): preferredRenderer: null
D/zzca ( 6872): preferredRenderer: null
I/Google Maps Android API( 6872): Google Play services package version: 221215028
I/Google Maps Android API( 6872): Google Play services maps renderer version(legacy): 203115000
7
I/Counters( 6872): exceeded sample count in FrameTime
>
> I/m.example.g_ma( 6872): NativeAlloc concurrent copying GC freed 17476(988KB) AllocSpace objects, 0(0B) LOS objects, 50% free, 7MB/14MB, paused 172us total 133.433ms
10
I/Counters( 6872): exceeded sample count in FrameTime
I/m.example.g_ma( 6872): NativeAlloc concurrent copying GC freed 4201(193KB) AllocSpace objects, 0(0B) LOS objects, 49% free, 7MB/14MB, paused 138us total 149.308ms
7
I/Counters( 6872): exceeded sample count in FrameTime
I/chatty ( 6872): uid=10498(com.example.g_map) androidmapsapi- identical 1 line
3
I/Counters( 6872): exceeded sample count in FrameTime
E/flutter ( 6872): [ERROR:flutter/runtime/dart_isolate.cc(1098)] Unhandled exception:
E/flutter ( 6872): Binding has not yet been initialized.
E/flutter ( 6872): The "instance" getter on the ServicesBinding binding mixin is only available once that binding has been initialized.
E/flutter ( 6872): Typically, this is done by calling "WidgetsFlutterBinding.ensureInitialized()" or "runApp()" (the latter calls the former). Typically this call is done in the "void main()" method. The "ensureInitialized" method is idempotent; calling it multiple times is not harmful. After calling that method, the "instance" getter will return the binding.
E/flutter ( 6872): In a test, one can call "TestWidgetsFlutterBinding.ensureInitialized()" as the first line in the test's "main()" method to initialize the binding.
E/flutter ( 6872): If ServicesBinding is a custom binding mixin, there must also be a custom binding class, like WidgetsFlutterBinding, but that mixes in the selected binding, and that is the class that must be constructed before using the "instance" getter.
E/flutter ( 6872): #0 BindingBase.checkInstance.<anonymous closure>
package:flutter/…/foundation/binding.dart:281
E/flutter ( 6872): #1 BindingBase.checkInstance
package:flutter/…/foundation/binding.dart:363
E/flutter ( 6872): #2 ServicesBinding.instance
package:flutter/…/services/binding.dart:48
E/flutter ( 6872): #3 MethodChannel.binaryMessenger
package:flutter/…/services/platform_channel.dart:132
**My Code is **
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:g_map/cubit/googlemap_cubit.dart';
// import 'package:google_maps_flutter/google_maps_flutter.dart';
import 'screens/home_page.dart';
void main() async{
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return BlocProvider<GooglemapCubit>(
create: (context) => GooglemapCubit(),
child: MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Map'),
),
);
}
}
import 'dart:developer';
import 'package:geolocator/geolocator.dart';
class GLocationPermission{
Future<bool> checkPermission()async{
bool serviceEnabled ;
LocationPermission permission;
serviceEnabled = await Geolocator.isLocationServiceEnabled();
if(!serviceEnabled){
log("",error: "Location service is not enabled");
}
permission = await Geolocator.checkPermission();
if(permission == LocationPermission.denied){
permission = await Geolocator.requestPermission();
if(permission == LocationPermission.denied){
log("Permission is denied again ");
}
}
if(permission == LocationPermission.deniedForever){
log("",error: "Location permission denied forever");
return false;
}
if(permission == LocationPermission.whileInUse || permission == LocationPermission.always){
return true;
}else{
return false;
}
}
}
import 'dart:developer';
import 'dart:isolate';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:g_map/isolates/current_location_in_background.dart';
import 'package:g_map/services/location_permission.dart';
import 'package:geocoding/geocoding.dart';
// import 'package:geolocator/geolocator.dart';
import 'package:google_maps_flutter/google_maps_flutter.dart';
// import 'package:geolocator/geolocator.dart';
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage>{
late GoogleMapController _mapController;
final TextEditingController _searchAddressController = TextEditingController();
final _locationPermission = GLocationPermission();
String searchedAddress = "";
late ReceivePort _receivePort;
late Isolate _isolate;
#override
void initState() {
_checkPermission();
super.initState();
}
Future<void> _checkPermission()async{
if(await _locationPermission.checkPermission() == true){
createIsloate();
}
}
Future<void> createIsloate()async{
_receivePort = ReceivePort();
_isolate = await Isolate.spawn(CurrentLocationInBackGround.getLocation, _receivePort.sendPort);
_receivePort.listen((message) {
log("message $message");
// final pos = message as Stream;
// pos.listen((event) {
// log("Event $event");
// });
},
onError: (error){
log("Error $error",error: error);
}
);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Stack(
children: [
_googleMap(
inititalCameraPosition: const CameraPosition(
target: LatLng(37.42796133580664, -122.085749655962),
)),
_searchAddressField(context: context)
],
));
}
Widget _googleMap({required CameraPosition inititalCameraPosition}) {
// buildWhen: (previous, current) => current.runtimeType == ,
return GoogleMap(
// minMaxZoomPreference: const MinMaxZoomPreference(1, 20),
zoomControlsEnabled: true,
onMapCreated: _onMapCreated,
myLocationButtonEnabled: true,
initialCameraPosition: inititalCameraPosition,
);
}
Widget _searchAddressField({required BuildContext context}){
return Card(
child: SizedBox(
width: double.infinity,
height: MediaQuery.of(context).size.height*.07,
child: Center(
child: TextField(
onChanged: (value){
// searchedAddress = context.read<GooglemapCubit>().searchAddress(address: value);
},
controller: _searchAddressController,
decoration: InputDecoration(border: InputBorder.none,
suffix: IconButton(onPressed:() => _searchAndNavigate(context: context), icon: const Icon(Icons.search))
),
),
),
),
);
}
Future<void> _searchAndNavigate({required BuildContext context})async{
final location = GeocodingPlatform.instance.locationFromAddress(_searchAddressController.text);
location.then((value){
debugPrint(value[0].latitude.toString());
debugPrint(value[0].longitude.toString());
_mapController.animateCamera(CameraUpdate.newCameraPosition(CameraPosition(
zoom: 12,
target:LatLng(value[0].latitude, value[0].longitude))));
});
}
void _onMapCreated(GoogleMapController controller) {
// _mapController = context.read<GooglemapCubit>().assignControllerOn(controller);
_mapController = controller;
}
}
import 'dart:developer';
import 'dart:isolate';
import 'package:geolocator/geolocator.dart';
class CurrentLocationInBackGround{
static void getLocation(SendPort sendPort)async{
final pos = await Geolocator.getCurrentPosition();
log("pos stream $pos");
sendPort.send(pos);
}
}
I think you tried to run geocoding methods on isolate because it's freezer the main thread
await placemarkFromCoordinates()
or
await locationFromAddress()
will freeze the main thread this bug on there repository
but here is a great solution
link to solution

MaterialApp rebuild when Home widget calls build function

My app's MyApp widget, which returns MaterialApp (as done in virtually every Flutter app) is rebuild whenever the build function on the home widget is called. I need to know why this happens, as it greatly reduces the performance of my app.
I use a StreamProvider (the Riverpod implementation of StreamBuilder) to either show my app's HomePage, LandingPage or loading screen (called PseudoSplashScreen for historical reasons), depending on whether a user is logged in or not, or whether the stream is waiting.
My main.dart contains, among other things:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
FirebaseMessaging.instance.unsubscribeFromTopic('allUsers');
runApp(const ProviderScope(child: MyApp()));
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
debugPrint("Returning MaterialApp");
return MaterialApp(
title: 'MyApp',
localizationsDelegates: AppLocalizations.localizationsDelegates,
supportedLocales: AppLocalizations.supportedLocales,
debugShowCheckedModeBanner: false,
theme: themeDataLight(),
darkTheme: themeDataDark(),
home: const ReDirector(),
);
}
}
class ReDirector extends ConsumerWidget {
const ReDirector({Key? key}) : super(key: key);
static const LandingPage landingPage = LandingPage();
static const PseudoSplashScreen pseudoSplashScreen = PseudoSplashScreen();
#override
Widget build(BuildContext context, WidgetRef ref) {
debugPrint("Building Redirector");
return ref.watch(authStreamProvider).when(
data: (data) {
debugPrint(data.toString());
if (data != null && data == AuthResultStatus.successful) {
debugPrint("Returning Homepage");
return Container(
width: double.infinity,
height: double.infinity,
color: Colors.blue,
);
} else {
debugPrint("AuthStreamProvider returned $data");
// When logging in, it is set to true. Hence, set it to false to prevent
// the isInAsync overlay from showing when logging out.
ref.read(landingPageProvider).isInAsync = false;
return landingPage;
}
},
error: (e, tb) {
debugPrint("Error in the AuthChecker");
debugPrint("$e\n$tb");
// When logging in, it is set to true. Hence, set it to false to prevent
// the isInAsync overlay from showing on error
ref.read(landingPageProvider).isInAsync = false;
return landingPage;
},
loading: () {
debugPrint("Returning PseudoSplashScreen");
return pseudoSplashScreen;
},
);
}
}
The Stream is derived from FirebaseAuth.instance.authStateChanges but is expanded to check some extra details on the user:
final authStreamProvider = StreamProvider.autoDispose<AuthResultStatus?>((ref) {
return FirebaseAuth.instance
.authStateChanges()
.asyncExpand((User? user) async* {
AuthResultStatus? result;
if (user != null) {
final IdTokenResult idTokenResult = await user.getIdTokenResult();
if (user.emailVerified && idTokenResult.claims!['approved'] == true) {
ref.read(userDataProvider).initialize(user, idTokenResult.claims!);
result = AuthResultStatus.successful;
} else {
result = AuthResultStatus.undefined;
}
}
debugPrint("AuthStreamProvider is yielding $result");
yield result;
});
});
Where AuthResultStatus is an enum. Now I would expect that while the stream is loading, the PseudoSplashScreen is shown, and when the Stream fires an AuthResultStatus.successful, the HomePage is shown. This is indeed what happens, but somehow my Redirector is rebuild about a second after the HomePage is shown. In fact, the build function of MyApp is called again! Regarding the debugPrints in the code, the console shows this:
I/flutter (22428): Returning MaterialApp
I/flutter (22428): Building Redirector
I/flutter (22428): Returning PseudoSplashScreen
I/flutter (22428): Creating new userdatamodel
I/flutter (22428): CURRENTUSER: Wessel van Dam
I/flutter (22428): AuthStreamProvider is yielding AuthResultStatus.successful
I/flutter (22428): Building Redirector
I/flutter (22428): AuthResultStatus.successful
I/flutter (22428): Returning Homepage
I/flutter (22428): Returning MaterialApp
I/flutter (22428): Building Redirector
I/flutter (22428): AuthResultStatus.successful
I/flutter (22428): Returning Homepage
Note that the rebuilding of the Redirector is not due to a new firing event of the Stream, because then you would expect another print of Returning successful ARS. However, this rebuild of the Redirector is pretty annoying as building the HomePage is a pretty intense process. This rebuild causes a the screen to flicker. Could anyone tell me why the Redirector's build function is called again in this sequence? If that can be prevented, the user experience for my app would be greatly improved.

The getter 'length' was called on null. fetch from api

I am trying to fetch data from api its splash screen of my app I want user wait 5 second when app is launched and then go to next screen but when I tried fetch data from api I received The getter 'length' was called on null. please help me here is my code I tried resolve it number of other resources but failed to find solution that's why I am posting my question is here please check and help
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_app/main.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
void main() {
runApp(new MaterialApp(
home: new SplashScreen(),
debugShowCheckedModeBanner: false,
routes: <String, WidgetBuilder>{
'/MyHomePage': (BuildContext context) => new MyHomePage()
},
));
}
class SplashScreen extends StatefulWidget {
#override
_SplashScreenState createState() => new _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
startTime() async {
var _duration = new Duration(seconds: 5);
return new Timer(_duration, navigationPage);
}
void navigationPage() {
Navigator.of(context).pushReplacementNamed('/MyHomePage');
}
bool _loading=true;
Map data;
List userData=null;
Future getData() async {
http.Response response = await http.get("https://livinghopemobile.com/public/api/fetch-site-settings?token=123ab_#_#AbCD");
data = json.decode(response.body);
debugPrint(response.body);
setState(() {
userData = data["data"];
_loading=false;
// print(userData[0]['title']);
});
}
#override
void initState() {
super.initState();
//startTime();
getData();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: ListView.builder(
itemCount:userData.length,
itemBuilder: (context, index) {
return Container(
child: Image.network(userData[index]['site_logo']),
);
}
)
);
}
}
Launching lib/ui/SplashScreen.dart on iPhone 11 Pro Max in debug mode...
Running Xcode build...
Xcode build done. 23.8s
Debug service listening on ws://127.0.0.1:60469/bL7bmRYyhoc=/ws
Syncing files to device iPhone 11 Pro Max...
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following NoSuchMethodError was thrown building SplashScreen(dirty, state: _SplashScreenState#5fa75):
The getter 'length' was called on null.
Receiver: null
Tried calling: length
The relevant error-causing widget was:
SplashScreen file:///Users/apple/livinghopev4/livinghope4ios/lib/ui/SplashScreen.dart:10:15
When the exception was thrown, this was the stack:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:54:5)
#1 _SplashScreenState.build (package:flutter_app/ui/SplashScreen.dart:61:30)
#2 StatefulElement.build (package:flutter/src/widgets/framework.dart:4612:27)
#3 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4495:15)
#4 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4667:11)
...
════════════════════════════════════════════════════════════════════════════════════════════════════
flutter: {"status":200,"message":"Data fetched successfully","data":{"id":1,"site_logo":"https:\/\/livinghopemobile.com\/public\/storage\/site_logo\/270421_122025_image.png","site_name":"Living hope","created_at":null,"updated_at":"2021-04-27T07:20:26.000000Z"}}
[VERBOSE-2:ui_dart_state.cc(186)] Unhandled Exception: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'List<dynamic>'
#0 _SplashScreenState.getData.<anonymous closure> (package:flutter_app/ui/SplashScreen.dart:41:7)
#1 State.setState (package:flutter/src/widgets/framework.dart:1267:30)
#2 _SplashScreenState.getData (package:flutter_app/ui/SplashScreen.dart:40:5)
<asynchronous suspension>
This is because data is not type List, and userData is null hence there is no length to it when you are calling userData.length in ListView.builder.
Change null to [].
{"status":200,"message":"Data fetched successfully","data":{"id":1,"site_logo":"https:\/\/livinghopemobile.com\/public\/storage\/site_logo\/270421_122025_image.png","site_name":"Living hope","created_at":null,"updated_at":"2021-04-27T07:20:26.000000Z"}}
You could append the received data to userData, like: userData.add(data).
You try it:
itemCount:userData.length == null ? 0 : userData.length
Data is returning in Object and you are taking it as List. This is the reason you are getting the error.
Solution:
Don't use Listview.builder as api response is just an object(Map<String, dynamic>).
You can simply use
Image.network(userData['site_logo']),
and everthing will be fine.

GoogleMap in PageView

I have a googlemap located on containers in a pageview... When u swipe between the pages that contain these googlemap widgets, the pagesnapping breaks... so inside my code when I do
class Homepage extends StatelessWidget {
#override build(BuildContext context){
return PageView(
children: <Widget>[
Container(color:Colors.red),
Container(color:Colors.green),
Container(color:Colors.blue),
Container(color:Colors.yellow),
Container(color:Colors.pink),
// Container(child:GoogleMap(initialCameraPosition: CameraPosition(target:LatLng(0, 0)),)),
// Container(child:GoogleMap(initialCameraPosition: CameraPosition(target:LatLng(0, 0)),)),
// Container(child:GoogleMap(initialCameraPosition: CameraPosition(target:LatLng(0, 0)),)),
// Container(child:GoogleMap(initialCameraPosition: CameraPosition(target:LatLng(0, 0)),))
],
);
}
This, it works fine and all the pages snap perfectly.. However when I uncomment the GoogleMap widgets like so:
class Homepage extends StatelessWidget {
#override build(BuildContext context){
return PageView(
children: <Widget>[
// Container(color:Colors.red),
// Container(color:Colors.green),
// Container(color:Colors.blue),
// Container(color:Colors.yellow),
// Container(color:Colors.pink),
Container(child:GoogleMap(initialCameraPosition: CameraPosition(target:LatLng(0, 0)),)),
Container(child:GoogleMap(initialCameraPosition: CameraPosition(target:LatLng(0, 0)),)),
Container(child:GoogleMap(initialCameraPosition: CameraPosition(target:LatLng(0, 0)),)),
Container(child:GoogleMap(initialCameraPosition: CameraPosition(target:LatLng(0, 0)),))
],
);
}
}
The PageView works for a while but breaks (on IOS) and this error is (sometimes) shown in the console:
[VERBOSE-2:ui_dart_state.cc(148)] Unhandled Exception: 'package:flutter/src/gestures/converter.dart': Failed assertion: line 155 pos 18: '!state.down': is not true.
#0 _AssertionError._doThrowNew (dart:core/runtime/liberrors_patch.dart:40:39)
#1 _AssertionError._throwNew (dart:core/runtime/liberrors_patch.dart:36:5)
#2 PointerEventConverter.expand (package:flutter/src/gestures/converter.dart:155:18)
#3 _SyncIterator.moveNext (dart:core/runtime/libcore_patch.dart:152:12)
#4 ListQueue.addAll (dart:collection/queue.dart:715:25)
#5 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:83:27)
#6 _rootRunUnary (dart:async/zone.dart:1136:13)
#7 _CustomZone.runUnary (dart:async/zone.dart:1029:19)
#8 _CustomZone.runUnaryGuarded (dart:async/zone.dart:931:7)
#9 _invoke1 (dart:ui/hooks.dart:223:10)
#10 _dispatchPointerDataPacket (dart:ui/hooks.dart:144:5
Anyone seen and fixed this?
Thanks for your attention..
John.
I had a similar issue working with google map in pageview but after searching online I got a solution that finally worked
All I did was put the google map in a stateful widget, used the with AutomaticKeepAliveClientMixin and #override bool get wantKeepAlive => true; and called in the required widget
This is the stateful widget containing the google map
class GoogleMapWidget extends StatefulWidget{
const GoogleMapWidget({Key? key}) : super(key: key);
#override
_GoogleMapWidgetState createState() => _GoogleMapWidgetState();
}
class _GoogleMapWidgetState extends State<GoogleMapWidget> with AutomaticKeepAliveClientMixin {
#override
bool get wantKeepAlive => true;
#override
Widget build(BuildContext context) {
return Container(
child:GoogleMap(initialCameraPosition: CameraPosition(target:LatLng(0, 0)),)
);
}
}
Then you can call it from your Homepage like so
class Homepage extends StatelessWidget {
#override
build(BuildContext context){
return PageView(
children: <Widget>[
GoogleMapWidget(),
GoogleMapWidget(),
],
);
}
}
I hope this is the answer you're looking for
don't use Pageview instead use PageView.builder and then create a global list
List latLong = [
// pass all google maps and latLong values here
];
then on itemBuilder pass the latlong according to index and don't forget to turn gestureDetector on your googleMaps else it'll also scroll the map