sqflite - Flutter でデータベースの変更を確認するためにホットリスタートを実行する必要があるのはなぜですか?

okwaves2024-01-24  7

私は Flutter を学習しており、SQFLite パッケージを使用してデバイス上にデータを保持しようとしています。すべてが完璧に機能しますが、問題が 1 つあります。新しい要素を追加したりアップグレードしたりするたびに、変更を確認するためにアプリを再起動する必要があります。理由はわかりませんが、エラーも何もありません。 github にアップロードしたので試してみてください。おそらく私のエミュレータに何かがあるか、私が知らない何かがあるかもしれません。 https://github.com/Rodrigogzmn6/sql_demo

または、完全なプロジェクトの一部をここで見ることができます

ホームページ

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()));
          }),
    );
  }
}

アイテムの作成ページ

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);
              });
            },
          ),
        ],
      ),
    );
  }
}

データベース操作

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]);
  }
}


------------------------

あなたはn 以下の完全なコードをコピーして貼り付けて実行します Navigator.push が AddProductPage に到達するのを待ってから、setState(() {}); を呼び出すことができます。 コードスニペット

onPressed: () async {
        await Navigator.push(context,
            MaterialPageRoute(builder: (context) => AddProductPage()));

        setState(() {});
      }),

動作デモ

完全なコード

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(),
    );
  }
}

1

あなたは私の命を救ってくれました!!完全に機能します。ありがとうございました。

– ロドリゴ・アイザック・グズムán

2020 年 9 月 3 日 19:43



------------------------

ホット リロード: ホット リロード機能 quファイルに新しく追加されたコードを素早くコンパイルし、そのコードを Dart Virtual Machine に送信します。アプリケーションで状態を使用している場合、ホット リロードでは状態が保存されるため、ホット リロード時に設定がデフォルト値に更新されません。

また、initState() は状態が保持されるため、ホット リロード後に再構築されません。したがって、データベースの変更を確認するには、ホット リスタートを実行する必要があります。

  @override
  void initState() {
    super.initState();
    helper = DbHelper();
  }

ステートフル ウィジェットがビルドされるときはヘルパーがありますが、ホット リロード後は、ヘルパーはホット リスタートと呼ばれるか、ウィジェットを起動するだけの initState と同じになります。したがって、ヘルパー変数は保存されます。したがって、ホットリスタートする必要があります。

役立つリンク: Flutter のホット リロードとホット リスタートを最も簡単な方法で理解する |参照

総合生活情報サイト - OKWAVES
総合生活情報サイト - OKWAVES
生活総合情報サイトokwaves(オールアバウト)。その道のプロ(専門家)が、日常生活をより豊かに快適にするノウハウから業界の最新動向、読み物コラムまで、多彩なコンテンツを発信。