late initialization error field _id has not been initialized - flutter

Hello guys in tis application when i add delete or update student in emulator it says late initialization error field _id has not been initialized this is because it wrote in student.dart late int _id; i don't want to make a value for _id in order to be able to add a new value
class Student {
late int _id ;
late String _name;
late String _description;
late int _pass;
late String _date;
Student(this._name, this._description, this._pass, this._date);
Student.withId(
this._id, this._name, this._description, this._pass, this._date);
String get date => _date;
int get pass => _pass;
String get description => _description;
String get name => _name;
int get id => _id;
set date(String value) {
_date = value;
}
set pass(int value) {
if (value >= 1 && value <= 2) {
_pass = value;
}
}
set description(String value) {
if (value.length <= 255) {
_description = value;
}
}
set name(String value) {
if (value.length <= 255) {
_name = value;
}
}
Map<String, dynamic> toMap() {
var map = Map<String, dynamic>();
map["id"] = this._id;
map["name"] = this._name;
map["description"] = this._description;
map["pass"] = this._pass;
map["date"] = this._date;
return map;
}
Student.getMap(Map<String, dynamic> map) {
this._id = map["id"];
this._name = map["name"];
this._description = map["description"];
this._pass = map["pass"];
this._date = map["date"];
}
}
when i write late int _id ; it says late initialization error this is the entire code https://github.com/abdelrahman992-cpu/studentfinal

You need to be careful when marking a variable as being late. You must instantiate the variable with a value before you ever access it. In your case, the default constructor for Student doesn't instantiate _id with a value, so anywhere in your code afterward that tries to access _id is going to throw this error.
You can either give _id a default value to ensure it is instantiated:
Student(this._name, this._description, this._pass, this._date)
: _id = -1;
Student.withId(this._id, this._name, this._description, this._pass, this._date);
Or mark it as nullable:
int? _id;
late String _name;
late String _description;
late int _pass;
late String _date;
Having said all this, there is no reason for your fields to be marked as late. That keyword is reserved for situations where your fields cannot be logically made nullable but their values won't exist until some time after the object has been created.
For example, if the instance represents some data that exists in some asynchronous source:
class RemoteData {
final String name;
late final List<String> rows;
RemoteData(this.name);
// Must call fetch before using any instance of this class
Future<void> fetch() async {
rows = await SomeRemoteDataSource.getRows();
}
}
...
final data = RemoteData('foo');
// fetch hasn't been called on data so it's in a dangerous error-prone state
// print(data.rows); // Uncommenting this line will result in an error
await SomeRemoteDataSource.initialize();
await data.fetch();
// Now it's safe to use data because rows has been initialized
print(data.rows);
In general, the use of late is discouraged for the following reasons:
You almost never actually need it.
When you think you do need it, it's usually better to refactor your code so you don't need it anymore.
The reason is that Dart expects all non-nullable fields of a class to have a value by the time the constructor is finished. The late keyword disables that behavior for a field, allowing the class to be created without the field having a value. But there's a catch - if the field doesn't have a value by the time it's accessed for the first time, Dart will throw an error. This is an example of a race condition, and it should be avoided at all costs since you can easily shoot yourself in the foot even if you think you know what you're doing.
For example, if you created RemoteData and then tried to access rows without first calling fetch, the code would throw an error. And even sneakier, there's no guarantee that even fetch would properly instantiate rows, either. (What if the call to SomeRemoteDataSource.getRows() never completes or throws an error?) So the RemoteData class would be better off being refactored so that the call to SomeRemoteDataSource.getRows() happened before the object was created, and then the rows passed in along with the name to the constructor itself.
In your case, all of the fields are being instantiated in the constructor as is normal for a class's fields, so there's no reason whatsoever for the fields to be marked as late. As such, get rid of late since it can only cause harm to your code to leave it in.

Related

Flutter Login With Database SQLite

I a creating a Login page with SQLite, but in the file UserModel in directory lib/models, there is this error:
This is the code:
class UserModel {
String _name;
String _email;
String _password;
UserModel(this._name, this._email, this._password);
//Receiving data from server
UserModel.fromMap(dynamic obj) {
this._name = obj['name'];
this._email = obj['email'];
this._password = obj['password'];
}
String get name => _name;
String get username => _email;
String get password => _password;
Map<String, dynamic> toMap() {
var map = new Map<String, dynamic>();
map["name"] = _name;
map["username"] = _email;
map["password"] = _password;
return map;
}
}
Try to store the result in a variable:
final result = Usermodel.fromMap('whatever you are sending');
Otherwise, I need to see what you are doing behind the help box.
Because the 3 fields _name, _email and _password are of type String, an non-nullable type, they always need to have a value. At least before the code from the body of the constructor is executed.
There are different ways to solve this, depending on our needs:
Method 1: provide a default value for the variables
String _name = '';
Method 2: Make the variable nullable
String? _name;
Method 3: Mark the variable as late
late String _name;
Method 4: This is probably the nicest solution. Initialize the variable before the body of the constructor:
UserModel.fromMap(dynamic obj) : _name = obj['name']{
}
You can do this for multiple variables:
UserModel.fromMap(dynamic obj) : _name = obj['name'], _email = obj['email']
{
}

error MissingpluginException(No implementation found for method getApplicationDocementsDirectory on channel plugins.flutter.io/path_provider)

Hello guys this program consists of two pages named student list and studentdetail it don't make any error in the analyzer but in emulator when I open the first page that display list of students and tap on any student and go to the student detail and wanting to delete , update or goback to the fist page it says MissingpluginException(No implementation found for method getApplicationDocementsDirectory on channel plugins.flutter.io/path_provider in console and I can't delete or add student and in student page
class Student {
late int _id ;
late String _name;
late String _description;
late int _pass;
late String _date;
Student(this._name, this._description, this._pass, this._date);
Student.withId(
this._id, this._name, this._description, this._pass, this._date);
String get date => _date;
int get pass => _pass;
String get description => _description;
String get name => _name;
int get id => _id;
set date(String value) {
_date = value;
}
set pass(int value) {
if (value >= 1 && value <= 2) {
_pass = value;
}
}
set description(String value) {
if (value.length <= 255) {
_description = value;
}
}
set name(String value) {
if (value.length <= 255) {
_name = value;
}
}
Map<String, dynamic> toMap() {
var map = Map<String, dynamic>();
map["id"] = this._id;
map["name"] = this._name;
map["description"] = this._description;
map["pass"] = this._pass;
map["date"] = this._date;
return map;
}
Student.getMap(Map<String, dynamic> map) {
this._id = map["id"];
this._name = map["name"];
this._description = map["description"];
this._pass = map["pass"];
this._date = map["date"];
}
}
when i write late int _id ; it says late initialization error after field _id hasn't been initialized after add or delete student
this is the entire code
https://github.com/abdelrahman992-cpu/studentfinal
run these commands in terminals hope this will help you
>> flutter clean
>> flutter pub get
if this didn't worked try stopping and restarting the app. let me know if this help you or not.

Singleton Class in Flutter with NullSafety

I have this class which takes some parameters by using the factory constructor, if instance is null, a new object will be created; if it's not null, the value of instance will be returned so we always receive the same object all the time (Singleton). This is how I used the singleton pattern before enabling null-safety features of dart.
class GuestUser extends User {
static GeustUser _instance;
factory GuestUser(
{required String firstName,
required String lastName,
required String email,
required Address address,
required PaymentInfo paymentInfo}) {
if (_instance == null) {
_instance =
GuestUser._(firstName, lastName, email, address, paymentInfo);
}
return _instance;
}
Now with null-safety enabled, I get this error:
The non-nullable variable '_instance' must be initialized.
Try adding an initializer expression.
Also if (_instance == null) is not needed anymore.
If I define the _instance like this: static late final GuestUser _instance; then I cannot use the if (_instance == null) to only create the _instance when needed. so I have to remove the if statement and create a new instance every time the factory constructor is called.
How can I solve this issue and create a singleton class with null-safety enabled?
I have this solution in mind to keep track of the instance with a boolean variable:
static late final GeustUser _instance;
static bool _isInstanceCreated = false;
factory GuestUser(
{required String firstName,
required String lastName,
required String email,
required Address address,
required PaymentInfo paymentInfo}) {
if (_isInstanceCreated == false) {
_instance =
GuestUser._(firstName, lastName, email, address, paymentInfo);
}
_isInsanceCreated = true;
return _instance;
}
But I want to know whether there is a way to do this without defining new variable and by using the features of the null-safety
Your singleton is a little strange since your are taking arguments which will only be used the first time it is called. It is not a great pattern since it can give some surprises if e.g. your want to use it for two different guest users.
In your example it makes sense to just use GuestUser? as the type for _instance. Non-nullable by default in Dart should not be seen as the use of null is bad and you should definitely use null where it makes sense (especially if we can prevent the introduction of bool variables to indicate if a variable has been set). In your example, _instance is null until it is initialized the first time.
Example where we use the ??= operator. The operator will check if _instance is null and in case of null, it will assign the variable to the object created by calling the constructor GuestUser._. It will hereafter return the value of _instance. If _instance does already have a value (not null), this value will just be returned without calling the GuestUser._ constructor.
class GuestUser extends User {
static GuestUser? _instance;
factory GuestUser(
{required String firstName,
required String lastName,
required String email,
required Address address,
required PaymentInfo paymentInfo}) =>
_instance ??=
GuestUser._(firstName, lastName, email, address, paymentInfo);
}
If you had a more traditional singleton, you could have made a static final variable where the instance is created in the definition. But this does not allow for parameters.
You can use the same traditional way to create a singleton. You only have to put the null-safety operator in the right place.
class MySingleton {
// make this nullable by adding '?'
static MySingleton? _instance;
MySingleton._() {
// initialization and stuff
}
factory MySingleton() {
if (_instance == null) {
_instance = new MySingleton._();
}
// since you are sure you will return non-null value, add '!' operator
return _instance!;
}
}
As #julemand101 mentioned, your singleton is actually strange, because generally you'd do something like:
class Foo {
static final instance = Foo._();
Foo._();
}
However, you can't instantiate it with the parameters. For that you can do this:
class Bar {
static Bar? instance;
Bar._(int i);
factory Bar.fromInt(int i) {
var bar = Bar._(i);
instance = bar;
return bar;
}
void display() => print('Bar instance');
}
void main() {
final nullableBar = Bar.instance;
final nonNullableBar = Bar.fromInt(0);
nullableBar!.display(); // Runtime error as Bar.instance is used before Bar.fromMap(0)
nonNullableBar.display(); // No error
}
What you are getting as it is part of Lazy Initialization, with this approach we create an instance at runtime, not at the time of initialization.
Lastly, your problem will be solved using the null aware operator, and better use factory constructor for initialization of an object.
class GuestUser {
static GuestUser? _instance;
GuestUser._(
String firstName,
String lastName,
String email,
String address,
String paymentInfo);
factory GuestUser(
{required String firstName,
required String lastName,
required String email,
required String address,
required String paymentInfo}) {
_instance ??=
GuestUser._(firstName, lastName, email, address, paymentInfo);
return _instance!;
}
///.. Rest code
}
Create object like
GuestUser user = GuestUser(firstName: "jitesh", lastName: "mohite", email: "jitesh#gmail.com", address: "Universe", paymentInfo: "As you like");

Acessing data from instance of a class

I have a question, I started learning dart/flutter, and when passing data from one screen to another I access the data like this
final orderData = ModalRoute.of(context).settings.arguments;
OrderData class looks like this
class OrderItem {
final String id;
final String name;
final String date;
final String address;
final String recordNumber;
OrderItem({
#required this.id,
#required this.name,
#required this.date,
#required this.address,
#required this.recordNumber,
});
Map<String, dynamic> toMap() {
return {
'id': id,
'name': name,
'date': date,
'address': address,
'recordNumber': recordNumber,
};
}
factory OrderItem.fromMap(Map<String, dynamic> map) {
if (map == null) return null;
return OrderItem(
id: map['id'],
name: map['name'],
date: map['date'],
address: map['address'],
recordNumber: map['recordNumber'],
);
}
String toJson() => json.encode(toMap());
factory OrderItem.fromJson(String source) => OrderItem.fromMap(json.decode(source));
#override
String toString() {
return 'OrderItem(id: $id, name: $name, date: $date, address: $address, recordNumber: $recordNumber)';
}
#override
bool operator ==(Object o) {
if (identical(this, o)) return true;
return o is OrderItem &&
o.id == id &&
o.name == name &&
o.date == date &&
o.address == address &&
o.recordNumber == recordNumber;
}
#override
int get hashCode {
return id.hashCode ^
name.hashCode ^
date.hashCode ^
address.hashCode ^
recordNumber.hashCode;
}
}
My question is two fold(this is what vs code plugin generates for class). First is how can I access the data in the instance of the class(do I need for each specific getter), and second can somebody explain what toMap(), fromMap(), toJson(), fromJson(), bool operator ==(Object o), and hashCode getter do.
Looks like you're trying to use Flutter navigation methods.
Have a look at this blog post that explains how it works.
In summary, to "push" state to be used in the next screen, do something like this:
final arguments = OrderItem(
id = 'id',
name = 'name',
date = 'date',
address = 'address',
recordNumber = '10',
);
Navigator.pushNamed(context, NamedPagePassed.route, arguments: arguments);
You can later access it like this:
final OrderItem args = ModalRoute.of(context).settings.arguments;
print('The id of the order is ${args.id}');
You seem to have a whole lot of generated code in your class. The fromJson, toJson, fromMap and toMap methods are used for serialization (i.e. turn a Dart object into something that can be "transferred" to/from another language/network/etc).
The == operator and hashCode are used to check if an object instance is equal to another (which is very common in Flutter as Flutter wants to know if your UI state has been modified). hashCode allows a fast way to check that two objects are definitely not equal (you can know for sure that two objects are not equal if their hash-codes are different... if the hash-codes are equal, the objects may or may not be equal, but the probability they are NOT equal will be low because hash functions try to avoid "collisions", which is when two different objects have the same hash-code).
Hash-code and == are normally implemented together to give your class "identity". Just google around and you'll see how this all works.
I would recommend you don't use code generation from your IDE like this. Instead, get familiar with how Dart builders work, then use a codegen library that will automatically create these methods for you every time you compile (so changes to the data model are immediately reflected in the implementation of all these generated methods).
My recommendation is to use freezed for that.
Your code will be much more maintainable this way.

Why Flutter Floor DAO findAll returns entity set with null ids?

This is a Flutter project using Floor (package equivalent of Jetpack's Room).
I have an entity with an auto increment id (note that this is pre null-safety code, in the answer I start now with post null safety snippet):
const String ACTIVITIES_TABLE_NAME = 'activities';
#Entity(
tableName: ACTIVITIES_TABLE_NAME,
indices: [
Index(value: ['start'])
],
)
class Activity {
#PrimaryKey(autoGenerate: true)
int id;
#ColumnInfo(name: 'device_name')
final String deviceName;
#ColumnInfo(name: 'device_id')
final String deviceId;
final int start;
Activity({
this.deviceName,
this.deviceId,
this.start,
});
}
I have this DAO:
#dao
abstract class ActivityDao {
#Query('SELECT * FROM $ACTIVITIES_TABLE_NAME ORDER BY start DESC')
Future<List<Activity>> findAllActivities();
#insert
Future<int> insertActivity(Activity activity);
}
In my app I recorded five activities so far, hunky-dory.
_database =
await $FloorAppDatabase.databaseBuilder('app_database.db').build();
...
_activity =
Activity(deviceName: device.name, deviceId: device.id.id, start: _lastRecord.millisecondsSinceEpoch);
final id = await _database.activityDao.insertActivity(_activity);
_activity.id = id;
Then in another view I list them, but there is a lurking problem.
final data = await _database.activityDao.findAllActivities();
When I query the entities with this dead simple method, all the five or so activities in my DB are returned with an id field filled with null. That makes the entity completely useless because any other operation I would like to perform on it fails due to lack of actual id. Am I doing something wrong?
I mostly have experience with MySQL, Postgres and non SQLite RDBMS. As I understand in SQLite every row has a unique rowid, and by declaring my auto increment id primary key field basically I alias that rowid? Whatever it is, I need the id. It cannot be null.
I'm debugging the guts of Floor.
Future<List<T>> queryList<T>(
final String sql, {
final List<dynamic> arguments,
#required final T Function(Map<String, dynamic>) mapper,
}) async {
final rows = await _database.rawQuery(sql, arguments);
return rows.map((row) => mapper(row)).toList();
}
At this point the rows still have the ids filled in properly, although the entities in the rows are just a list of dynamic values. The rows.map supposed to map them to the entity objects, and that cannot carry the id over for some reason? Can this be a Floor bug?
Ok, now I see that in the generated database.g.dart the mapper does not have the id:
static final _activitiesMapper = (Map<String, dynamic> row) => Activity(
deviceName: row['device_name'] as String,
deviceId: row['device_id'] as String,
start: row['start'] as int);
That explains it why id is null then. But this is generated code, how can I tell Floor I need the id? Or why should I tell it, it has to be there by default, who wouldn't want to know the primary key of an object?
Ok, so this is because I didn't have the the id as a constructor parameter. I didn't have that because it's an auto increment field and I'm not the one who determines it. However without having it as a constructor argument, the generated code cannot pass it along with the mapper as a parameter, so it leaves it out from the mapper. So I added the id as a constructor argument.
Post null-safety version:
class Activity {
#PrimaryKey(autoGenerate: true)
int? id;
#ColumnInfo(name: 'device_name')
final String deviceName;
#ColumnInfo(name: 'device_id')
final String deviceId;
final int start;
final int end;
Activity({
this.id,
required this.deviceName,
required this.deviceId,
required this.start,
this.end: 0,
});
}
I also add this Floor GitHub issue here, it looks like in the future there might be an annotation: https://github.com/vitusortner/floor/issues/527
Pre null-safety version:
import 'package:meta/meta.dart';
class Activity {
#PrimaryKey(autoGenerate: true)
int id;
#ColumnInfo(name: 'device_name')
#required
final String deviceName;
#ColumnInfo(name: 'device_id')
#required
final String deviceId;
final int start;
Activity({
this.id: null,
this.deviceName,
this.deviceId,
this.start,
});
}
The compiler is a little iffy about the null, but after the flutter packages pub run build_runner build the database.g.dart's mappers have the id as well.