I modified the basic sqlLite example to fit a more dynamic list. But its probably not the best method of doing it. Anyway the Database code looks like this:
import 'package:sqflite/sqflite.dart';
import 'package:sqflite/sqlite_api.dart';
import 'Entry.dart';
import 'package:path/path.dart';
class Database_ {
Future<Database> database ;
void openDBFunction() async {
var databasesPath = await getDatabasesPath();
String path = join(databasesPath, 'Journal Entries.db');
database = openDatabase(path, version: 1,
onCreate: (Database db, int version) async {
await db.execute(
"CREATE TABLE entries( _entry TEXT, _date TEXT)"
);
});
}
Future<void> insertEntry(Entry entry) async {
final Database db = await database;
await db.insert(
'entry',
entry.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
Future<List<Entry>> entries() async {
final Database db = await database;
final List<Map<String, dynamic>> maps = await db.query('entries');
return List.generate(maps.length, (i) {
return Entry(
maps[i]["_entry"],
maps[i]["_date"],
);
});
}
}
the main.dart looks like this:
import 'package:flutter/material.dart';
import 'package:slide_journal/MainPage.dart';
import 'package:flutter/widgets.dart';
import 'package:slide_journal/Database_.dart';
main()async {
WidgetsFlutterBinding.ensureInitialized();
Database_().openDBFunction();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData.dark(),
home: MainPage(),
);
}
}
and then this is the input page:
import 'dart:ui';
import 'package:flutter/material.dart';
import 'package:slide_journal/Database_.dart';
import 'package:slide_journal/Entry.dart';
import 'List_of_Entries.dart';
// ignore: must_be_immutable
class MainPage extends StatelessWidget{
TextEditingController _controller = TextEditingController();
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
shape: RoundedRectangleBorder(borderRadius: BorderRadius.vertical(bottom: Radius.circular(30))),
title: Text("Home"),
toolbarHeight: 50,
automaticallyImplyLeading: false,
actions:<Widget> [IconButton(
icon: Icon(Icons.list_alt_sharp),
onPressed: () =>{
Navigator.push(context, (MaterialPageRoute(builder: (context)=>ListOfEntries())))
},
),
]
),
drawer: new Drawer(
child: new ListView(
children: <Widget>[
new DrawerHeader(
child: Text("Trisha is baby", style: new TextStyle(fontSize: 20),),
)
],
),
),
body: Center(
child: SingleChildScrollView(
child: Column(
children: [
Container(
height: 600,
width: 350,
child: TextField(
enabled: true,
controller: _controller,
enableSuggestions: true,
decoration: InputDecoration(
hintText: "Use text, emojis...",
suffixIcon: IconButton(
onPressed: () => {
addEntry(_controller.toString(), "DateTime.now().toString()"),
},
icon: Icon(Icons.send_outlined),
),
),
keyboardType: TextInputType.multiline,
style: TextStyle(fontSize: 30),
maxLength: 100,
),
)
],
),
)
),
);
}
void addEntry(String entry_, String date_)async {
final entry = Entry(
entry_,
date_
);
Database_().insertEntry(entry);
}
}
This is the error:
[ERROR:flutter/lib/ui/ui_dart_state.cc(186)] Unhandled Exception: NoSuchMethodError: The method 'insert' was called on null.
Database is not intialized in your app. Do as below
class DatabaseHelper {
static String tableName = 'entries';
static late Database _database;
static Future<Database> get database async {
final databasePath = await getDatabasesPath();
final status = await databaseExists(databasePath);
if (!status) {
_database = await openDatabase(join(databasePath, 'notes_database.db'),
onCreate: (database, version) {
return database.execute(
"CREATE TABLE entries( _entry TEXT, _date TEXT)"
);
}, version: 1);
}
return _database;
}
static Future<bool> insertDb(Model yourModel) async {
final db = await database;
try {
await db.insert(your insert cmd);
} on Error {
throw Error();
}
return true;
}
}
database is not initialized. It has to be initialized before you can turn objects into it.
Related
Hello guys I made simple application use sqflite when I want to insert database it says in console MissingPluginException(No implementation Found for method getDabasesPath on channel com.tekartik.sqflite)
this is code
main.dart
import 'dart:async';
import 'package:ass/sqlflite.dart';
import 'package:flutter/material.dart';
void main() async {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
home: Home(),
title: 'Sqlflite',
);
}
}
class Home extends StatefulWidget {
_HomeState createState() => _HomeState();
}
class _HomeState extends State<Home> {
SqlDb sqlDb = SqlDb();
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(),
body: Container(
child: Column(
children: <Widget>[
Center(
child: MaterialButton(
color: Theme.of(context).primaryColor,
child: Text(
'InsertData ',
style: TextStyle(color: Colors.white),
),
onPressed: () async {
int response = await sqlDb.insertData(
"INSERT into 'notes' ('note') VALUES ('note one')");
print(response);
},
),
),
Center(
child: MaterialButton(
color: Theme.of(context).primaryColor,
child: Text(
'ReadData ',
style: TextStyle(color: Colors.white),
),
onPressed: () async {
List<Map> response =
await sqlDb.readData("SELECT * FROM notes");
print(response);
},
),
),
],
),
),
);
}
}
and sqlflite.dart
import 'dart:async';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
class SqlDb {
static Database? _db;
Future<Database?> get db async {
if (_db == null) {
_db = await initialDb();
return db;
} else {
return _db;
}
}
initialDb() async {
var databasepath = await getDatabasesPath();
String path = await join(databasepath, 'wael.db');
Database mydb = await openDatabase(path,
onCreate: _onCreate, version: 3, onUpgrade: _onUpgrade);
return mydb;
}
_onUpgrade(Database db, int oldversion, int newversion) async {
print("upgrade on =============");
}
_onCreate(Database db, int version) async {
await db.execute('''
CREATE TABLE "notes"(
"id" INTEGER NOT NULL PRIMARY KEY AUTOINCREMENT ,
"note" TEXT NOT NULL
)
''');
print("create DB");
}
readData(String sql) async {
Database? mydb = await db;
List<Map> response = await mydb!.rawQuery(sql);
return response;
}
insertData(String sql) async {
Database? mydb = await db;
int response = await mydb!.rawInsert(sql);
return response;
}
updateData(String sql) async {
Database? mydb = await db;
int response = await mydb!.rawUpdate(sql);
return response;
}
deleteData(String sql) async {
Database? mydb = await db;
int response = await mydb!.rawDelete(sql);
return response;
}
}
it doesn't make any errors in analyzer but when the emulator appears and click on insertdata button it says in console
MissingPluginException(No implementation Found for method getDabasesPath on channel com.tekartik.sqflite)
MissingPluginException occurs due to the newly added dependencies run the following commands it will work
flutter clean
flutter pub get
I'm a beginner in flutter, I'm building a simple Note app where users can enter, edit and save the note in local db. I'm able to save the notes to DB but it is not fetched as soon as it is saved. I need to restart the app to see the note list.
This is a Notes model class
import 'db_operations.dart';
class Note {
int id;
String title;
String body;
Note(this.id, this.title, this.body);
Note.fromMap(Map<String, dynamic> map) {
id = map['id'];
title = map['title'];
body = map['body'];
}
Map<String, dynamic> toMap(){
return {
DatabaseHelper.columnId : id,
DatabaseHelper.columnTitle : title,
DatabaseHelper.columnBody : body
};
}
#override
String toString(){
return 'Note{title : $title, body : $body}';
}
}
This is a Database helper class
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'model_notes.dart';
class DatabaseHelper {
static final _databaseName = "myNote.db";
static final _databaseVersion = 1;
static final table = 'notes_table';
static final columnId = 'id';
static final columnTitle = 'title';
static final columnBody = 'body';
DatabaseHelper._privateConstructor();
static final DatabaseHelper instance = DatabaseHelper._privateConstructor();
static Database _database;
Future<Database> get database async {
if (_database != null) return _database;
// lazily instantiate the db the first time it is accessed
_database = await initDatabase();
return _database;
}
initDatabase() async {
String path = join(await getDatabasesPath(), _databaseName);
return await openDatabase(path,
version: _databaseVersion,
onCreate: _onCreate);
}
Future _onCreate(Database db, int version) async {
await db.execute('''
CREATE TABLE $table (
$columnId INTEGER PRIMARY KEY AUTOINCREMENT,
$columnTitle TEXT NOT NULL,
$columnBody TEXT NOT NULL
)
''');
}
Future<int> insert(Note note) async {
Database db = await instance.database;
if (note.title.trim().isEmpty) note.title = 'Untitled Note';
return await db.insert(table, {'title': note.title, 'body': note.body});
}
Future<List<Note>> getNotesFromDB() async {
final db = await database;
List<Note> notesList = [];
List<Map> maps = await db.query(table);
if (maps.length > 0) {
maps.forEach((map) {
notesList.add(Note.fromMap(map));
});
}
return notesList;
}
}
This is where I am adding notes
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:note_taking_app/constants/buttons_and_icons_misc(classes).dart';
import 'package:note_taking_app/db/db_operations.dart';
import 'package:note_taking_app/db/model_notes.dart';
import 'package:sqflite/sqflite.dart';
import 'main_screen.dart';
final bodyController = TextEditingController();
final headerController = TextEditingController();
final dbHelper = DatabaseHelper.instance;
class AddingNotes extends StatefulWidget {
#override
_AddingNotesState createState() => _AddingNotesState();
}
class _AddingNotesState extends State<AddingNotes> {
#override
void initState() {
super.initState();
bodyController.clear();
headerController.clear();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
backwardsCompatibility: true,
leading: LeadingIcon(
callBack: () {
Navigator.pop(context);
},
),
backgroundColor: Colors.white.withOpacity(0.4),
actions: <Widget>[
ActionsIconButton(
icon: Icon(undo, color: black),
callBack: () {
debugPrint('undo tapped');
},
),
ActionsIconButton(
icon: Icon(redo, color: black),
callBack: () {
debugPrint('redo tapped');
},
),
ActionsIconButton(
icon: Icon(save, color: black),
callBack: () async {
debugPrint(bodyController.text);
debugPrint(headerController.text);
String title = headerController.text;
String body = bodyController.text;
Note note = Note(20, title, body);
var value = await dbHelper.insert(note);
print("if 1 is return then insert success and 0 then not inserted : $value");
Navigator.pop(context);
},
)
],
),
body: Container(
color: Colors.white.withOpacity(0.4),
child: Padding(
padding: const EdgeInsets.all(13.0),
child: Column(
children: [
HeaderBody(
textEditingController: headerController,
),
SizedBox(
height: 32.0,
),
Expanded(
child: NotesBody(
textEditingController: bodyController,
),
),
],
),
),
),
);
}
}
This is where I am displaying notes
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:note_taking_app/constants/text_and_decorations(methods).dart';
import 'package:note_taking_app/db/model_notes.dart';
import 'package:note_taking_app/ui/adding_notes.dart';
import 'package:note_taking_app/db/db_operations.dart';
class MainScreen extends StatefulWidget {
#override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
List<Note> noteList = [];
#override
void initState() {
super.initState();
dbHelper.initDatabase();
setNotesFromDB();
}
setNotesFromDB() async{
print("Entered setNotes");
var fetchedNotes = await dbHelper.getNotesFromDB();
setState(() {
noteList = fetchedNotes;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
elevation: 0,
title: titleText,
backwardsCompatibility: false,
automaticallyImplyLeading: false,
backgroundColor: Colors.white.withOpacity(0.4),
),
floatingActionButton: Container(
height: 80.0,
width: 80.0,
child: FittedBox(
child: FloatingActionButton(
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => AddingNotes()));
},
child: const Icon(
Icons.add,
),
backgroundColor: Colors.green,
),
),
),
body: ListView.builder(
itemCount: noteList.length,
itemBuilder: (context, index){
return ListTile(
title: Text('${noteList[index]}'),
);
},
),
);
}
}
When I restart the app I'm getting user-entered notes. How can I make this dynamic, as a user enters a note and save it, it should be displayed on Main Screen. but I don't know how to do that. Any help here guys, I'm stuck at this..
The problem is that you are using a future, once it is complete there will be no updates, unless the Widget calling the getNotesFromDB() gets rebuild, which is the case when you restart the app or the emulator.
Moreover, you are also only fetching the notes in initState() of your MainScreen.
Option 1:
Try turning your ListView.builder in the body into a streambuilder, which is refreshing your Screen whenever a new note is saved.
Option 2:
Alternatively, implement a pull-to-refresh logic, which calls getNotesFromDB() for you. Checkout this video from the FlutterTeam to implement the feature.
I'm trying to make an app that has basically the same mechanics as a simple todo-app. My problem is, when I try to open the screen where I can create a new project/todo(new_project_screen), there should be loaded some TextFields, but they don't. Instead, this error occurs. I tried several solutions from stackoverflow, but nothing worked and I have no idea why it's not working.(sorry for my bad english, I'm not a native xD)
Here is my code:
main.dart:
import 'package:flutter/material.dart';
import 'package:leisy/surface/main_screen.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(App());
}
class App extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Leisy',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MainScreen(),
);
}
}
main_screen.dart:
import 'package:flutter/material.dart';
import 'dart:async';
import 'package:sqflite/sqflite.dart';
import 'package:leisy/db/database_helper.dart';
import 'package:leisy/model/project.dart';
import 'package:leisy/surface/settings_screen.dart';
import 'package:leisy/surface/new_project_screen.dart';
class MainScreen extends StatefulWidget {
#override
_MainScreenState createState() => _MainScreenState();
}
class _MainScreenState extends State<MainScreen> {
DatabaseHelper databaseHelper = DatabaseHelper();
List<Project> projectList = [];
int count = 0;
#override
Widget build(BuildContext context) {
if (projectList == null) {
projectList = <Project>[];
updateListView();
}
debugPrint("Building entire main screen scaffold");
return Scaffold(
appBar: AppBar(
title: Text("Leisy"),
),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Center(
child: Text(
"Menü",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 25,
),
),
),
decoration: BoxDecoration(color: Colors.blue),
),
ListTile(
leading: Icon(Icons.home),
title: Text('Home'),
onTap: () => {Navigator.of(context).pop()},
),
ListTile(
leading: Icon(Icons.add),
title: Text('Neues Projekt'),
onTap: () => {
Navigator.of(context).push(new MaterialPageRoute(
builder: (context) => new NewProjectScreen()))
},
),
ListTile(
leading: Icon(Icons.settings),
title: Text('Einstellungen'),
onTap: () => {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => SettingsScreen()))
},
)
],
),
),
body: getProjectListView(),
floatingActionButton: FloatingActionButton(
child: Icon(Icons.add),
onPressed: navigateToNewProject,
),
);
}
ListView getProjectListView() {
TextStyle titleStyle = Theme.of(context).textTheme.subtitle1;
return ListView.builder(
itemCount: count,
itemBuilder: (BuildContext context, int position) {
return Card(
color: Colors.white,
elevation: 2.0,
child: ListTile(
leading: CircleAvatar(
backgroundColor: Colors.blue,
),
title: Text(
this.projectList[position].name,
style: titleStyle,
),
subtitle: Text(this.projectList[position].date),
onTap: () {
debugPrint('ListTile Tapped');
//navigateToDetail() einfügen
},
),
);
});
}
void _showSnackBar(BuildContext context, String message) {
final snackBar = SnackBar(
content: Text(message),
);
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
void navigateToNewProject() async {
bool result = await Navigator.push(context, MaterialPageRoute(builder: (context) => NewProjectScreen()));
if (result == true) {
updateListView();
}
}
void updateListView() {
final Future<Database> dbFuture = databaseHelper.initDB();
dbFuture.then((database) {
Future<List<Project>> projectListFuture = databaseHelper.getProjectList();
projectListFuture.then((projectList) {
setState(() {
this.projectList = projectList;
this.count = projectList.length;
});
});
});
}
}
new_project_screen.dart:
import 'package:flutter/material.dart';
import 'package:leisy/db/database_helper.dart';
import 'package:leisy/model/project.dart';
import 'package:leisy/surface/main_screen.dart';
import 'package:leisy/surface/settings_screen.dart';
class NewProjectScreen extends StatefulWidget {
#override
_NewProjectScreenState createState() => _NewProjectScreenState();
}
class _NewProjectScreenState extends State<NewProjectScreen> {
Project project;
DatabaseHelper helper = DatabaseHelper();
TextEditingController nameController = TextEditingController();
TextEditingController dateController = TextEditingController();
TextEditingController locationController = TextEditingController();
#override
Widget build(BuildContext context) {
nameController.text = project.name;
dateController.text = project.date;
locationController.text = project.location;
return Scaffold(
appBar: AppBar(
title: Text("Neues Projekt"),
leading: IconButton(
icon: Icon(Icons.arrow_back),
onPressed: () {
Navigator.pop(context);
},
),
),
drawer: Drawer(
child: ListView(
padding: EdgeInsets.zero,
children: <Widget>[
DrawerHeader(
child: Center(
child: Text(
"Menü",
textAlign: TextAlign.center,
style: TextStyle(
color: Colors.white,
fontSize: 25,
),
),
),
decoration: BoxDecoration(color: Colors.blue),
),
ListTile(
leading: Icon(Icons.home),
title: Text('Home'),
onTap: () => {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => MainScreen()))
},
),
ListTile(
leading: Icon(Icons.add),
title: Text('Neues Projekt'),
onTap: () => {Navigator.of(context).pop()},
),
ListTile(
leading: Icon(Icons.settings),
title: Text('Einstellungen'),
onTap: () => {
Navigator.of(context).push(
MaterialPageRoute(builder: (context) => SettingsScreen()))
},
)
],
),
),
body: Padding(
padding: EdgeInsets.all(8.0),
child: ListView(
children: <Widget>[
TextField(
controller: nameController,
decoration: InputDecoration(labelText: 'Name'),
style: TextStyle(fontSize: 20),
onChanged: (value) {
setState(() {
updateName();
});
},
),
TextField(
decoration: InputDecoration(labelText: 'Datum'),
style: TextStyle(fontSize: 20),
onChanged: (value) {
setState(() {
updateDate();
});
},
),
TextField(
decoration: InputDecoration(labelText: 'Ort'),
style: TextStyle(fontSize: 20),
onChanged: (value) {
setState(() {
updateLocation();
});
},
),
Row(
children: <Widget>[
Expanded(
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
Theme.of(context).primaryColorDark),
),
child: Text('Speichern'),
onPressed: () {
setState(() {
_save();
});
},
)),
Expanded(
child: ElevatedButton(
style: ButtonStyle(
backgroundColor: MaterialStateProperty.all(
Theme.of(context).primaryColorDark),
),
child: Text('Abbrechen'),
onPressed: () {
setState(() {
_cancel();
});
},
)),
],
)
],
)
)
);
}
void _save() async {
Navigator.pop(context, true);
await helper.insertProject(project);
}
void _showSnackBar(String message) {
SnackBar snackBar = SnackBar(content: Text(message));
ScaffoldMessenger.of(context).showSnackBar(snackBar);
}
void _cancel() async {
Navigator.pop(context, true);
_showSnackBar('Vorgang abgebrochen');
}
void updateName() {
project.name = nameController.text;
}
void updateDate() {
project.date = dateController.text;
}
void updateLocation() {
project.location = locationController.text;
}
}
project.dart:
class Project {
int _id;
String _name;
String _date;
String _location;
String _personaldb;
Project(this._name, this._date, this._location, this._personaldb);
Project.withId(
this._id, this._name, this._date, this._location, this._personaldb);
int get id => _id;
String get name => _name;
String get date => _date;
String get location => _location;
String get personalDB => _personaldb;
set name(String newName) {
if (newName.length <= 63) {
this._name = newName;
}
}
set date(String newDate) {
this._date = newDate;
}
set location(String newLocation) {
this._location = newLocation;
}
set personalDB(String newPersonalDB) {
this._personaldb = newPersonalDB;
}
Map<String, dynamic> toMap() {
var map = Map<String, dynamic>();
if (id != null) {
map['id'] = _id;
}
map['name'] = _name;
map['date'] = _date;
map['location'] = _location;
map['personalDB'] = _personaldb;
return map;
}
Project.fromMapObject(Map<String, dynamic> map) {
this._id = map['id'];
this._name = map['name'];
this._date = map['date'];
this._location = map['location'];
this._personaldb = map['personalDB'];
}
}
database_helper.dart:
import 'dart:async';
import 'dart:io';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'package:leisy/model/project.dart';
class DatabaseHelper {
static DatabaseHelper _databaseHelper;
static Database _database;
String projectTable = 'project_table';
String colId = 'id';
String colName = 'name';
String colDate = 'date';
String colLocation = 'location';
String colPersonalDB = 'personalDB';
DatabaseHelper._createInstance();
factory DatabaseHelper() {
if (_databaseHelper == null) {
_databaseHelper = DatabaseHelper._createInstance();
}
return _databaseHelper;
}
Future<Database> get database async {
if (_database == null) {
_database = await initDB();
}
return _database;
}
Future<Database> initDB() async {
Directory directory = await getApplicationDocumentsDirectory();
String path = directory.path + 'projects.db';
var projectsDB = await openDatabase(path, version: 1, onCreate: _createDB);
return projectsDB;
}
void _createDB(Database db, int newVersion) async {
await db.execute('CREATE TABLE $projectTable('
'$colId INTEGER PRIMARY KEY AUTOINCREMENT,'
'$colName TEXT,'
'$colDate TEXT,'
'$colLocation TEXT,'
'$colPersonalDB TEXT)');
}
Future<List<Map<String, dynamic>>> getProjectMapList() async {
Database db = await this.database;
var result = await db.query(projectTable);
return result;
}
Future<int> insertProject(Project project) async {
Database db = await this.database;
var result = await db.insert(projectTable, project.toMap());
return result;
}
Future<int> updateProject(Project project) async {
var db = await this.database;
var result = await db.update(projectTable, project.toMap(), where: '$colId = ?', whereArgs: [project.id]);
return result;
}
Future<int> deleteProject(int id) async {
var db = await this.database;
int result = await db.delete(projectTable, where: '$colId = $id');
return result;
}
Future<int> getCount() async {
Database db = await this.database;
List<Map<String, dynamic>> x = await db.rawQuery('SELECT COUNT (*) from $projectTable');
int result = Sqflite.firstIntValue(x);
return result;
}
Future<List<Project>> getProjectList() async {
var projectMapList = await getProjectMapList();
int count = projectMapList.length;
List<Project> projectList = <Project>[];
for (int i = 0; i < count; i++) {
projectList.add(Project.fromMapObject(projectMapList[i]));
}
return projectList;
}
}
Error:
======== Exception caught by widgets library =======================================================
The following NoSuchMethodError was thrown building NewProjectScreen(dirty, state: _NewProjectScreenState#670bc):
The getter 'name' was called on null.
Receiver: null
Tried calling: name
The relevant error-causing widget was:
NewProjectScreen file:///C:/Users/gabri/AndroidStudioProjects/leisy/lib/surface/main_screen.dart:116:89
When the exception was thrown, this was the stack:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:54:5)
#1 _NewProjectScreenState.build (package:leisy/surface/new_project_screen.dart:24:35)
#2 StatefulElement.build (package:flutter/src/widgets/framework.dart:4612:27)
#3 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4495:15)
#4 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4667:11)
...
====================================================================================================
If anybody can help me, I would really appreciate it. And if anything in my code is inconvenient or badly implemented, please be kind with me I'm a beginner at this.
The file new_project_screen.dart has the problem
To be exact, the problem can be found in lines 24:35
And seems like that project variable is null project.name;
That is because you are creating Project project but isn't instancied yet. Is just a null variable
See the image below, will help you to understand a bit:
https://dartpad.dev/1ebc897cd3f547cc0b79e52290a63653
So to fix it, you need to create the instance previously
is there a way to test the content within a show dialog?
I am trying to do BDD in the project, The following is the scenario:
As a User, I would like to add a photo or select one from the gallery so that I can use it on the item.
The following is the code I am using to test it but for some reason, the test fails.
add_item_view.dart
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter_hooks/flutter_hooks.dart';
import 'package:my_app_mobile/models/graded_item/graded_item.dart';
import 'package:my_app_mobile/template/index.dart' as template;
import 'package:image_picker/image_picker.dart';
class AddItemView extends HookWidget {
final GradedItem gradedItem;
static final Key photoKey = Key('#photoKey');
static final GlobalKey<FormState> formKey = GlobalKey<FormState>();
final void Function() onPhoto;
final ImagePicker _imagePicker = ImagePicker();
AddItemView({
#required this.gradedItem,
this.onPhoto,
});
#override
Widget build(BuildContext context) {
final _image = useState<File>();
Future getImage() async {
final pickedFile = await _imagePicker.getImage(source: ImageSource.camera);
if (pickedFile != null) {
_image.value = File(pickedFile.path);
} else {
print('No image selected.');
}
}
return Scaffold(
appBar: AppBar(),
body: SingleChildScrollView(
child: Form(
key: formKey,
child: Column(
children: [
GestureDetector(
onTap: () async {
if (onPhoto != null) {
onPhoto();
}
showDialog(
context: context,
barrierColor: Colors.red.withOpacity(.2),
builder: (context) {
return CameraOptions();
},
);
},
child: Container(
key: photoKey,
alignment: Alignment.center,
child: Icon(
Icons.add_a_photo,
color: Theme.of(context).primaryColor,
size: 44.0,
),
height: 100.0,
width: 100.0,
decoration: BoxDecoration(
color: template.colors.grey340,
borderRadius: BorderRadius.circular(10.0),
),
),
),
],
),
),
),
);
}
}
class CameraOptions extends StatelessWidget {
static final Key captureButtonPhotoKey = Key('#captureButtonPhotoKey');
static final Key chooseButtonPhotoKey = Key('#chooseButtonPhotoKey');
static final Key cancelButtonKey = Key('#cancelButtonKey');
final void Function() onCapture;
final void Function() onChoose;
final void Function() onCancel;
CameraOptions({this.onCapture, this.onChoose, this.onCancel});
#override
Widget build(BuildContext context) {
return Center(
child: Container(
height: 200.0,
width: 200.0,
child: Icon(Icons.camera, color: Colors.blue),
),
);
}
}
add_item_view_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'my_app_mobile/models/graded_item/graded_item.dart';
import 'my_app_mobile/views/dashboard/children/collection/children/add_item/add_item.dart';
import 'package:mockito/mockito.dart';
void main() {
Widget mountApp({GradedItem gradedItem, void Function() onPhoto}) {
return MaterialApp(
home: AddItemView(
gradedItem: gradedItem,
onPhoto: onPhoto,
),
);
}
testWidgets('should build with no problems', (tester) async {
await tester.pumpWidget(mountApp(gradedItem: GradedItem.generate()));
expect(find.byType(AddItemView), findsOneWidget);
});
group('photo', () {
testWidgets(
'should photo widget be available',
(tester) async {
await tester.pumpWidget(mountApp(
gradedItem: GradedItem.generate(),
));
expect(find.byKey(AddItemView.photoKey), findsOneWidget);
},
);
testWidgets(
'should be able to call onPhoto handler when is available',
(tester) async {
final fn = MockedFunctions();
await tester.pumpWidget(mountApp(
gradedItem: GradedItem.generate(),
onPhoto: fn.onPhoto,
));
expect(find.byKey(AddItemView.photoKey), findsOneWidget);
await tester.tap(find.byKey(AddItemView.photoKey));
verify(fn.onPhoto()).called(1);
},
);
testWidgets(
'should onPhoto handler open camera options',
(tester) async {
await tester.pumpWidget(
MaterialApp(
home: Material(
child: Builder(
builder: (BuildContext context) {
return AddItemView(
gradedItem: GradedItem.generate(),
// onPhoto: fn.onPhoto,
);
},
),
),
),
);
await tester.tap(find.byKey(AddItemView.photoKey));
await tester.pumpAndSettle(const Duration(seconds: 1));
expect(find.byIcon(Icons.camera), findsOneWidget);
},
);
});
}
class MockedFunctions extends Mock {
void onPhoto();
}
Is there a way to do testing on a showDialog function?
Solved, for some reason, the code I posted is working, I restarted my computer and now they are working.
I'm learning Flutter and I'm trying to use the SQFLite package to persist data on the device. Everything works perfect but there's one problem, every time I add a new element or I upgrade it, I need to restart my app to see the changes and I don't know why, there are no errors or anything.
I uploaded it to github so you can try it, maybe is something in my emulator or something I dont know.
https://github.com/Rodrigogzmn6/sql_demo
or you can see part of the complete project here
Home Page
import 'package:flutter/material.dart';
import 'package:sql_demo/models/product.dart';
import 'package:sql_demo/pages/add_product_page.dart';
import 'package:sql_demo/pages/update_product_page.dart';
import 'package:sql_demo/pages/view_product_page.dart';
import 'package:sql_demo/services/dbhelper.dart';
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
DbHelper helper;
#override
void initState() {
super.initState();
helper = DbHelper();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home Page'),
),
body: FutureBuilder(
future: helper.getProducts(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
Product product = Product.fromMap(snapshot.data[index]);
return ListTile(
contentPadding: const EdgeInsets.all(16.0),
title: Text(
'${product.name} - \$${(product.price).toString()}'),
subtitle: Text(product.description),
trailing: Column(
children: [
Expanded(
child: IconButton(
icon: Icon(
Icons.delete,
color: Colors.red,
),
onPressed: () {
setState(() {
helper.deleteProduct(product.id);
});
}),
),
SizedBox(
height: 20.0,
),
Expanded(
child: IconButton(
icon: Icon(
Icons.edit,
color: Colors.blue,
),
onPressed: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => UpdateProductPage(
product: product,
)),
);
}),
),
],
),
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetailsPage(
product: product,
)));
},
);
});
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
),
floatingActionButton: FloatingActionButton(
child: Icon(
Icons.add,
color: Colors.white,
),
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => AddProductPage()));
}),
);
}
}
Creating Item page
import 'package:flutter/material.dart';
import 'package:sql_demo/models/product.dart';
import 'package:sql_demo/services/dbhelper.dart';
class AddProductPage extends StatefulWidget {
#override
_AddProductPageState createState() => _AddProductPageState();
}
class _AddProductPageState extends State<AddProductPage> {
String name, description;
num price;
DbHelper helper;
//Instantiate Helper
#override
void initState() {
super.initState();
helper = DbHelper();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Add new product"),
),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
TextFormField(
decoration: InputDecoration(
hintText: 'Enter product name',
labelText: 'Product name',
),
onChanged: (value) {
setState(() {
name = value;
});
},
),
SizedBox(height: 16),
TextFormField(
decoration: InputDecoration(
hintText: 'Enter product description',
labelText: 'Product description',
),
onChanged: (value) {
setState(() {
description = value;
});
},
),
SizedBox(height: 16),
TextFormField(
keyboardType: TextInputType.number,
decoration: InputDecoration(
hintText: 'Enter product price',
labelText: 'Product price',
),
onChanged: (value) {
setState(() {
price = double.parse(value);
});
},
),
SizedBox(height: 16),
RaisedButton(
child: Text('Save'),
onPressed: () {
Product product = Product({
'name': name,
'description': description,
'price': price,
});
setState(() {
helper.createProduct(product);
Navigator.pop(context);
});
},
),
],
),
);
}
}
Database operations
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'package:sql_demo/models/product.dart';
class DbHelper {
//Creates a singleton class (it only creates once)
static final DbHelper _singleton = DbHelper._internal();
factory DbHelper() => _singleton;
DbHelper._internal();
//Creating an object of type database
static Database _database;
//Initializing or creating the database named mydb.db
//Creating a products table with necessary fields
Future<Database> initDatabase() async {
//If this class was never instaciated, we will execute this method, otherwise return
if (_database != null) return _database;
String path = join(await getDatabasesPath(), 'mydb.db');
_database = await openDatabase(
path,
version: 1,
onCreate: (Database db, int v) async {
await db.execute(
'CREATE TABLE Products (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, description TEXT, price REAL)');
},
);
return _database;
}
//Select all products
Future<List> getProducts() async {
Database db = await initDatabase();
return await db.query('Products');
}
//Create new product
Future<int> createProduct(Product product) async {
Database db = await initDatabase();
print('Product added');
return await db.insert(
'Products',
product.toMap(),
);
}
//Update product
Future<int> updateProduct(Product product) async {
Database db = await initDatabase();
return await db.update(
'Products',
product.toMap(),
where: 'id=?',
whereArgs: [product.id],
);
}
//Delete a product
Future<int> deleteProduct(int productID) async {
Database db = await initDatabase();
return await db.delete('Products', where: 'id=?', whereArgs: [productID]);
}
}
You can copy paste run full code below
You can await Navigator.push to AddProductPage and then call setState(() {});
code snippet
onPressed: () async {
await Navigator.push(context,
MaterialPageRoute(builder: (context) => AddProductPage()));
setState(() {});
}),
working demo
full code
import 'package:flutter/material.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
import 'dart:convert';
class Product {
int _id;
String _name;
String _description;
double _price;
//Getters because the attributes are private
int get id => _id;
String get name => _name;
String get description => _description;
double get price => _price;
//Constructor
Product(dynamic obj) {
_id = obj['id'];
_name = obj['name'];
_description = obj['description'];
_price = obj['price'];
}
//Named objet (takes a Map as parameter)
Product.fromMap(Map<String, dynamic> data) {
_id = data['id'];
_name = data['name'];
_description = data['description'];
_price = data['price'];
}
//Method that converts the object into a map
Map<String, dynamic> toMap() {
return {
'id': _id,
'name': _name,
'description': _description,
'price': _price,
};
}
}
class HomePage extends StatefulWidget {
#override
_HomePageState createState() => _HomePageState();
}
class _HomePageState extends State<HomePage> {
DbHelper helper;
#override
void initState() {
super.initState();
helper = DbHelper();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Home Page'),
),
body: FutureBuilder(
future: helper.getProducts(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
if (snapshot.hasData) {
return ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
Product product = Product.fromMap(snapshot.data[index]);
return ListTile(
contentPadding: const EdgeInsets.all(16.0),
title: Text(
'${product.name} - \$${(product.price).toString()}'),
subtitle: Text(product.description),
trailing: Column(
children: [
Expanded(
child: IconButton(
icon: Icon(
Icons.delete,
color: Colors.red,
),
onPressed: () {
setState(() {
helper.deleteProduct(product.id);
});
}),
),
SizedBox(
height: 20.0,
),
Expanded(
child: IconButton(
icon: Icon(
Icons.edit,
color: Colors.blue,
),
onPressed: () {
/*Navigator.push(
context,
MaterialPageRoute(
builder: (context) => UpdateProductPage(
product: product,
)),
);*/
}),
),
],
),
onTap: () {
/*Navigator.push(
context,
MaterialPageRoute(
builder: (context) => ProductDetailsPage(
product: product,
)));*/
},
);
});
} else {
return Center(
child: CircularProgressIndicator(),
);
}
},
),
floatingActionButton: FloatingActionButton(
child: Icon(
Icons.add,
color: Colors.white,
),
onPressed: () async {
await Navigator.push(context,
MaterialPageRoute(builder: (context) => AddProductPage()));
setState(() {});
}),
);
}
}
class AddProductPage extends StatefulWidget {
#override
_AddProductPageState createState() => _AddProductPageState();
}
class _AddProductPageState extends State<AddProductPage> {
String name, description;
num price;
DbHelper helper;
//Instantiate Helper
#override
void initState() {
super.initState();
helper = DbHelper();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text("Add new product"),
),
body: ListView(
padding: const EdgeInsets.all(16),
children: [
TextFormField(
decoration: InputDecoration(
hintText: 'Enter product name',
labelText: 'Product name',
),
onChanged: (value) {
setState(() {
name = value;
});
},
),
SizedBox(height: 16),
TextFormField(
decoration: InputDecoration(
hintText: 'Enter product description',
labelText: 'Product description',
),
onChanged: (value) {
setState(() {
description = value;
});
},
),
SizedBox(height: 16),
TextFormField(
keyboardType: TextInputType.number,
decoration: InputDecoration(
hintText: 'Enter product price',
labelText: 'Product price',
),
onChanged: (value) {
setState(() {
price = double.parse(value);
});
},
),
SizedBox(height: 16),
RaisedButton(
child: Text('Save'),
onPressed: () {
Product product = Product({
'name': name,
'description': description,
'price': price,
});
setState(() {
helper.createProduct(product);
Navigator.pop(context);
});
},
),
],
),
);
}
}
class DbHelper {
//Creates a singleton class (it only creates once)
static final DbHelper _singleton = DbHelper._internal();
factory DbHelper() => _singleton;
DbHelper._internal();
//Creating an object of type database
static Database _database;
//Initializing or creating the database named mydb.db
//Creating a products table with necessary fields
Future<Database> initDatabase() async {
//If this class was never instaciated, we will execute this method, otherwise return
if (_database != null) return _database;
String path = join(await getDatabasesPath(), 'mydb.db');
_database = await openDatabase(
path,
version: 1,
onCreate: (Database db, int v) async {
await db.execute(
'CREATE TABLE Products (id INTEGER PRIMARY KEY AUTOINCREMENT, name TEXT, description TEXT, price REAL)');
},
);
return _database;
}
//Select all products
Future<List> getProducts() async {
Database db = await initDatabase();
return await db.query('Products');
}
//Create new product
Future<int> createProduct(Product product) async {
Database db = await initDatabase();
print('Product added');
return await db.insert(
'Products',
product.toMap(),
);
}
//Update product
Future<int> updateProduct(Product product) async {
Database db = await initDatabase();
return await db.update(
'Products',
product.toMap(),
where: 'id=?',
whereArgs: [product.id],
);
}
//Delete a product
Future<int> deleteProduct(int productID) async {
Database db = await initDatabase();
return await db.delete('Products', where: 'id=?', whereArgs: [productID]);
}
}
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
visualDensity: VisualDensity.adaptivePlatformDensity,
),
home: HomePage(),
);
}
}
Hot reload: Hot reload feature quickly compile the newly added code in our file and sent the code to Dart Virtual Machine. If you are using States in your application then Hot Reload preservers the States so they will not update on Hot Reload our set to their default values.
And, initState() does not rebuild after hot reload as its state is preserved. So, you have to perform hot restart to see database changes:
#override
void initState() {
super.initState();
helper = DbHelper();
}
When stateful widget is build, you have helper, but after you hot reload, the helper will be same as initState only called hot restart or you launch the widget. So, helper variable is preserved. Hence, you have to hot restart.
Links that might help you: Understanding Flutter hot reload and hot restart the simplest way | Refs