I am sending a request to an api with flutter and saving the response values in instance of one of my models. but i am getting some strange errors. you can see my code and errors that i am getting below. I am using scoped_model for state management.
import 'dart:convert';
import 'dart:async';
import 'dart:io';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:scoped_model/scoped_model.dart';
import 'package:http/http.dart' as http;
import 'package:rxdart/subjects.dart';
class Patient {
final String guid;
final String phone;
final String token;
final String name;
final String lastName;
Patient({#required this.guid, #required this.phone, #required this.token , #required this.name , #required this.lastName });
}
class RTN {
String msg = '';
String success = 'false';
String guid ='';
String srcPath ='';
String thumbPath ='';
dynamic obj ='';
RTN(
{#required this.msg,
#required this.guid,
#required this.obj,
#required this.srcPath,
#required this.success,
#required this.thumbPath});
}
class MainModel extends Model with Connected, PatientModel, UtilityModel {
}
mixin Connected on Model {
List<Doctor> _doctor = [];
Patient _authenticatedPatient;
bool _isLoading = false;
RTN _rtn;
RTN get rtn{
return _rtn;
}
List<Doctor> get allDrs {
return List.from(_doctor);
}
}
mixin PatientModel on Connected {
PublishSubject<bool> _patientSubject = PublishSubject();
Patient get patient {
return _authenticatedPatient;
}
PublishSubject<bool> get patientSubject {
return _patientSubject;
}
Future<Map<String, dynamic>> authenticateFirst(String phone) async {
try{
_isLoading = true;
notifyListeners();
final Map<String, dynamic> authFirstData = {
'Phone': phone,
};
http.Response response;
response = await http.post(
'http://guffy.ir/Auth/RegisterOne',
body: json.encode(authFirstData),
headers: {'Content-Type': 'application/json'},
);
final Map<String, dynamic> responseData = json.decode(response.body);
print(responseData);
bool hasError = true;
String message = '';
print(responseData);
if (responseData.containsKey("guid")) {
hasError = false;
rtn.msg = responseData["msg"];
rtn.guid = responseData["guid"];
rtn.obj = responseData["obj"];
rtn.srcPath = responseData["srcPath"];
rtn.success = responseData["success"];
rtn.thumbPath = responseData["thumbPath"];
message = rtn.msg;
_authenticatedPatient = Patient(
guid: responseData["guid"],
phone: phone,
token: null,
name: null,
lastName: null,
);
// _patientSubject.add(true);
final SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('token', '');
prefs.setString('patientPhone', phone);
prefs.setString('patientGuid', responseData['guid']);
prefs.setString('name', '');
prefs.setString('lastName', '');
}
_isLoading = false;
notifyListeners();
return {'success': !hasError, 'message': message};
}
catch(error){
_isLoading = false;
print(error);
}}
Future<Map<String, dynamic>> authenticateSecond(String phone) async {
_isLoading = true;
notifyListeners();
final Map<String, dynamic> authFirstData = {
'Phone': phone,
};
http.Response response;
response = await http.post(
'http://guffy.ir/Auth/RegisterOne',
body: json.encode(authFirstData),
headers: {'Content-Type': 'application/json'},
);
final Map<String, dynamic> responseData = json.decode(response.body);
print(responseData);
bool hasError = true;
String message = '';
print(responseData);
if (responseData.containsKey('guid')) {
hasError = false;
message = responseData['msg'];
_authenticatedPatient = Patient(
guid: responseData['guid'],
phone: phone,
token: null,
name: null,
lastName: null,
);
// _patientSubject.add(true);
final SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('token', null);
prefs.setString('patientPhone', phone);
prefs.setString('patientGuid', responseData['guid']);
prefs.setString('name', null);
prefs.setString('lastName', null);
}
_isLoading = false;
notifyListeners();
return {'success': !hasError, 'message': message};
}
Future<Map<String, dynamic>> authenticateThird(String phone) async {
_isLoading = true;
notifyListeners();
final Map<String, dynamic> authThirdData = {
'Phone': phone,
};
http.Response response;
response = await http.post(
'http://guffy.ir/Auth/RegisterOne',
body: json.encode(authThirdData),
headers: {'Content-Type': 'application/json'},
);
final Map<String, dynamic> responseData = json.decode(response.body);
print(responseData);
bool hasError = true;
String message = '';
print(responseData);
if (responseData.containsKey('guid')) {
hasError = false;
message = responseData['msg'];
_authenticatedPatient = Patient(
guid: responseData['guid'],
phone: phone,
token: null,
name: null,
lastName: null,
);
_patientSubject.add(true);
final SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.setString('token', null);
prefs.setString('patientPhone', phone);
prefs.setString('patientGuid', responseData['guid']);
prefs.setString('name', null);
prefs.setString('lastName', null);
}
_isLoading = false;
notifyListeners();
return {'success': !hasError, 'message': message};
}
void autoAuthenticate() async {
final SharedPreferences prefs = await SharedPreferences.getInstance();
final String name = prefs.getString('name');
final String lastName = prefs.getString('lastName');
if (name != '' && lastName != '') {
final String patientPhone = prefs.getString('patientPhone');
final String patientGuid = prefs.getString('patientGuid');
final String token = prefs.getString('token');
_authenticatedPatient =
Patient(guid: patientGuid, phone: patientPhone, token: token , name: name , lastName: lastName);
_patientSubject.add(true);
notifyListeners();
}
}
void logout() async {
_authenticatedPatient = null;
_patientSubject.add(false);
final SharedPreferences prefs = await SharedPreferences.getInstance();
prefs.remove('token');
prefs.remove('PatientEmail');
prefs.remove('PatientId');
}
}
mixin UtilityModel on Connected {
bool get isLoading {
return _isLoading;
}
}
this is the response that i am getting from the api:
{msg: کد ارسال شد, success: true, guid: 15dde915-d752-4bf1-90ad-49872868af35, srcPath: null, thumbPath: null, obj: null}
this is the error that i am getting:
I/flutter (10151): NoSuchMethodError: The setter 'msg=' was called on null.
I/flutter (10151): Receiver: null
I/flutter (10151): Tried calling: msg="کد ارسال شد"
E/flutter (10151): [ERROR:flutter/shell/common/shell.cc(184)] Dart Error: Unhandled exception:
E/flutter (10151): NoSuchMethodError: The method '[]' was called on null.
E/flutter (10151): Receiver: null
E/flutter (10151): Tried calling: []("success")
E/flutter (10151): #0 Object.noSuchMethod (dart:core/runtime/libobject_patch.dart:50:5)
E/flutter (10151): #1 _AuthOnePageState._submitForm (package:restt/pages/authone.dart:93:27)
E/flutter (10151): <asynchronous suspension>
The error is saying that you tried to access the field msg on a null object, which likely is this line:
rtn.msg = responseData["msg"];
You just need to instantiate the object before using it:
RTN _rtx;
RTN get rtn {
if (_rtn == null) {
_rtx = RTN(); // Instantiate the object if its null.
}
return _rtn;
}
Initializing the class is enough
RTN _rtx = RTN();
Related
Currently I'm learning Flutter and I have an error during the execution of a project that I can't find. Maybe someone has an idea where the error could be?
This is the error:
[VERBOSE-2:ui_dart_state.cc(157)] Unhandled Exception: type 'String' is not a subtype of type 'int' of 'index'
This is the function in which the error is located:
Future<void> fetchAndSetProducts([bool filterByUser = false]) async {
final filterString = filterByUser ? 'orderBy="creatorId"&equalTo="$userId"' : '';
var url =
'https://xxxx.firebaseio.com/products.json?auth=$authToken&$filterString';
try {
final response = await http.get(url);
final extractedData = json.decode(response.body) as Map<String, dynamic>;
if (extractedData == null) {
return;
}
url =
'https://xxxx.firebaseio.com/userFavorites/$userId.json?auth=$authToken';
final favoriteResponse = await http.get(url);
final favoriteData = json.decode(favoriteResponse.body);
final List<Product> loadedProducts = [];
extractedData.forEach((prodId, prodData) {
loadedProducts.add(Product(
id: prodId,
title: prodData['title'],
description: prodData['description'],
price: prodData['price'],
isFavorite:
favoriteData == null ? false : favoriteData[prodId] ?? false,
imageUrl: prodData['imageUrl'],
));
});
_items = loadedProducts;
notifyListeners();
} catch (error) {
throw (error);
}
}
I want to fetch data from the server, then parse json. When they are done, I want to navigate to another view.
void getServerData() async{
WebRequests ws = WebRequests('https://sampleurl');
Map<String, dynamic> map = await ws.getData();
mychamplist = map['mychampionships'];
mychamplist.forEach((f){
mychampionships.add(MyChampionships(
name: f['name'],
id: int.parse(f['id']),
numberOfPlayers: int.parse(f['nofplayers']),
));
});
Navigator
.of(context)
.pushReplacement(new MaterialPageRoute(builder: (BuildContext context) {
return FantasyNbi();
}));
}
It navigates to the FantasyNbi class before the previous code finished.
How could it do in proper way?
I do have a example class for you that you could use:
class API {
static Future getData(String url) {
return http.get('api link' + url);
}
static Future<List<BasicDiskInfo>> fetchAllDisks() async {
final response = await getData('disk');
if (response.statusCode == 200) {
Iterable list = json.decode(response.body);
List<BasicDiskInfo> disks =
list.map((model) => BasicDiskInfo.fromJson(model)).toList();
return disks;
} else {
throw Exception('Failed to load disks');
}
}
static Future<Disk> fetchDisk(int id) async {
final response = await getData('disk/' + id.toString());
if (response.statusCode == 200) {
return Disk.fromJson(json.decode(response.body));
} else {
throw Exception('Failed to load disk');
}
}
}
class Disk {
int id;
String name;
String volumeLable;
bool isReady;
String driveType;
String driveFormat;
int totalSize;
int totalFreeSpace;
int availableFreeSpace;
Disk(
{this.id,
this.name,
this.volumeLable,
this.isReady,
this.driveType,
this.driveFormat,
this.totalSize,
this.totalFreeSpace,
this.availableFreeSpace});
factory Disk.fromJson(Map<String, dynamic> json) {
return Disk(
id: json['id'],
name: json['name'],
volumeLable: json['volumeLable'],
isReady: json['isReady'],
driveType: json['driveType'],
driveFormat: json['driveFormat'],
totalSize: json['totalSize'],
totalFreeSpace: json['totalFreeSpace'],
availableFreeSpace: json['availableFreeSpace']);
}
}
And to get the data I can do this:
var data = await API.fetchAllDisks();
// or
API.fetchAllDisks().then((response) => {/* do something */})
I am trying to fetch some data from the internet, store it to my sqlite database and display it on the screen using a ListView.
When I fetch the data for the first time everything works fine and I am able to see the data on the screen, the data is also inserted in the sqlite database, but when I reopen the app I get an error saying
flutter: The following NoSuchMethodError was thrown building StreamBuilder<StudentModel>(dirty, state:
flutter: _StreamBuilderBaseState<StudentModel, AsyncSnapshot<StudentModel>>#3f888):
flutter: The getter 'studentData' was called on null.
flutter: Receiver: null
flutter: Tried calling: studentData
Here is my model class
class StudentModel {
int status;
String msg;
StudentModelData studentModelData;
StudentModel({this.status, this.msg, this.studentModelData});
StudentModel.fromJson(Map<String, dynamic> json) {
status = json['status'];
msg = json['msg'];
studentModelData = json['data'] != null ? new StudentModelData.fromJson(json['data']) : null;
}
StudentModel.fromDb(Map<String, dynamic> parsedJson) {
status = parsedJson['status'];
msg = parsedJson['msg'];
studentModelData = parsedJson['data'] != null ? new StudentModelData.fromJson(parsedJson['data']) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['status'] = this.status;
data['msg'] = this.msg;
if (this.studentModelData != null) {
data['data'] = this.studentModelData.toJson();
}
return data;
}
}
class StudentModelData {
int lastIndex;
List<StudentData> studentData;
StudentModelData({this.lastIndex, this.studentData});
StudentModelData.fromJson(Map<String, dynamic> json) {
lastIndex = json['lastIndex'];
if (json['studentData'] != null) {
studentData = new List<StudentData>();
json['studentData'].forEach((v) {
studentData.add(new StudentData.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['lastIndex'] = this.lastIndex;
if (this.studentData != null) {
data['studentData'] = this.studentData.map((v) => v.toJson()).toList();
}
return data;
}
}
class StudentData {
String studentId;
String studName;
String studProfilepic;
String studentEmail;
String studentMobile;
String courseName;
String classCode;
int minAvg;
int avg;
StudentData(
{this.studentId,
this.studName,
this.studProfilepic,
this.studentEmail,
this.studentMobile,
this.courseName,
this.classCode,
this.minAvg,
this.avg});
StudentData.fromJson(Map<String, dynamic> json) {
studentId = json['student_id'];
studName = json['stud_name'];
studProfilepic = json['stud_profilepic'];
studentEmail = json['student_email'];
studentMobile = json['student_mobile'];
courseName = json['course_name'];
classCode = json['class_code'];
minAvg = json['minAvg'];
avg = json['avg'];
}
StudentData.fromDb(Map<String, dynamic> parsedJson){
studentId = parsedJson['student_id'];
studName = parsedJson['stud_name'];
studProfilepic = parsedJson['stud_profilepic'];
studentEmail = parsedJson['student_email'];
studentMobile = parsedJson['student_mobile'];
courseName = parsedJson['course_name'];
classCode = parsedJson['class_code'];
minAvg = parsedJson['minAvg'];
avg = parsedJson['avg'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['student_id'] = this.studentId;
data['stud_name'] = this.studName;
data['stud_profilepic'] = this.studProfilepic;
data['student_email'] = this.studentEmail;
data['student_mobile'] = this.studentMobile;
data['course_name'] = this.courseName;
data['class_code'] = this.classCode;
data['minAvg'] = this.minAvg;
data['avg'] = this.avg;
return data;
}
}
Following is my repository class
class StudentDbProvider implements Source, Cache {
Database db;
void init() async {
print("database initialized");
Directory documentsDirectory = await getApplicationDocumentsDirectory();
final path = join(documentsDirectory.path, "students.db");
db = await openDatabase(path, version: 1,
onCreate: (Database newDb, int version) {
newDb.execute("""
CREATE TABLE STUDENTS(
id INTEGER PRIMARY KEY,
student_id TEXT,
stud_name TEXT,
stud_profilepic TEXT,
student_email TEXT,
student_mobile TEXT,
course_name TEXT,
class_code TEXT,
minAvg TEXT,
avg TEXT
)
""");
});
}
#override
Future<int> clear() {
return db.delete("STUDENTS");
}
#override
Future<StudentModel> fetchStudents(String disciplineId, String schoolId,
String year_id, String lastIndex) async {
print("PritishSawant${db==null}");
final maps =
await db.query("STUDENTS");
if (maps.length > 0) {
return StudentModel.fromDb(maps.first);
}
return null;
}
#override
Future<int> addStudent(StudentData studentData) {
return db.insert("STUDENTS", studentData.toJson(),
conflictAlgorithm: ConflictAlgorithm.ignore);
}
}
final studentDbProvider = StudentDbProvider();
Following is my bloc class
class StudentsBloc {
final _repository = Repository();
final _students = PublishSubject<StudentModel>();
Observable<StudentModel> get students => _students.stream;
fetchStudents(String disciplineId,String schoolId,String year_id,String lastIndex) async {
await studentDbProvider.init();
final student = await _repository.fetchStudents(disciplineId, schoolId, year_id, lastIndex);
_students.sink.add(student);
}
clearCache(){
return _repository.clearCache();
}
dispose(){
_students.close();
}
}
As far as I can understand the error must be occurring due to improper database initialisation but when I did the first network request everything was working fine and I did not get any error in the console and the database was also initialised. I am not able to understand why the error is occurring for the second time onwards?
I suppose you are calling snapshot.data.studentData in some part of your code.
On a stream builder, I tend to first do a null check
if (snapshot.data != null) {
// your code here
}
And then proceed to verify the data, else you can use a getter on a null data provided by the StreamBuilder
You should check snapshot!=null && snapshot.hasError to ensure your data is actually returned
if (snapshot!=null && !snapshot.hasError) {
// your code here
}
I have API.dart like this to authenticating a user, log in and log out
class Api {
static FirebaseAuth _auth = FirebaseAuth.instance;
static GoogleSignIn _googleSignIn = GoogleSignIn();
FirebaseUser firebaseUser;
Api(FirebaseUser user) {
this.firebaseUser = user;
}
static Future<FBApi> signInWithGoogle() async {
final GoogleSignInAccount googleUser = await _googleSignIn.signIn();
final GoogleSignInAuthentication googleAuth = await googleUser.authentication;
final FirebaseUser user = await _auth.signInWithGoogle(
accessToken: googleAuth.accessToken,
idToken: googleAuth.idToken,
);
assert(user.email != null);
assert(user.displayName != null);
assert(await user.getIdToken() != null);
final FirebaseUser currentUser = await _auth.currentUser();
assert(user.uid == currentUser.uid);
// print('photoURL api ' + user.photoUrl);
return Api(user);
}
static Future<void> signOut() async {
await _auth.signOut().then((_) {
print("***** log out...what the hell?");
_googleSignIn.signOut();
});
}
}
I've have a cloud function to create new user to database cloud firestore.
And in view account settings, I want to update user information like displayName, photoUrl into firestore. How I get current user in my account setting view.
class Settings extends StatelessWidget {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text(
'ACCOUNT',
style: TextStyle(color: primaryColor, fontWeight: FontWeight.bold),
),
centerTitle: true,
),
body: new SettingsScreen(),
);
}
}
class SettingsScreen extends StatefulWidget {
#override
State createState() => new SettingsScreenState();
}
class SettingsScreenState extends State<SettingsScreen> {
TextEditingController controllerNickname;
SharedPreferences prefs;
String id;
String nickName;
String photoUrl;
bool isLoading = false;
File avatarImageFile;
final FocusNode focusNodeNickname = new FocusNode();
#override
void initState() {
super.initState();
readLocal();
}
void readLocal() async {
prefs = await SharedPreferences.getInstance();
id = prefs.getString('id') ?? '';
nickName = prefs.getString('nickName') ?? '';
photoUrl = prefs.getString('photoUrl') ?? '';
controllerNickname = new TextEditingController(text: nickName);
// Force refresh input
setState(() {});
}
Future getImage() async {
File image = await ImagePicker.pickImage(source: ImageSource.gallery);
if (image != null) {
setState(() {
avatarImageFile = image;
isLoading = true;
});
}
uploadFile();
}
Future uploadFile() async {
String fileName = id;
StorageReference reference = FirebaseStorage.instance.ref().child(fileName);
StorageUploadTask uploadTask = reference.putFile(avatarImageFile);
StorageTaskSnapshot storageTaskSnapshot;
uploadTask.onComplete.then((value) {
if (value.error == null) {
storageTaskSnapshot = value;
storageTaskSnapshot.ref.getDownloadURL().then((downloadUrl) {
photoUrl = downloadUrl;
Firestore.instance
.collection('users')
.document(id)
.updateData({'displayName': nickName, 'photoUrl': photoUrl}).then((data) async {
await prefs.setString('photoUrl', photoUrl);
setState(() {
isLoading = false;
});
Fluttertoast.showToast(msg: "Upload success");
}).catchError((err) {
setState(() {
isLoading = false;
});
Fluttertoast.showToast(msg: err.toString());
});
}, onError: (err) {
setState(() {
isLoading = false;
});
Fluttertoast.showToast(msg: 'This file is not an image');
});
} else {
setState(() {
isLoading = false;
});
Fluttertoast.showToast(msg: 'This file is not an image');
}
}, onError: (err) {
setState(() {
isLoading = false;
});
Fluttertoast.showToast(msg: err.toString());
});
}
void handleUpdateData() {
focusNodeNickname.unfocus();
setState(() {
isLoading = true;
});
Firestore.instance
.collection('users')
.document(id)
.updateData({'displayName': nickName, 'photoUrl': photoUrl}).then((data) async {
await prefs.setString('nickname', nickName);
await prefs.setString('photoUrl', photoUrl);
setState(() {
isLoading = false;
});
Fluttertoast.showToast(msg: "Update success");
}).catchError((err) {
setState(() {
isLoading = false;
});
Fluttertoast.showToast(msg: err.toString());
});
}
#override
Widget build(BuildContext context) {
...
You can do something like this FirebaseAuth.instance.currentUser()
This returns the current user if any. Otherwise it returns null
I am trying to fetch some data from network and store it in sqlite database. Following is the model class
class StudentModel {
int status;
String msg;
StudentModelData studentModelData;
StudentModel({this.status, this.msg, this.studentModelData});
StudentModel.fromJson(Map<String, dynamic> json) {
status = json['status'];
msg = json['msg'];
studentModelData = json['data'] != null ? new StudentModelData.fromJson(json['data']) : null;
}
StudentModel.fromDb(Map<String, dynamic> parsedJson) {
status = parsedJson['status'];
msg = parsedJson['msg'];
studentModelData = studentModelData = jsonDecode(json['data']) != null ? new StudentModelData.fromJson(jsonDecode(json['data'])) : null;
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['status'] = this.status;
data['msg'] = this.msg;
if (this.studentModelData != null) {
data['data'] = this.studentModelData.toJson();
}
return data;
}
}
class StudentModelData {
int lastIndex;
List<StudentData> studentData;
StudentModelData({this.lastIndex, this.studentData});
StudentModelData.fromJson(Map<String, dynamic> json) {
lastIndex = json['lastIndex'];
if (json['studentData'] != null) {
studentData = new List<StudentData>();
json['studentData'].forEach((v) {
studentData.add(new StudentData.fromJson(v));
});
}
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['lastIndex'] = this.lastIndex;
if (this.studentData != null) {
data['studentData'] = this.studentData.map((v) => v.toJson()).toList();
}
return data;
}
}
class StudentData {
String studentId;
String studName;
String studProfilepic;
String studentEmail;
String studentMobile;
String courseName;
String classCode;
int minAvg;
int avg;
StudentData(
{this.studentId,
this.studName,
this.studProfilepic,
this.studentEmail,
this.studentMobile,
this.courseName,
this.classCode,
this.minAvg,
this.avg});
StudentData.fromJson(Map<String, dynamic> json) {
studentId = json['student_id'];
studName = json['stud_name'];
studProfilepic = json['stud_profilepic'];
studentEmail = json['student_email'];
studentMobile = json['student_mobile'];
courseName = json['course_name'];
classCode = json['class_code'];
minAvg = json['minAvg'];
avg = json['avg'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = new Map<String, dynamic>();
data['student_id'] = this.studentId;
data['stud_name'] = this.studName;
data['stud_profilepic'] = this.studProfilepic;
data['student_email'] = this.studentEmail;
data['student_mobile'] = this.studentMobile;
data['course_name'] = this.courseName;
data['class_code'] = this.classCode;
data['minAvg'] = this.minAvg;
data['avg'] = this.avg;
return data;
}
}
And my database provider class looks like following
class StudentDbProvider implements Source, Cache {
Database db;
StudentDbProvider() {
init();
}
void init() async {
Directory documentsDirectory = await getApplicationDocumentsDirectory();
final path = join(documentsDirectory.path, "students.db");
db = await openDatabase(path, version: 1,
onCreate: (Database newDb, int version) {
newDb.execute("""
CREATE TABLE STUDENTS(
id INTEGER PRIMARY KEY,
status INTEGER,
msg TEXT,
data BLOB
)
""");
});
}
#override
Future<int> clear() {
return db.delete("STUDENTS");
}
#override
Future<StudentModel> fetchStudents(String disciplineId, String schoolId,
String year_id, String lastIndex) async {
final maps =
await db.query("STUDENTS");
if (maps.length > 0) {
return StudentModel.fromDb(maps.first);
}
return null;
}
#override
Future<int> addStudent(StudentModel studentModel) {
return db.insert("STUDENTS", studentModel.toJson(),conflictAlgorithm: ConflictAlgorithm.ignore);
}
}
final studentDbProvider = StudentDbProvider();
Whenever I tried to fetch the data and stored in the database, I get the following error in the console
NoSuchMethodError: The method 'query' was called on null.
Receiver: null
Tried calling: query("STUDENTS")
#0 Object.noSuchMethod (dart:core/runtime/libobject_patch.dart:50:5)
The data gets added to the database but I am not able to query the data from the database.
Reducing at minimum your example, this throws the exception The method 'query' was called on null
because fetch is executed before db is properly initialized:
class Database {
Future<int> query() {
return Future.value(1);
}
}
const oneSecond = Duration(seconds: 1);
class Provider {
Database db;
Provider() {
init();
}
void init() async {
db = await Future.delayed(oneSecond, () => Database());
}
Future<int> fetch() {
return db.query();
}
}
main() async {
var provider = Provider();
await provider.fetch();
}
The problem resides in calling an async method inside a constructor, see also:
Calling an async method from component constructor in Dart
This works:
class Database {
Future<int> query() {
return Future.value(1);
}
}
const oneSecond = Duration(seconds: 1);
class Provider {
Database db;
Provider() {
//init();
}
void init() async {
db = await Future.delayed(oneSecond, () => Database());
}
Future<int> fetch() {
return db.query();
}
}
main() async {
var provider = Provider();
await provider.init();
await provider.fetch();
}
Please note that init must be awaited, otherwise you will catch the same The method 'query' was called on null.
the problem is the init must be awaited. here what I did to fix it
_onCreate(Database db, int version) async {
await db.execute('CREATE TABLE ... <YOUR QUERY CREATION GOES HERE>');
}
Future<Database> getDatabaseInstance() async {
final String databasesPath = await getDatabasesPath();
final String path = join(databasesPath, '<YOUR DB NAME>');
return await openDatabase(path, version: 1, onCreate: _onCreate);
}
Future<int> save(Contact contact) {
return getDatabaseInstance().then((db) {
final Map<String, dynamic> contactMap = Map();
contactMap['name'] = contact.name;
contactMap['account_number'] = contact.accountNumber;
return db.insert('contacts', contactMap);
});
}
The SQFlite page gives a good example about it and helps a lot.
https://github.com/tekartik/sqflite/blob/master/sqflite/doc/opening_db.md