I am just trying to save a user to my database. Following is my user model class
class User {
int _id;
String _userId;
String _mobileNumber;
User([this._userId, this._mobileNumber]);
User.withId(this._id, this._userId, this._mobileNumber);
int get id => _id;
String get userId => _userId;
String get mobileNumber => _mobileNumber;
set userId(String newUserId) {
this.userId = newUserId;
}
set mobileNumber(String newMobileNumber) {
this.mobileNumber = newMobileNumber;
}
Map<String, dynamic> toMap() {
var map = Map<String, dynamic>();
if (id != null) {
map["id"] = _id;
}
map["userId"] = _userId;
map["mobileNumber"] = _mobileNumber;
return map;
}
User.fromMapObject(Map<String, dynamic> map) {
this._id = map["id"];
this._mobileNumber = map["userId"];
this._userId = map["mobileNumber"];
}
}
Here is my repository class
class UserRepository {
static UserRepository _userRepository;
static Database _database;
String userTable = "user";
String colId = "id";
String colUserId = "userId";
String colMobileNumber = "mobileNumber";
String databaseName = "dice.db";
UserRepository._createInstance();
factory UserRepository() {
if (_userRepository == null) {
_userRepository = UserRepository._createInstance();
}
return _userRepository;
}
Future<Database> get database async {
if (_database == null) {
_database = await initializeDatabase();
}
return _database;
}
Future<Database> initializeDatabase() async {
Directory directory = await getApplicationDocumentsDirectory();
String path = directory.path + databaseName;
var userDatabase =
await openDatabase(path, version: 1, onCreate: _createDb);
return userDatabase;
}
void _createDb(Database db, int newversion) async {
await db.execute(
"CREATE TABLE $userTable($colId INTEGER PRIMARY KEY AUTOINCREMENT,$colUserId TEXT, $colMobileNumber TEXT)");
}
Future<List<Map<String, dynamic>>> getUserMapList() async {
Database db = await this.database;
return await db.query(userTable);
}
Future<int> insertUser(User user) async {
Database db = await this.database;
return await db.insert(userTable, user.toMap());
}
Future<int> updateNote(User user) async {
var db = await this.database;
return await db.update(userTable, user.toMap(),
where: "$colId = ?", whereArgs: [user.id]);
}
Future<List<User>> getUserList() async {
var userMapList = await getUserMapList();
List<User> userList = List<User>();
//We have only one user so i am only getting user at 0th position
userList.add(User.fromMapObject(userMapList[0]));
return userList;
}
}
var userRepository = UserRepository();
Now in my main class on button's click i am writing following code to save the user
User user = User();
user.mobileNumber = mobileData.data.mobile.toString();
user.userId = mobileData.data.userid.toString();
userRepository.insertUser(user).then((result) {
if (result != 0) {
print("Successfully saved to database");
} else {
print("Error saving to database");
}
});
Following is the error when i click the button
[ERROR:flutter/shell/common/shell.cc(184)] Dart Error: Unhandled exception:
E/flutter (23914): Stack Overflow
E/flutter (23914): #0 User.mobileNumber= (package:dice_clutter/repository/User.dart:20:3)
E/flutter (23914): #1 User.mobileNumber= (package:dice_clutter/repository/User.dart:21:10)
RootZone.runUnary (dart:async/zone.dart:1379:54)
E/flutter (23914): #19311 _FutureListener.handleValue (dart:async/future_impl.dart:129:18)
E/flutter (23914): #19312 Future._propagateToListeners.handleValueCallback (dart:async/future_impl.dart:642:45)
E/flutter (23914): #19313 Future._propagateToListeners (dart:async/future_impl.dart:671:32)
E/flutter (23914): #19314 Future._complete (dart:async/future_impl.dart:476:7)
E/flutter (23914): #19315 _SyncCompleter.complete (dart:async/future_impl.dart:51:12)
E/flutter (23914): #19316 _AsyncAwaitCompleter.complete (dart:async/runtime/libasync_patch.dart:28:18)
E/flutter (23914): #19317 _completeOnAsyncReturn (dart:async/runtime/libasync_patch.d
I am creating only one reference of my repository class.
Any help would be appreciated.
You have a stackoverflow because you are using the name of your setter
Change this:
set userId(String newUserId) {
this.userId = newUserId;
}
set mobileNumber(String newMobileNumber) {
this.mobileNumber = newMobileNumber;
}
To this:
set userId(String newUserId) {
_userId = newUserId;
}
set mobileNumber(String newMobileNumber) {
_mobileNumber = newMobileNumber;
}
Looks like the issue is caused by this setter:
set mobileNumber(String newMobileNumber) {
this.mobileNumber = newMobileNumber;
}
Setting this.mobileNumber will cause the setter to be run so calling inside a setter method will cause an infinite loop and a Stack Overflow exception.
To fix it, set the private variable:
set mobileNumber(String newMobileNumber) {
_mobileNumber = newMobileNumber;
}
You should do the same on your userId setter as this has the same problem.
Related
I´m having problems with sqflite in Flutter.
Normal inserts work just fine... but as soon as I insert a value, which is the id I get from inserting int into the first table, I get a syntax error near ")".
This is the error I get:
flutter: error DatabaseException(Error Domain=FMDatabase Code=1 "near
")": syntax error" UserInfo={NSLocalizedDescription=near ")": syntax
error}) sql 'CREATE TABLE pageM (id INTEGER PRIMARY KEY,caardId
INTEGER,title INTEGER,content TEXT,)' args []} during open, closing...
[VERBOSE-2:ui_dart_state.cc(157)] Unhandled Exception:
DatabaseException(Error Domain=FMDatabase Code=1 "near ")": syntax
error" UserInfo={NSLocalizedDescription=near ")": syntax error}) sql
'CREATE TABLE pageM (id INTEGER PRIMARY KEY,caardId INTEGER,title
INTEGER,content TEXT,)' args []}
#0 wrapDatabaseException (package:sqflite/src/exception_impl.dart:11:7)
#1 SqfliteDatabaseFactoryImpl.wrapDatabaseException (package:sqflite/src/factory_impl.dart:78:7)
#2 SqfliteDatabaseMixin.safeInvokeMethod (package:sqflite_common/src/database_mixin.dart:208:15)
#3 SqfliteDatabaseMixin.invokeExecute (package:sqflite_common/src/database_mixin.dart:370:12)
#4 SqfliteDatabaseMixin.txnExecute. (package:sqflite_common/src/database_mixin.dart:362:14)
#5 SqfliteDatabaseMixin.txnSynchronized (package:sqflite_common/src/database_mixin.dart:312:26)
#6 SqfliteDatabaseMixin.txnWriteSynchronized (package:sqflite_common/src/database_mixin.dart:345:<…>
Here my insert:
onPressed: () async {
currentCaard = Caard(topicId: widget.topicId, pageAmount: widget.pageAmount);
print(currentCaard);
currentCaard.id = await DatabaseProviderCaard.db.insert(currentCaard);
currentPage = PageM(caardId: currentCaard.id, title: textControllerTitle.text,content: textControllerContent.text);
DatabaseProviderPage.db.insert(currentPage);
},
and here is my whole db Provider file:
import 'package:caards/model.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:sqflite/sqlite_api.dart';
class DatabaseProviderCaard {
static const String TABLE_CAARD = "caard";
static const String COLUMN_ID = "id";
static const String COLUMN_TOPIC_ID = "topicId";
static const String COLUMN_PAGE_AMOUNT = "pageAmount";
DatabaseProviderCaard._();
static final DatabaseProviderCaard db = DatabaseProviderCaard._();
Database _database;
Future<Database> get database async {
print("caard database getter called");
if (_database != null) {
return _database;
}
_database = await createDatabase();
return _database;
}
Future<Database> createDatabase() async {
String dbPath = await getDatabasesPath();
return await openDatabase(
join(dbPath, 'caardDB.db'),
version: 1,
onCreate: (Database database, int version) async {
print("Creating caard table");
await database.execute(
"CREATE TABLE $TABLE_CAARD ("
"$COLUMN_ID INTEGER PRIMARY KEY,"
"$COLUMN_TOPIC_ID INTEGER,"
"$COLUMN_PAGE_AMOUNT INTEGER"
")",
);
},
);
}
Future<List<Caard>> getCaards() async {
final db = await database;
var caards = await db
.query(TABLE_CAARD, columns: [COLUMN_ID, COLUMN_TOPIC_ID, COLUMN_PAGE_AMOUNT]);
List<Caard> caardList = List<Caard>();
caards.forEach((currentCaard) {
Caard caard = Caard.fromMap(currentCaard);
caardList.add(caard);
});
return caardList;
}
Future<int> insert(Caard caard) async {
final db = await database;
caard.id = await db.insert(TABLE_CAARD, caard.toMap());
return caard.id;
}
Future<int> delete(int id) async {
final db = await database;
return await db.delete(
TABLE_CAARD,
where: "id = ?",
whereArgs: [id],
);
}
Future<int> update(Caard caard) async {
final db = await database;
return await db.update(
TABLE_CAARD,
caard.toMap(),
where: "id = ?",
whereArgs: [caard.id],
);
}
}
class DatabaseProviderPage {
static const String TABLE_PAGE = "page";
static const String COLUMN_ID = "id";
static const String COLUMN_CAARD_ID = "caardId";
static const String COLUMN_TITLE = "title";
static const String COLUMN_CONTENT = "content";
DatabaseProviderPage._();
static final DatabaseProviderPage db = DatabaseProviderPage._();
Database _database;
Future<Database> get database async {
print("page database getter called");
if (_database != null) {
return _database;
}
_database = await createDatabase();
return _database;
}
Future<Database> createDatabase() async {
String dbPath = await getDatabasesPath();
return await openDatabase(
join(dbPath, 'pageDB.db'),
version: 1,
onCreate: (Database database, int version) async {
print("Creating page table");
await database.execute(
"CREATE TABLE $TABLE_PAGE ("
"$COLUMN_ID INTEGER PRIMARY KEY,"
"$COLUMN_CAARD_ID INTEGER,"
"$COLUMN_TITLE INTEGER,"
"$COLUMN_CONTENT TEXT,"
")",
);
},
);
}
Future<List<PageM>> getPages() async {
final db = await database;
var pages = await db
.query(TABLE_PAGE, columns: [COLUMN_ID, COLUMN_CAARD_ID, COLUMN_TITLE, COLUMN_CONTENT]);
List<PageM> pageList = List<PageM>();
pages.forEach((currentPage) {
PageM page = PageM.fromMap(currentPage);
pageList.add(page);
});
return pageList;
}
Future<PageM> insert(PageM pageM) async {
final db = await database;
pageM.id = await db.insert(TABLE_PAGE, pageM.toMap());
return pageM;
}
Future<int> delete(int id) async {
final db = await database;
return await db.delete(
TABLE_PAGE,
where: "id = ?",
whereArgs: [id],
);
}
Future<int> update(PageM page) async {
final db = await database;
return await db.update(
TABLE_PAGE,
page.toMap(),
where: "id = ?",
whereArgs: [page.id],
);
}
}
and here is my Model:
import 'package:caards/database_provider.dart';
class Caard {
int id;
int topicId;
int pageAmount;
Caard({this.id, this.topicId, this.pageAmount});
Map<String, dynamic> toMap() {
var map = <String, dynamic>{
DatabaseProviderCaard.COLUMN_ID: id, //versuch
DatabaseProviderCaard.COLUMN_TOPIC_ID: topicId,
DatabaseProviderCaard.COLUMN_PAGE_AMOUNT: pageAmount
};
if (id != null) {
map[DatabaseProviderCaard.COLUMN_ID] = id;
}
return map;
}
Caard.fromMap(Map<String, dynamic> map) {
id = map[DatabaseProviderCaard.COLUMN_ID];
topicId = map[DatabaseProviderCaard.COLUMN_TOPIC_ID];
pageAmount = map[DatabaseProviderCaard.COLUMN_PAGE_AMOUNT];
}
}
class PageM {
int id;
int caardId;
String title;
String content;
PageM({this.id, this.caardId, this.title, this.content});
Map<String, dynamic> toMap() {
var map = <String, dynamic>{
DatabaseProviderPage.COLUMN_CAARD_ID: caardId,
DatabaseProviderPage.COLUMN_TITLE: title,
DatabaseProviderPage.COLUMN_CONTENT: content
};
if (id != null) {
map[DatabaseProviderPage.COLUMN_ID] = id;
}
return map;
}
PageM.fromMap(Map<String, dynamic> map) {
id = map[DatabaseProviderPage.COLUMN_ID];
caardId = map[DatabaseProviderPage.COLUMN_CAARD_ID];
title = map[DatabaseProviderPage.COLUMN_TITLE];
content = map[DatabaseProviderPage.COLUMN_CONTENT];
}
}
```
You need to syntactically correct the SQL query.
You currently use:
'CREATE TABLE pageM (id INTEGER PRIMARY KEY,caardId INTEGER,title INTEGER,content TEXT,)'
This query has an extra comma in the end, which is not syntactically correct. That is why the DB complains about a syntax error. In fact in the error message of the DB there is the query created using the code, inside which there is a trailing comma ',' before the parenthesis. Change your code so that the query is:
'CREATE TABLE pageM (id INTEGER PRIMARY KEY,caardId INTEGER,title INTEGER,content TEXT)'
You need to change the following part in the DB Provider file.
The error is caused because there is a comma after TEXT in the following part:
await database.execute(
"CREATE TABLE $TABLE_PAGE ("
"$COLUMN_ID INTEGER PRIMARY KEY,"
"$COLUMN_CAARD_ID INTEGER,"
"$COLUMN_TITLE INTEGER,"
"$COLUMN_CONTENT TEXT,"
")",
A correct version would be the following.
await database.execute(
"CREATE TABLE $TABLE_PAGE ("
"$COLUMN_ID INTEGER PRIMARY KEY,"
"$COLUMN_CAARD_ID INTEGER,"
"$COLUMN_TITLE INTEGER,"
"$COLUMN_CONTENT TEXT"
")",
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();
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 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
I am new in flutter application development. In my flutter application, I create a database using path provider plugin and SQFLite. But it is not working, it shows an exception message
type 'Future' is not a subtype of type 'Future'
I add my code here
static final DatabaseHelper _instance = new DatabaseHelper.internal();
factory DatabaseHelper() => _instance;
static Database _db;
Future<Database> get db async {
if (_db != null) {
return _db;
}
_db = await initDb();
return _db;
}
DatabaseHelper.internal();
initDb() async {
Directory documentDirectory = await getApplicationDocumentsDirectory();
String path = join(documentDirectory.path, "tododatabase.db");
var ourDb = await openDatabase(path, version: 1, onCreate: _onCreate);
return ourDb;
}
Future _onCreate(Database db, int version) async {
await db.execute(
"CREATE TABLE TodoList(id INTEGER PRIMARY KEY, todoText TEXT)");
// print("Table is created");
}
//insertion
Future<int> saveTodo(Todo todo) async {
var dbClient = await db;
int res = await dbClient.insert(" TodoList", todo.toMap());
return res;
}
please help me. give a suggestion, please. Thanks in advance.
0631/com.stunntech.fluttertodoapp E/flutter: [ERROR:topaz/lib/tonic/logging/dart_error.cc(16)] Unhandled exception:
type '(Database, int) => void' is not a subtype of type '(Database, int) => Future<dynamic>'
#0 DatabaseHelper.initDb (package:flutter_todo_app/database/database.dart:29:64)
<asynchronous suspension>
#1 DatabaseHelper.db (package:flutter_todo_app/database/database.dart:20:17)
<asynchronous suspension>
#2 DatabaseHelper.saveTodo (package:flutter_todo_app/database/database.dart:40:26)
<asynchronous suspension>
#3 _MyTodoListState._submitTodo (package:flutter_todo_app/todo_list.dart:144:30)
<asynchronous suspension>
#4 _MyTodoListState._showAlert.<anonymous closure> (package:flutter_todo_app/todo_list.dart:97:19)
#5 GestureRecognizer.invokeCallback (package:flutter/src/gestures/recognizer.dart:102:24)
#6 TapGestureRecognizer._checkUp (package:flutter/src/gestures/tap.dart:161:9)
#7 TapGestureRecognizer.handlePrimaryPointer (package:flutter/src/gestures/tap.dart:94:7)
#8 PrimaryPointerGestureRecognizer.handleEvent (package:flutter/src/gestures/recognizer.dart:315:9)
#9 PointerRouter._dispatch (package:flutter/src/gestures/pointer_router.dart:73:12)
#10 PointerRouter.route (package:flutter/src/gestures/pointer_router.dart:101:11)
#11 _WidgetsFlutterBinding&BindingBase&GestureBinding.handleEvent (package:flutter/src/gestures/binding.dart:143:19)
#12 _WidgetsFlutterBinding&BindingBase&GestureBinding.dispatchEvent (package:flutter/src/gestures/binding.dart:121:22)
#13 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerEvent (package:flutter/src/gestures/binding.dart:101:7)
#14 _WidgetsFlutterBinding&BindingBase&GestureBinding._flushPointerEventQueue (package:flutter/src/gestures/binding.dart:64:7)
#15 _WidgetsFlutterBinding&BindingBase&GestureBinding._handlePointerDataPacket (package:flutter/src/gestures/binding.dart:48:7)
#16 _invoke1 (dart:ui/hooks.dart:134:13)
#17 _dispatchPointerDataPacket (dart:ui/hooks.dart:91:5)enter code here
this is the log i get.
You need to have a Future that returns type database for your initDB() method:
Future<Database> initDB() async {
var databasesPath = await getDatabasesPath();
String path = join(databasesPath, "event.db");
var theDatabase = await openDatabase(path, version: 1, onCreate: _onCreate);
return theDatabase;
}
A complete example is here:
https://github.com/dazza5000/austin-feeds-me-flutter/blob/master/lib/data/event_database.dart
class EventsDatabase {
static const EVENT_TABLE_NAME = "event";
static final EventsDatabase _instance = EventsDatabase._internal();
factory EventsDatabase() => _instance;
static Database _db;
Future<Database> get db async {
if (_db != null) {
return _db;
}
_db = await initDB();
return _db;
}
EventsDatabase._internal();
Future<Database> initDB() async {
var databasesPath = await getDatabasesPath();
String path = join(databasesPath, "event.db");
var theDatabase = await openDatabase(path, version: 1, onCreate: _onCreate);
return theDatabase;
}
void _onCreate(Database db, int version) async {
await db.execute("CREATE TABLE " + EVENT_TABLE_NAME + " ("
"id STRING PRIMARY KEY, "
"name TEXT, "
"time INTEGER, "
"description TEXT, "
"url TEXT, "
"photo TEXT, "
"lat DOUBLE, "
"lng DOUBLE)");
}
Future closeDb() async {
var dbClient = await db;
return dbClient.close();
}
}
Your onCreate() function should be of type void (instead of Future) and should be async!