Null check operator - android

Hi guys I'm new to flutter . I was working with a follow along tutorial
and this were working out fine until I ran my code and got a null check operator used on a null value and when I remove the ! the code just stays on a loading mode and doesn't return the response from thee api?
please advice
below is my main.dart
import 'package:flutter/material.dart';
import 'package:c3mobiredo/presentation/LoginScreen.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return const MaterialApp(
title: 'Material App',
home: Home(),
);
}
}
below is my LoginScreen.dart file
import 'package:flutter/material.dart';
import 'package:c3mobiredo/connectivity/apiConfig.dart';
import 'package:c3mobiredo/connectivity/models/getTimesheetForUserDay.dart';
import '../connectivity/Services/api_service.dart';
class Home extends StatefulWidget {
const Home({Key? key}) : super(key: key);
#override
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
late List<UserProjectSpecificDay>? _userModel = [];
#override
void initState() {
super.initState();
_getData();
}
void _getData() async {
_userModel = (await ApiService().GetUserProjectSpecificDay())!;//where I'm getting the error but when I remove the ! the code stays in a loading state which is another issue
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('REST API Example'),
),
body: _userModel == null || _userModel!.isEmpty
? const Center(
child: CircularProgressIndicator(),
)
: ListView.builder(
itemCount: _userModel!.length,
itemBuilder: (context, index) {
return Card(
child: Column(
children: [
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(_userModel![index].id.toString()),
Text(_userModel![index].project.projectName),
],
),
const SizedBox(
height: 20.0,
),
Row(
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
Text(_userModel![index].hours),
Text(_userModel![index].desc),
],
),
],
),
);
},
),
);
}
}

since someone downvote, i update with reference from official documentation:
https://dart.dev/null-safety/understanding-null-safety
https://stackoverflow.com/a/69313493/12838877
when I remove the ! the code just stays on a loading mode
yes it because your _userModel == null
and here you set the condition like that
_userModel == null || _userModel!.isEmpty
? const Center(
child: CircularProgressIndicator(),)
here need to fix
use late means, the value is non-null variable and you will set the value later. remove late when you initilize nullable value.
when you use ? sign, it means, the variable is nullable
List<UserProjectSpecificDay>? _userModel; // since its nullable, no need to set initial value
then on API call:
void _getData() async {
_userModel = await ApiService().GetUserProjectSpecificDay());
}
no need ! anymore, because we had remove late above
last in your body:
body: _userModel == null // only check if null
? const Center(
child: CircularProgressIndicator(),)
: ListView.builder(
itemCount: _userModel.length ?? 0 // if null, set the list length = 0

It means your reponse.body is null. You cn use use a FutureBuiler to build your widget and you can also set a timeout for the request after what you show the user that there is no data.
Eg:
List<UserProjectSpecificDay>? _userModel;
bool isTimeout = false;
String errorMsg = '';
void _getData() async {
ApiService().GetUserProjectSpecificDay().then((response) {
// I suppose you have a "fromMap" in your model
if (response.statusCode == 200) {
var data = jsonDecode(response.body);
_userModel = UserProjectSpecificDay.fromMap(data);
} else if (response.statusCode == 408) {
setState(() {
isTimeout = true;
errorMsg = 'There was a network error';
});
} else setState(() => errorMsg = 'An error occured');
});
}
/* ... */
body: FutureBuilder(
builder: (_, __) {
if (_userModel != null) {
// return your widget
}
if (isTimeout) {
return Center(child: Text(errorMsg);
}
return Center(child: CircularProgressIndicator());
}

Related

Flutter setState() not updating the view after Invoking Flutter Code From Native Side

I am trying to implement invoking Flutter Code From Native Side using method channel and working as expected. But having issue with rendering the view after trying to set the state. Can any one help to fix the issue?
Actually the SimSlotInfo is calling from the below widget,
List<Step> getSteps() {
return <Step>[
Step(
state: currentStep > 0 ? StepState.complete : StepState.indexed,
isActive: currentStep >= 0,
title: const Text("Send SMS"),
content: Column(
children: [
SimSlotInfo()
],
),
),
];
}
SimSlotInfo dart class
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:flutterdemo/model/device_slot.dart';
class SimSlotInfo extends StatefulWidget {
//callback function
final void Function(String) callBackFunction;
const SimSlotInfo(this.callBackFunction, {super.key});
//const SimSlotInfo({Key? key}) : super(key: key);
#override
State<SimSlotInfo> createState() => _SimSlotInfoState();
}
class _SimSlotInfoState extends State<SimSlotInfo> {
final platformMethodChannel = const MethodChannel('common_lib_plugin');
List<SimDetails> simDetailsObj = [];
//execute the below code while page loading
#override
void initState() {
super.initState();
platformMethodChannel.setMethodCallHandler(handleNativeMethodCall);
}
Future<void> handleNativeMethodCall(MethodCall call) async {
// do some processing
switch(call.method) {
case "deviceInfo":
var simData = call.arguments;
var arrayObjsText = '[{"slot":0,"simno":"89911017061","deviceid":"3518920","carrierName":"Vodafone"},{"slot":1,"simno":"89101706","deviceid":"3511643","carrierName":"JIO"}]';
List simObjsJson = jsonDecode(arrayObjsText) as List;
simDetailsObj = simObjsJson.map((tagJson) => SimDetails.fromJson(tagJson)).toList();
setState(() {
simDetailsObj = simDetailsObj;
});
}
}
#override
Widget build(BuildContext context) {
return Column(
children:
simDetailsObj.map((data) => RadioListTile(
dense: true,
contentPadding: EdgeInsets.zero,
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
"${data.carrierName}",
style: const TextStyle(color: Colors.black, fontSize: 18),
),
],
),
groupValue: _selectedSim,
value: data.simno,
onChanged: (val) {
},
)).toList()
);
}
}
First, you are trying to assign List to List so your code is getting brake there. to solve that loop the object with SimDetails object. and that will do the trick
ParentWidget
class _ParentWidgetState extends State<ParentWidget> {
#override
Widget build(BuildContext context) {
return ChildWidget( // <---- child widget
callSetState: (list) { // <--- callback Function
print(list);
setState(() {
// <---
});
},
);
}
}
In Child widget
class ChildWidget extends StatefulWidget {
const ChildWidget({Key? key, required this.callSetState}) : super(key: key);
final Function(List<SimDetails>) callSetState; // <-- declare callback function here
#override
State<ChildWidget> createState() => _ChildWidgetState();
}
and replace your setState with widget.callSetState
Future<void> handleNativeMethodCall(MethodCall methodCall) async {
switch (call.method) {
case 'deviceInfo':
var simData = call.arguments;
var arrayObjsText =
'[{"slot":0,"simno":"89911017061","deviceid":"3518920","carrierName":"Vodafone"},{"slot":1,"simno":"89101706","deviceid":"3511643","carrierName":"JIO"}]';
for (var data in jsonDecode(arrayObjsText)) {
simDetailsObj.add(
SimDetails(
slot: data['slot'],
simno: data['simno'],
deviceid: data['deviceid'],
carrierName: data['carrierName'],
),
);
}
/// setState(() {});
widget.callSetState(simDetailsObj);
break;
default:
}}

Flutter The method 'map' was called on null. Receiver: null error

I'm having this super annoying issue of being unable to grab and display a table from my server hosted on PhpmyAdmin. (I've managed to grab the data and have it printed in the console, but now that I'm trying to display it in a table I can't seem to get it working)
I've tried nulling my variables but I'm not really sure what the main culprit for this error is. Any help would be greatly appreciated.
Image of Error
data.dart File
class dataListing extends StatefulWidget {
const dataListing({Key? key}) : super(key: key);
#override
State<dataListing> createState() => _dataListingState();
}
class _dataListingState extends State<dataListing> {
#override
Widget build(BuildContext context) {
return Container();
}
}
class listingData{
String? ListingID, listingName, listingDescription, address, suburbName, phoneNumber, openingHours, Email, Website;
listingData({
this.ListingID,
this.listingName,
this.listingDescription,
this.address,
this.suburbName,
this.phoneNumber,
this.openingHours,
this.Email,
this.Website,
});
//constructor
List<listingData> datalist = [];
factory listingData.fromJSON(Map<String, dynamic> json){
return listingData(
ListingID: json["ListingID"],
listingName: json["listingName"],
listingDescription: json["listingDescription"],
address: json["address"],
suburbName: json["suburbName"],
phoneNumber: json["phoneNumber"],
openingHours: json["openingHours"],
Email: json["Email"],
Website: json["Website"],
);
}
}
Directory.dart file
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'package:app/pages/data.dart';
class directoryPage extends StatefulWidget {
#override
State<directoryPage> createState() => _directoryPageState();
}
class _directoryPageState extends State<directoryPage> {
// List serviceListing = [];
//
// getAllListing()async{
// String url = "URL HERE";
// var response = await http.get(Uri.parse(url));
// if (response.statusCode == 200){
// setState (() {
// serviceListing = json.decode(response.body);
// });
// print (serviceListing);
// return serviceListing;
// }
// }
bool error = false, dataloaded = false;
var data;
String dataurl = "URL HERE";
#override
void initState (){
loaddata();
super.initState();
// getAllListing();
}
void loaddata() {
Future.delayed(Duration.zero,() async {
var res = await http.post(Uri.parse(dataurl));
if (res.statusCode == 200) {
setState(() {
data = json.decode(res.body);
dataloaded = true;
});
}
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Directory'),
centerTitle: true,
elevation: 0,
backgroundColor: Color(0xFFA30B32),
//WSU Appbar Icon
leading: Padding(
padding: const EdgeInsets.all(8.0),
child: Image.asset("assets/wsulogo.png", scale: 8.0),
),
),
body: Container(
padding: EdgeInsets.all(15),
child:dataloaded?datalist():
Center(
child:CircularProgressIndicator()
),
)
);
}
Widget datalist(){
if(data["error"]) {
return Text(data["errmsg"]);
}else{
List<listingData> datalist = List<listingData>.from(data["data"].map((i){
return listingData.fromJSON(i);
})
);
return Table( //if data is loaded then show table
border: TableBorder.all(width:1, color:Colors.black45),
children: datalist.map((listingdata){
return TableRow( //return table row in every loop
children: [
//table cells inside table row
TableCell(child: Padding(
padding: EdgeInsets.all(5),
child:Text(listingdata.ListingID!)
)
),
TableCell(child: Padding(
padding: EdgeInsets.all(5),
child:Text(listingdata.listingName!)
)
),
TableCell(child: Padding(
padding: EdgeInsets.all(5),
child:Text(listingdata.listingDescription!)
)
),
TableCell(child: Padding(
padding: EdgeInsets.all(5),
child:Text(listingdata.address!)
)
),
]
);
}).toList(),
);
}
}
}
Looks like the issue was actually unrelated to the dart side of things, the php code wasn't properly structuring the data. Cannot have underscores or spaces.
Correct-> $json["dballlisting"] = array (); (I renamed it to just "data" later)
Incorrect->$json["db_all_listing"] = array ();
The error seems to be originating from this line, the data['data'] is null which is expected to be an Array.
List<listingData> datalist = List<listingData>.from(data["data"].map((i){
return listingData.fromJSON(i);
})
You need to investigate your API call to make sure why it is happening. If the null value is expected then you need to add safeguards in your code to make sure it won't break when it encounter such scenarios. You can add null safety checks for that one way to do it would be to
List<listingData> datalist = List<listingData>.from((data["data"] ?? []).map((i){
return listingData.fromJSON(i);
})

Firebase auth not persisting on iOS or Android in Flutter

To start, I have gone through more than 20 different questions and solutions here on Stack Overflow about this topic (most of them are related to the web version), I have also tried twitter, and even the FlutterDev Discord server and cannot seem to find this issue.
I am using firebase for mobile authentication for my app, and no matter what I try, I cannot seem to get the persistent auth state to work on iOS or Android.
Here is my main:
Future<void> main() async {
WidgetsFlutterBinding.ensureInitialized();
await Firebase.initializeApp();
runApp(
MultiProvider(
...
child: const MyApp(),
),
);
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
final const ColorScheme colorScheme = ColorScheme(
...
);
#override
Widget build(BuildContext context) {
bool isDebug = false;
if (Constants.DEBUG_BANNER == 'true') {
isDebug = true;
}
return MaterialApp(
theme: ThemeData(
...
),
routes: {
// This is a general layout of how all my routes are in case this is the issue
Screen.route: (BuildContext context) => const Screen(),
},
home: const HomeScreen(),
debugShowCheckModeBanner: isDebug,
);
}
}
the ... is just code that I think is unrelated to my question and so I am hiding it for brevity. Mostly themes, and private data
Let's just start with my google-sign-in-button and if necessary I can share others if it is important. We are using Facebook, Google, and Apple for iOS.
class GoogleSignInButton extends StatefulWidget {
const GoogleSignInButton({Key? key}) : super(key: key);
#override
_GoogleSignInButtonState createState() => _GoogleSignInButtonState();
}
class _GoogleSignInButtonState extends State<GoogleSignInButton> {
bool _isSigningIn = false;
#override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 16.0),
child: _isSigningIn
? CircularProgressIndicator(
valueColor: AlwaysStoppedAnimation<Color>(MRRM.colorScheme.primary),
)
: OutlinedButton(
key: const Key('google_sign_in_button'),
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(Colors.white),
shape: MaterialStateProperty.all(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(40),
),
),
),
onPressed: () async {
setState(() {
_isSigningIn = true;
});
context.read<Member>().signInWithGoogle(context: context).then<void>((void user) {
setState(() {
_isSigningIn = false;
});
Navigator.pushReplacementNamed(context, UserInfoScreen.route);
});
},
child: Padding(
padding: const EdgeInsets.fromLTRB(0, 10, 0, 10),
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
const Image(
image: AssetImage('assets/images/png/google_logo.png'),
height: 35.0,
),
Padding(
padding: const EdgeInsets.only(left: 10),
child: Text(
'Sign in with Google',
style: TextStyle(
fontSize: 20,
color: MRRM.colorScheme.secondary,
fontWeight: FontWeight.w600,
),
))
],
),
),
),
);
}
}
I am using the provider pub, which is what context.read<Object?>() is from.
Here is the signInWithGoogle function;
Future<String> signInWithGoogle({required BuildContext context}) async {
final FirebaseAuth _auth = FirebaseAuth.instance;
final GoogleSignIn googleSignIn = GoogleSignIn();
final GoogleSignInAccount? googleSignInAccount =
await googleSignIn.signIn();
if (googleSignInAccount != null) {
final GoogleSignInAuthentication googleSignInAuthentication =
await googleSignInAccount.authentication;
final AuthCredential credential = GoogleAuthProvider.credential(
accessToken: googleSignInAuthentication.accessToken,
idToken: googleSignInAuthentication.idToken,
);
try {
final UserCredential userCredential =
await _auth.signInWithCredential(credential);
_firebaseUser = userCredential.user!;
_authType = AuthType.Google;
_uuId = _firebaseUser.uid;
notifyListeners();
} on FirebaseAuthException catch (e) {
if (e.code == 'account-exists-with-different-credential') {
ScaffoldMessenger.of(context).showSnackBar(
customSnackBar(
content: 'The account already exists with different credentials.',
),
);
} else if (e.code == 'invalid-credential') {
ScaffoldMessenger.of(context).showSnackBar(
customSnackBar(
content: 'Error occurred while accessing credentials. Try again.',
),
);
}
} catch (e) {
ScaffoldMessenger.of(context).showSnackBar(
customSnackBar(
content: 'Error occurred using Google Sign-In. Try again.',
),
);
}
}
return getMemberLogin();
}
This is contained in my Member object, which just stores all of the Auth data as well as the Member specific data that comes from one of our internal API's, and the member data is stored as an App State object in provider, which is linked in the main.dart file
The getMemberLogin() function is just taking the UUID from the auth and sending it to an API and getting internal member data, I would hope that a simple post request isn't what is causing this. but if you think it might let me know and I will try to post it while obfuscating any NDA related data.
This is the home/splash Screen that handles the initial routing and goes to the loadingScreen that is supposed to be checking if there is a persisted login and going to the UserInfo screen instead of the Auth Screen.
class HomeScreen extends StatefulWidget {
const HomeScreen({Key? key}) : super(key: key);
static const String route = '/home';
#override
_HomeScreenState createState() => _HomeScreenState();
}
class _HomeScreenState extends State<HomeScreen> {
#override
Widget build(BuildContext context) {
return Scaffold(
body: Column(
key: const Key('Home'),
children: <Widget>[
Expanded(
child: Image.asset('assets/images/png/Retail_Rebel_Primary.png'),
),
BlinkingTextButton(
key: const Key('blinking_text_button'),
textButton: TextButton(
child: Text(
'Tap to continue',
style: TextStyle(
color: MRRM.colorScheme.primary,
fontSize: 16.0,
),
),
onPressed: () {
Navigator.of(context).pushReplacementNamed(LoadingScreen.route);
},
),
),
Container(
height: 8.0,
),
],
),
);
}
}
And lastly, this is the LoadingScreen that the HomeScreen navigates to:
class LoadingScreen extends StatelessWidget {
const LoadingScreen({Key? key}) : super(key: key);
static const String route = '/loadingScreen';
#override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (BuildContext context, AsyncSnapshot<User?> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
if (snapshot.hasData) {
print('user is logged in');
SchedulerBinding.instance!.addPostFrameCallback((_) {
Navigator.of(context).pushReplacementNamed(UserInfoScreen.route);
});
return const Text('');
} else {
print('no user is logged in');
SchedulerBinding.instance!.addPostFrameCallback((_) {
Navigator.of(context).pushReplacementNamed(AuthScreen.route);
});
return const Text('');
}
}
return const SplashScreen();
},
);
}
}
Not sure if possibly the way that I am handing routing may be the issue, but it is very common for me to use Navigator.of(context).pushReplacementNamed(); unless popping is necessary then I will typically just use Navigator.of(context).pop();. I usually only use .pop() for modals/alertDialogs, and for things like QR scanners to return to previous screen.
Sorry if this is too much info, or I forgot a ton of stuff. I have been working on trying to get this fixed for a little over a week now and am kind of getting frustrated.
Thank you for any and all responses.
Just because I think it is important to see what I have looked at already, here is a list of a couple of other questions I have looked through that did not help.
This one I believe is dated as of August 2020, especially considering that onAuthStateChanges has been changed to a stream authStateChanges().
I have also tried just implementing auth in the exact way described in the docs here but same issue.
I also tried just using:
FirebaseAuth.instance.authStateChanges().then((User? user) {
if (user != null) {
Navigator.of(context).pushReplacementNamed(UserInfoScreen.route);
} else {
Navigator.of(context).pushReplacementNamed(AuthScreen.route);
}
Which didn't work. I have also attempted to just simply check if there is a current user with:
User user = FirebaseAuth.instance.currentUser;
if (user != null && user.uid != null) {
Navigator.of(context).pushReplacementNamed(UserInfoScreen.route);
} else {
Navigator.of(context).pushReplacementNamed(AuthScreen.route);
}
which still always went to AuthScreen I have also tried all of these methods as asynchronous tasks to see if maybe it is just taking a second to load, and same issue. The weirdest one is with the current method if I take out the if(snapshot.connectionState == ConnectionState.waiting) from the LoadingScreen it will print out no user is logged in immediately followed by user is logged in and then no user is logged in again and then it will navigate to AuthScreen
If you follow what I have done up above, and make a single change, it will work with persisted logins.
change:
class LoadingScreen extends StatelessWidget {
const LoadingScreen({Key? key}) : super(key: key);
static const String route = '/loadingScreen';
#override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (BuildContext context, AsyncSnapshot<User?> snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
if (snapshot.hasData) {
print('user is logged in');
SchedulerBinding.instance!.addPostFrameCallback((_) {
Navigator.of(context).pushReplacementNamed(UserInfoScreen.route);
});
return const Text('');
} else {
print('no user is logged in');
SchedulerBinding.instance!.addPostFrameCallback((_) {
Navigator.of(context).pushReplacementNamed(AuthScreen.route);
});
return const Text('');
}
}
return const SplashScreen();
},
);
}
}
to
class LoadingScreen extends StatelessWidget {
const LoadingScreen({Key? key}) : super(key: key);
static const String route = '/loadingScreen';
#override
Widget build(BuildContext context) {
return StreamBuilder<User?>(
stream: FirebaseAuth.instance.authStateChanges(),
builder: (BuildContext context, AsyncSnapshot<User?> snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
if (snapshot.hasData) {
print('user is logged in');
SchedulerBinding.instance!.addPostFrameCallback((_) {
Navigator.of(context).pushReplacementNamed(UserInfoScreen.route);
});
return const Text('');
} else {
print('no user is logged in');
SchedulerBinding.instance!.addPostFrameCallback((_) {
Navigator.of(context).pushReplacementNamed(AuthScreen.route);
});
return const Text('');
}
}
return const SplashScreen();
},
);
}
}

Information from api doesn't show - Flutter

I have a problem with Future builder in Flutter. It gets the info from api successfully but doesn't show it. When I put print and print the info from api, it is ok and it shows the movies name without any problems. here is my code:
class Search extends StatefulWidget {
final String value;
Search({Key key, String this.value}) : super(key: key);
#override
_SearchState createState() => _SearchState();
}
class _SearchState extends State<Search> {
var title;
Future getSearch({index}) async {
http.Response response = await http.get(
'https://api.themoviedb.org/3/search/company?api_key=6d6f3a650f56fd6b3347428018a20a73&query=' +
widget.value);
var results = json.decode(response.body);
setState(() {
this.title = results['results'];
});
return title[index]['name'];
}
getName(index) {
return title[index]['name'];
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: Color(0xff1d1d27),
body: Column(
children: [
Expanded(
child: FutureBuilder(
initialData: [],
future: getSearch(),
builder: (context, snapshot) {
return ListView.builder(itemBuilder: (context, index) {
Padding(
padding:
EdgeInsets.symmetric(horizontal: 30, vertical: 20),
child: Container(
color: Colors.white,
child: Text(getName(index).toString()),
),
);
});
},
))
],
)),
);
}
}
Please Use this code, It works fine to fetch the names and show them on the list,
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
class Search extends StatefulWidget {
final String value;
Search({Key key, String this.value}) : super(key: key);
#override
_SearchState createState() => _SearchState();
}
class _SearchState extends State<Search> {
var title;
var results;
getSearch() async {
http.Response response = await http.get(
'https://api.themoviedb.org/3/search/company?api_key=6d6f3a650f56fd6b3347428018a20a73&query=' +
widget.value);
results = json.decode(
response.body); //make it global variable to fetch it everywhere we need
return results['results'][0]['name'];
}
getName(index) {
return results['results'][index]['name'];
}
#override
Widget build(BuildContext context) {
return SafeArea(
child: Scaffold(
backgroundColor: Color(0xff1d1d27),
body: Column(
children: [
Expanded(
child: FutureBuilder(
// initialData: [],
future: getSearch(),
builder: (context, snapshot) {
String name =
snapshot.data; // to get the data from the getSearch
print(name);
if (snapshot.hasData) {
// if there is data then show the list
return ListView.builder(
itemCount: results['results']
?.length, // to get the list length of results
itemBuilder: (context, index) {
return Padding(
padding: EdgeInsets.symmetric(
horizontal: 30, vertical: 20),
child: Container(
color: Colors.white,
child: Text(getName(index)
.toString()), // pass the index in the getName to get the name
),
);
});
} else {
// if there is no data or data is not loaded then show the text loading...
return new Text("Loading...",
style: TextStyle(fontSize: 42, color: Colors.white));
}
},
))
],
)),
);
}
}
P.S
To Learn the basics of Futurebuilder You can see this article For more learning
I have commented the code to explain more to you.

Image_picker throws removeInvalidNode all the node in jank list is out of time instead of returning image

I am trying to choose image with gallery or camera and display with image_picker.
When I run the app in android, I am able to choose image but not displaying. In contrast I am getting following in the console for the first time.
I/HwViewRootImpl(11213): removeInvalidNode all the node in jank list is out of time
If I repeat the same, it gives following in each time while press the button instead of opening gallery or camera.
I/flutter (11213): PlatformException(already_active, Image picker is already active, null)
I found following solutions from my search but not solved my case.
flutter clean , flutter clean
changing the version of the plugin
updating all dependencies
using retrieveLostData method as stated in the plugin documentation
Following is the code I have used for retrieve image:
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
class CameraApp extends StatefulWidget {
#override
_CameraAppState createState() => _CameraAppState();
}
class _CameraAppState extends State<CameraApp> {
File imageFile;
#override
void initState() {
super.initState();
}
Future _getImage(int type) async {
print("Called Image Picker");
var image = await ImagePicker.pickImage(
source: type == 1 ? ImageSource.camera : ImageSource.gallery,
);
setState(() {
print("$image.path");
imageFile = image;
});
}
Future<void> retrieveLostData() async {
final LostDataResponse response = await ImagePicker.retrieveLostData();
if (response == null) {
return;
}
if (response.file != null) {
setState(() {
if (response.type == RetrieveType.image) {
imageFile = response.file;
}
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Image Editor"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
imageFile != null
? Image.file(
imageFile,
height: MediaQuery.of(context).size.height / 2,
)
: Text("Image editor"),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text("Add Slip"),
content: Row(
children: <Widget>[
Expanded(
child: new FlatButton(
child: new Text("Camera"),
onPressed: () {
_getImage(1);
Navigator.pop(context);
},
),
),
Expanded(
child: new FlatButton(
child: new Text("Gallery"),
onPressed: () {
_getImage(2);
Navigator.pop(context);
},
),
)
],
),
);
},
);
},
tooltip: 'Pick Image',
child: Icon(Icons.camera),
),
);
}
}
I've tried the sample code that you've shared and for some reason got compiler issues but not the same issue as yours. Therefore, I've tried to debug your code. Here is the fixed code:
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
File imageFile;
#override
void initState() {
super.initState();
}
Future _getImage(int type) async {
print("Called Image Picker");
var image = await await ImagePicker.platform.pickImage(
source: type == 1 ? ImageSource.camera : ImageSource.gallery,
);
setState(() {
print("$image.path");
imageFile = File(image.path);
});
}
Future<void> retrieveLostData() async {
final LostData response = await ImagePicker.platform.retrieveLostData();
if (response == null) {
return;
}
if (response.file != null) {
setState(() {
if (response.type == RetrieveType.image) {
imageFile = response.file as File;
}
});
}
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Image Editor"),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
imageFile != null
? Image.file(
imageFile,
height: MediaQuery.of(context).size.height / 2,
)
: Text("Image editor"),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
showDialog(
context: context,
builder: (BuildContext context) {
return AlertDialog(
title: new Text("Add Slip"),
content: Row(
children: <Widget>[
Expanded(
child: new FlatButton(
child: new Text("Camera"),
onPressed: () {
_getImage(1);
Navigator.pop(context);
},
),
),
Expanded(
child: new FlatButton(
child: new Text("Gallery"),
onPressed: () {
_getImage(2);
Navigator.pop(context);
},
),
)
],
),
);
},
);
},
tooltip: 'Pick Image',
child: Icon(Icons.camera),
),
);
}
}
Few of the fixes are these lines:
var image = await await ImagePicker.pickImage(
source: type == 1 ? ImageSource.camera : ImageSource.gallery,
);
It's having an error in the compiler so I've changed it to this:
var image = await await ImagePicker.platform.pickImage(
source: type == 1 ? ImageSource.camera : ImageSource.gallery,
);
Same to these lines:
Future<void> retrieveLostData() async {
final LostData response = await ImagePicker.retrieveLostData();
if (response == null) {
return;
}
if (response.file != null) {
setState(() {
if (response.type == RetrieveType.image) {
imageFile = response;
}
});
}
}
Fixed version:
Future<void> retrieveLostData() async {
final LostData response = await ImagePicker.platform.retrieveLostData();
if (response == null) {
return;
}
if (response.file != null) {
setState(() {
if (response.type == RetrieveType.image) {
imageFile = response.file as File;
}
});
}
}
and this
setState(() {
print("$image.path");
imageFile = image;
}
to this:
setState(() {
print("$image.path");
imageFile = File(image.path);
}
The reason could be the version of image_picker that I'm using. Currently I'm using the image_picker: ^0.7.4.
Here is actual output:
I've also encounter an issue if your running this in an Android API version 30, you get this error:
Unhandled Exception: PlatformException(no_available_camera, No cameras available for taking pictures., null, null)
The workaround is to add <uses-permission android:name="android.permission.QUERY_ALL_PACKAGES"/> in manifest as mentioned in this GitHub post.

Categories

Resources