เนื้อหาตอนต่อไปนี้จะมาแนะนำ การบันทึกข้อมูลไว้ใน app
ในรูปแบบ SQLite database โดยใช้ package ที่ชื่อว่า Sqflite
โดยเนื้อหาจะเน้นไปที่ตัวอย่างโค้ด และการประยุกต์ มากกว่า
การอธิบายทีละส่วน เพราะในการใช้งานมีรายละเอีอดค่อน
ข้างมาก ดังนั้นจึงไว้วิธีแสดงเป็นภาพรวมแทน
*เนื้อหานี้ใช้เนื้อหาต่อเนื่องจากบทความตอนที่แล้ว http://niik.in/1046
ลำดับสิ่งที่เราจะทำ
สิ่งที่จะทำเป็นแนวทางการใช้งาน คือ จะสร้างระบบจำลองการเพิ่ม ลบ แก้ไข
เกี่ยวกับรายการหนังสือ ลงในฐานข้อมูล โดยการเพิ่มข้อมูล จะไม่เริ่มไปถึงขึ้นตอน
การสร้างฟอร์มกรอกข้อมูลใดๆ แต่จะใช้ข้อมูลทดสอบ ที่มีรูปแบบถูกต้องสำหรับ
บันทึกลงฐานข้อมูล และเน้นไปที่การทำงานกับฐานข้อมูลในรูปแบบต่างๆ ทั้งการ
เพิ่ม ลบ แก้ไข แสดงรายการทั้งหมด แสดงเฉพาะรายการ ล้างข้อมูลทั้งหมด เป็นต้น
ดูตัวอย่างการทำงานตามรูป

เราเชื่อมไปยังหน้าหนังสือ เริ่มต้นจะยังไม่มีรายการใดๆ จากนั้นกดเพิ่มจำนวน 6 รายการ
จากนั้นกดแสดงรายละเอียดรายการที่ 4 กดปิด จากนั้นกดลบรายการที่ 4 ออกไป ต่อด้วย
แก้ไขรายการที่ 3 สังเกตมีคำว่า new หลังจากแก้ไข และสุดท้ายกด ลบทั้งหมด รายการหาย
ไปจากฐานข้อมูล
เตรียมพร้อมก่อนใช้งาน SQLite database
เราจะทำการติดตั้ง package ที่ชื่อว่า Sqflite สำหรับจัดการฐานข้อมูล SQLite และติดตั้ง
package ชื่อ intl สำหรับจัดการรูปแบบข้อมูลวันที่
ติดตั้ง Sqflite และ Intl
เพิ่มไปในส่วนของไฟล์ pubspec.yaml
dependencies:
sqflite: ^2.3.3+1
intl: ^0.19.0
การ import ไปใช้งาน
1 2 3 4 5 6 7 | // สำหรับ sqflite import 'package:sqflite/sqflite.dart' ; import 'package:path/path.dart' ; // สำหรับ intl import 'package:intl/date_symbol_data_local.dart' ; import 'package:intl/intl.dart' ; |
ไฟล์ที่เกี่ยวข้อง
เราจะมีไฟล์ที่เกี่ยวข้องอยู่แค่ 3 ไฟล์ ดังนี้
- lib > screen > book.dart
- lib > models > book_model.dart
- lib > db > book_db.dart
โครงสร้างและ path ของไฟล์ตามรูปแบบด้านบน ไฟล์ book.dart เราจะใช้สำหรับจำลองการทำงาน
หลังจากเตรียมส่วนของการทำงานกับฐานข้อมูล และส่วนของข้อมูลไปแล้ว
ไฟล์ book_db.dart จะเป็นไฟล์ที่รวมเกี่ยวกับฐานข้อมูลหนังสือทั้งหมด เป็นรูปแบบคำสั่งที่รองรับการ
เชื่อมต่อฐานข้อมูล สร้างตาราง เพิ่ม ลบ แก้ไข ข้อมูลในตาราง จะอยู่ในไฟล์นี้ เวลาเอาไปปรับใช้ ก็แก้ไข
เฉพาะส่วนที่ต้องการได้
ไฟล์ book_model.dart เป็นไฟล์ที่รวมการกำหนดลักษณะของข้อมูล รวมถึงฟิลด์ข้อมูลในตารางที่จะใช้
ร่วมกับไฟล์ book_db.dart
จะเขียนคำอธิบายทั้งหมดไว้ในแต่ละไฟล์
การเตรียมข้อมูล Data Model
ไฟล์ book_model.dart
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | // กำหนดชื่อตารางไว้ในตัวแปร final String tableBooks = 'books' ; // กำหนดฟิลด์ข้อมูลของตาราง class BookFields { // สร้างเป็นลิสรายการสำหรับคอลัมน์ฟิลด์ static final List<String> values = [ id, book_id, title, price, in_stock, num_pages, publication_date ]; // กำหนดแต่ละฟิลด์ของตาราง ต้องเป็น String ทั้งหมด static final String id = '_id' ; // ตัวแรกต้องเป็น _id ส่วนอื่นใช้ชื่อะไรก็ได้ static final String book_id = 'book_id' ; static final String title = 'title' ; static final String price = 'price' ; static final String in_stock = 'in_stock' ; static final String num_pages = 'num_pages' ; static final String publication_date = 'publication_date' ; } // ส่วนของ Data Model ของหนังสือ class Book { final int? id; // จะใช้ค่าจากที่ gen ในฐานข้อมูล final int book_id; final String title; final double price; final bool in_stock; final int num_pages; final DateTime publication_date; // constructor const Book({ this .id, required this .book_id, required this .title, required this .price, required this .in_stock, required this .num_pages, required this .publication_date, }); // ฟังก์ชั่นสำหรับ สร้างข้อมูลใหม่ โดยรองรับแก้ไขเฉพาะฟิลด์ที่ต้องการ Book copy({ int? id, int? book_id, String? title, double? price, bool? in_stock, int? num_pages, DateTime? publication_date, }) => Book( id: id ?? this .id, book_id: book_id ?? this .book_id, title: title ?? this .title, price: price ?? this .price, in_stock: in_stock ?? this .in_stock, num_pages: num_pages ?? this .num_pages, publication_date: publication_date ?? this .publication_date, ); // สำหรับแปลงข้อมูลจาก Json เป็น Book object static Book fromJson(Map<String, Object?> json) => Book( id: json[BookFields.id] as int?, book_id: json[BookFields.book_id] as int, title: json[BookFields.title] as String, price: double.parse(json[BookFields.price] as String), in_stock: json[BookFields.in_stock] == 1, num_pages: json[BookFields.num_pages] as int, publication_date: DateTime.parse(json[BookFields.publication_date] as String), ); // สำหรับแปลง Book object เป็น Json บันทึกลงฐานข้อมูล Map<String, Object?> toJson() => { BookFields.id: id, BookFields.book_id: book_id, BookFields.title: title, BookFields.price: price, BookFields.in_stock: in_stock ? 1 : 0, BookFields.num_pages: num_pages, BookFields.publication_date: publication_date.toIso8601String(), }; } |
สังเกตการแปลงค่า DateTime , Boolean และ Double หากนำไปประยุกต์ใช้งาน ให้ใช้แนวทาง
ตามโค้ดตัวอย่าง ตัวอย่างเช่น boolean พอแปลงเป็นข้อมูล json จะไม่มีรูปแบบข้อมูลนี้ ดังนั้นจึง
ใช้เป็น 1 กับ 0 เช่นกับกับของวันที่ ก็แปลงเป็น string
1 2 | BookFields.in_stock: in_stock ? 1 : 0, BookFields.publication_date: publication_date.toIso8601String(), |
และเวลาแปลงกลับมาจาก json เป็น object ก็ต้องแปลงเป็นชนิดข้อมูลที่กำหนดด้วย
1 2 3 4 | price: double.parse(json[BookFields.price] as String), // แปลงเป็น double in_stock: json[BookFields.in_stock] == 1, // แปลงกลับเป็น boolean num_pages: json[BookFields.num_pages] as int, publication_date: DateTime.parse(json[BookFields.publication_date] as String), |
การกำหนด id ควรกำหนดสองส่วน คือเพิ่มของ id ที่เป็นค่าจากฐานข้อมูลที่จะสร้างอัตโนมัติ
กับ id ของรายการนั้น เช่นในตัวอย่าง ก็จะมี id กับ book_id
รูปแบบการกำหนดของไฟล์ข้างต้น เวลานำไปประยุกต๋ก็แก้ไข และปรับให้เหมือนกับรูปแบบข้างต้น
มีส่วนต่างๆ ให้ครบถ้วน
การใช้งาน Sqflite จัดการฐานข้อมูล
ไฟล์ book_db.dart
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 | import 'dart:async' ; import 'package:sqflite/sqflite.dart' ; import 'package:path/path.dart' ; import '../models/book_model.dart' ; // สร้าง class จัดการข้อมูล class BooksDatabase { // กำหนดตัวแปรสำหรับอ้างอิงฐานข้อมูล static final BooksDatabase instance = BooksDatabase._init(); // กำหนดตัวแปรฐานข้อมูล static Database? _database; BooksDatabase._init(); Future<Database> get database async { // ถ้ามีฐานข้อมูลนี้แล้วคืนค่า if (_database != null ) return _database!; // ถ้ายังไม่มี สร้างฐานข้อมูล กำหนดชื่อ นามสกุล .db _database = await _initDB( 'books.db' ); // คืนค่าฐานข้อมูล return _database!; } // ฟังก์ชั่นสร้างฐานข้อมูล รับชื่อไฟล์ที่กำหนดเข้ามา Future<Database> _initDB(String filePath) async { // หาตำแหน่งที่จะจัดเก็บในระบบ ที่เตรียมไว้ให้ final dbPath = await getDatabasesPath(); // ต่อกับชื่อที่ส่งมา จะเป็น path เต็มของไฟล์ final path = join(dbPath, filePath); // สร้างฐานข้อมูล และเปิดใช้งาน หากมีการแก้ไข ให้เปลี่ยนเลขเวอร์ชั่น เพิ่มขึ้นไปเรื่อยๆ return await openDatabase(path, version: 1, onCreate: _createDB); } // สร้างตาราง Future _createDB(Database db, int version) async { // รูปแบบข้อมูล sqlite ที่รองรับ final idType = 'INTEGER PRIMARY KEY AUTOINCREMENT' ; final textType = 'TEXT NOT NULL' ; final boolType = 'BOOLEAN NOT NULL' ; final integerType = 'INTEGER NOT NULL' ; // ทำคำสั่งสร้างตาราง await db.execute( '' ' CREATE TABLE $tableBooks ( ${BookFields.id} $idType, ${BookFields.book_id} $integerType, ${BookFields.title} $textType, ${BookFields.price} $textType, ${BookFields.in_stock} $boolType, ${BookFields.num_pages} $integerType, ${BookFields.publication_date} $textType ) ' '' ); } // คำสั่งสำหรับเพิ่มข้อมูลใหม่ คืนค่าเป็น book object ที่เพิ่มไป Future<Book> create(Book book) async { final db = await instance.database; // อ้างอิงฐานข้อมูล final id = await db.insert(tableBooks, book.toJson()); return book.copy(id: id); } // คำสั่งสำหรับแสดงข้อมูลหนังสือตามค่า id ที่ส่งมา Future<Book> readBook(int id) async { final db = await instance.database; // อ้างอิงฐานข้อมูล // ทำคำสั่งคิวรี่ข้อมูลตามเงื่อนไข final maps = await db.query( tableBooks, columns: BookFields.values, where: '${BookFields.id} = ?' , whereArgs: [id], ); // ถ้ามีข้อมูล แสดงข้อมูลกลับออกไป if (maps.isNotEmpty) { return Book.fromJson(maps.first); } else { // ถ้าไม่มีแสดง error throw Exception( 'ID $id not found' ); } } // คำสั่งแสดงรายการหนึงสือทั้งหมด ต้องส่งกลับเป็น List Future<List<Book>> readAllBook() async { final db = await instance.database; // อ้างอิงฐานข้อมูล // กำหนดเงื่อนไขต่างๆ รองรับเงื่อนไขและรูปแบบของคำสั่ง sql ตัวอย่าง // ใช้แค่การจัดเรียงข้อมูล final orderBy = '${BookFields.id} DESC' ; final result = await db.query(tableBooks, orderBy: orderBy); // ข้อมูลในฐานข้อมูลปกติเป็น json string data เวลาสั่งค่ากลับต้องทำการ // แปลงข้อมูล จาก json ไปเป็น object กรณีแสดงหลายรายการก็ทำเป็น List return result.map((json) => Book.fromJson(json)).toList(); } // คำสังสำหรับอัพเดทข้อมููล ส่ง book object ที่จะอัพเดทเข้ามา Future<int> update(Book book) async { final db = await instance.database; // อ้างอิงฐานข้อมูล // คืนค่าเป็นตัวเลขจำนวนรายการที่มีการเปลี่ยนแปลง return db.update( tableBooks, book.toJson(), where: '${BookFields.id} = ?' , whereArgs: [book.id], ); } // คำสั่งสำหรับลบข้อมล รับค่า id ที่จะลบ Future<int> delete (int id) async { final db = await instance.database; // อ้างอิงฐานข้อมูล // คืนค่าเป็นตัวเลขจำนวนรายการที่มีการเปลี่ยนแปลง return db. delete ( tableBooks, where: '${BookFields.id} = ?' , whereArgs: [id], ); } // คำสั่งสำหรับลบข้อมูลทั้งหมด Future<int> deleteAll() async { final db = await instance.database; // อ้างอิงฐานข้อมูล // คืนค่าเป็นตัวเลขจำนวนรายการที่มีการเปลี่ยนแปลง return db. delete ( tableBooks, ); } // คำสั่งสำหรับปิดฐานข้อมูล เท่าที่ลองใช้ เราไม่ควรปิด หรือใช้คำสั่งนี้ // เหมือนจะเป็น bug เพราะถ้าปิดฐานข้อมูล จะอ้างอิงไม่ค่อยได้ ในตัวอย่าง // จะไม่ปิดหรือใช้คำสั่งนี้ Future close() async { final db = await instance.database; // อ้างอิงฐานข้อมูล db.close(); } } |
ในไฟล์นี้ จะเป็นการทำงานของฝั่งฐานข้อมูลทั้งหมด สามารถปรับประยุกต์ จากตัวอย่างได้เลย
เพราะรองรับการเพิ่ม ลบ แก้ไขรายการ ในกรณีแสดงทั้งหมด สามารถเลือกกำหนดจำนวน เงื่อนไข
จัดกลุ่ม เหล่านี้เพิ่มเติมได้ เช่น
1 2 3 4 5 6 7 8 | final orderBy = '${BookFields.id} DESC' ; final result = await db.query(tableBooks, orderBy: orderBy, where: 'xxxx' , // กำหนด string คำสั่งตามต้องการ groupBy: 'xxxx' , // กำหนด string คำสั่งตามต้องการ offset: 0, limit: 10, ); |
การประยุกต์ใช้งาน Sqflite
มาถึงส่วนของการประยุกต์ใช้งาน หรือการนำ คำสั่งที่จัดการกับฐานข้อมูลมาใช้งานหน้า app ที่ต้องการ
ในที่นี้เราใช้ในไฟล์ชื่อ book.dart
ไฟล์ book.dart
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 | import 'dart:async' ; import 'package:flutter/material.dart' ; import 'package:intl/date_symbol_data_local.dart' ; import 'package:intl/intl.dart' ; import '../db/book_db.dart' ; import '../models/book_model.dart' ; class Books extends StatefulWidget { static const routeName = '/book' ; const Books({Key? key}) : super (key: key); @override State<StatefulWidget> createState() { return _BooksState(); } } class _BooksState extends State<Books> { late BooksDatabase _db; // อ้างอิงฐานข้อมูล late Future<List<Book>> books; // ลิสรายการหนังสือ int i = 0; // จำลองตัวเลขการเพิ่่มจำนวน late DateFormat dateFormat; // รูปแบบการจัดการวันที่และเวลา @override void initState() { // กำหนดรูปแบบการจัดการวันที่และเวลา มีเพิ่มเติมเล็กน้อยในในท้ายบทความ Intl.defaultLocale = 'th' ; initializeDateFormatting(); dateFormat = DateFormat.yMMMMEEEEd( 'th' ); // อ้างอิงฐานข้อมูล _db = BooksDatabase.instance; books = _db.readAllBook(); // แสดงรายการหนังสือ super .initState(); } // คำสั่งลบรายการทั้งหมด Future<void> clearBook() async { await _db.deleteAll(); // ทำคำสั่งลบข้อมูลทั้งหมด setState(() { books = _db.readAllBook(); // แสดงรายการหนังสือ }); } // คำสั่งลบเฉพาะรายการที่กำหนดด้วย id ที่ต้องการ Future<void> deleteBook(int id) async { await _db. delete (id); // ทำคำสั่งลบข้มูลตามเงื่อนไข id setState(() { books = _db.readAllBook(); // แสดงรายการหนังสือ }); } // จำลองทำคำสั่งแก้ไขรายการ Future<void> editBook(Book book) async { // เลื่อกเปลี่ยนเฉพาะส่วนที่ต้องการ โดยใช้คำสั่ง copy book = book.copy( title: book.title+ ' new ' , price: 30.00, in_stock: true , num_pages: 300, publication_date: DateTime.now() ); await _db.update(book); // ทำคำสั่งอัพเดทข้อมูล setState(() { books = _db.readAllBook(); // แสดงรายการหนังสือ }); } // จำลองทำคำสั่งเพิ่มข้อมูลใหม่ Future<void> newBook() async { i++; Book book = Book( book_id: i, title: 'Book title $i' , price: 20.00, in_stock: true , num_pages: 200, publication_date: DateTime.now() ); await _db.create(book); // ทำคำสั่งเพิ่มข้อมูลใหม่ setState(() { books = _db.readAllBook(); // แสดงรายการหนังสือ }); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text( 'Book' ), actions: <Widget>[ // IconButton( onPressed: () => clearBook(), // ปุ่มลบข้อมูลทั้งหมด icon: const Icon(Icons.clear_all), ), ], ), body: Center( child: FutureBuilder<List<Book>>( // ชนิดของข้อมูล future: books, // ข้อมูล Future builder: (context, snapshot) { if (snapshot.hasData) { return Column( children: [ Expanded( // ส่วนของลิสรายการ child: snapshot.data!.isNotEmpty // กำหนดเงื่อนไขตรงนี้ ? ListView.separated( // กรณีมีรายการ แสดงปกติหนด controller ที่จะใช้งานร่วม itemCount: snapshot.data!.length, itemBuilder: (context, index) { Book book = snapshot.data![index]; Widget card; // สร้างเป็นตัวแปร card = Card( margin: const EdgeInsets.all(5.0), // การเยื้องขอบ child: Column( children: [ ListTile( leading: IconButton( onPressed: () => editBook(book), // จำลองแก้ไขข้อมูล icon: const Icon(Icons.edit), ), title: Text(book.title), subtitle: Text( 'Date: ${dateFormat.format(book.publication_date)}' ), trailing: IconButton( onPressed: () => deleteBook(book.id!), // ลบข้อมูล icon: const Icon(Icons. delete ), ), onTap: (){ _viewDetail(book.id!); // กดเลือกรายการให้แสดงรายละเอียด }, ), ], ) ); return card; }, separatorBuilder: (BuildContext context, int index) => const SizedBox(), ) : const Center(child: Text( 'No items' )), // กรณีไม่มีรายการ ), ], ); } else if (snapshot.hasError) { // กรณี error return Text( '${snapshot.error}' ); } // กรณีสถานะเป็น waiting ยังไม่มีข้อมูล แสดงตัว loading return const RefreshProgressIndicator(); }, ), ), floatingActionButton: FloatingActionButton( onPressed: () => newBook(), child: const Icon(Icons.add), ), ); } // สร้างฟังก์ชั่นจำลองการแสดงรายละเอียดข้อมูล Future<Widget?> _viewDetail(int id) async { Future<Book> book = _db.readBook(id); // ดึงข้อมูลจากฐานข้อมูลมาแสดง showModalBottomSheet( context: context, builder: (BuildContext context){ return FutureBuilder<Book>( future: book, builder: (context,snapshot){ if (snapshot.hasData) { var book = snapshot.data!; return Container( width: MediaQuery.of(context).size.width, height: 200, padding: const EdgeInsets.all(10.0), child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( 'ID: ${book.id}' ), SizedBox(height: 5,), Text( 'ชื่อหนังสือ: ${book.title}' ), SizedBox(height: 5,), Text( 'รหัส: ${book.book_id}' ), SizedBox(height: 5,), Text( 'ราคา: ${book.price}' ), SizedBox(height: 5,), Text( 'จำนวนหน้า: ${book.num_pages}' ), SizedBox(height: 5,), Text( 'มีในคลัง: ${ book.in_stock ? ' มี ' : ' ไม่มี '}' ), SizedBox(height: 5,), Text( 'วันที่: ${dateFormat.format(book.publication_date)}' ), ], ), ); } else if (snapshot.hasError) { // กรณี error return Text( '${snapshot.error}' ); } return const RefreshProgressIndicator(); } ); } ); return null ; } } |
เพิ่มปุ่มลิ้งค์มาหน้า book ในไฟล์ about.dart
มีสองส่วนคือ import book.dart
และ ส่วนของการกำหนดปุ่ม
1 | import './book.dart' ; |
และ ส่วนของการกำหนดปุ่ม
1 2 3 4 5 6 7 8 9 10 11 12 13 | ElevatedButton( onPressed: () { /* Navigator.pushNamed( context, Books.routeName ); */ Navigator.push( context, MaterialPageRoute(builder: (context) => Books()), ); }, child: Text( 'Go to Book' ), ), |
ในตัวอย่าง เรามีการใช้งานฐานข้อมูล จากไฟล์ book_db.dart ที่มีคำสั่งต่างๆ ที่เรากำหนดไว้แล้ว
โดยกำหนดตัวแปรชื่อ _db = BooksDatabase.instance; สำหรับอ้างอิงฐานข้อมูล สำหรับขอมูลที่ได้
จากการแสดงรายการทั้งหมด หรือแสดงบางรายการตาม id ที่กำหนด จะเป็นข้อมูล Future เวลาแสดง
เราจึงใช้ FutureBuilder มาใช้งานร่วมด้วย
เมื่อเริ่มทำงาน เราจะทำการไปอ่านข้อมูลจากฐานข้อมูล ว่ามีรายการหนังสืออยู่หรือไม่ ถ้ามีก็คืนค่า
กลับมาใช้งาน ถ้าไม่มีก็แสดงข้อความ 'No items'
เราจำลองเมื่อกดปุ่มเครื่องหมายบวก + ก็ให้ทำการเพิ่มข้อมูลลงในฐานข้อมูล หลังจากเพิ่มก็อัพเดท
รายการข้อมูล ก็จะเห็นว่ามีรายการใหม่เพิ่มเข้ามาด้านบน
เมื่อกดที่รายการใดๆ ก็จะไปดึงข้อมูลจากฐานข้อมูล ของรายการนั้นๆ มาแสดง จริงๆ ถ้าข้อมูลใน
snapshot มีข้อมูลทั้งหมดแล้ว เราไม่จำเป็นต้องไปดึงจากฐานข้อมูลก็ได้ สามารถส่งค่ามาแสดงได้เลย
แต่ในที่นี้ เราจำลองสมมติว่า ต้องการไปดึงข้อมูลทั้งหมดจากฐานข้อมูลมาแสดงแทนการส่งค่า
เราสามารถลบราายการทั้งหมด โดยคลิกที่ปุ่ม action มุมบนขวา
การลบ และแก้ไขแต่ละรายการ สามารถกดที่ไอคอน ด้านหน้า และด้านหลังแต่ละรายการตามลำดับ
การจัดรูปแบบวันที่ด้วย intl package
เราสามารถจัดรูปแบบการแสดงข้อมูลวันที่หรือ DateTime ด้วย package ชื่อ intl ที่ได้ติดตั้งไปตอนต้น
ซึ่งรองรับการกำหนดและแสดงเป็นภาษาไทย มีรูปแบบการใช้งานไม่ยุ่งยาก
ตัวอย่างการกำหนดรูปแบบโดยใช้ค่าคงที่
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 | DateFormat.MMMM( 'th' ), : พฤศจิกายน DateFormat.MMMMd( 'th' ), : 6 พฤศจิกายน DateFormat.MMMMEEEEd( 'th' ), : วันเสาร์ที่ 6 พฤศจิกายน DateFormat.M( 'th' ), : 11 DateFormat.Md( 'th' ), : 6/11 DateFormat.MEd( 'th' ), : ส. 6/11 DateFormat.s( 'th' ), : 16 DateFormat.LLLL( 'th' ), : พฤศจิกายน DateFormat.EEEE( 'th' ), : วันเสาร์ DateFormat.y( 'th' ), : 2021 DateFormat.yMMM( 'th' ), : พ.ย. 2021 DateFormat.yMMMd( 'th' ), : 6 พ.ย. 2021 DateFormat.yMMMEd( 'th' ), : ส. 6 พ.ย. 2021 DateFormat.yQQQ( 'th' ), : ไตรมาส 4 2021 DateFormat.yMMMM( 'th' ), : พฤศจิกายน ค.ศ. 2021 DateFormat.yMMMMEEEEd( 'th' ), : วันเสาร์ที่ 6 พฤศจิกายน ค.ศ. 2021 DateFormat.yMMMMd( 'th' ), : 6 พฤศจิกายน ค.ศ. 2021 DateFormat.yM( 'th' ), : 11/2021 DateFormat.yMd( 'th' ), : 6/11/2021 DateFormat.yMEd( 'th' ), : ส. 6/11/2021 DateFormat.yQQQQ( 'th' ), : ไตรมาส 4 ค.ศ. 2021 DateFormat.MMM( 'th' ), : พ.ย. DateFormat.MMMd( 'th' ), : 6 พ.ย. DateFormat.MMMEd( 'th' ), : ส. 6 พ.ย. DateFormat.QQQ( 'th' ), : ไตรมาส 4 DateFormat.LLL( 'th' ), : พ.ย. DateFormat.E( 'th' ), : ส. DateFormat.d( 'th' ), : 6 DateFormat.m( 'th' ), : 52 DateFormat.ms( 'th' ), : 52:16 DateFormat.j( 'th' ), : 17 DateFormat.H( 'th' ), : 17 DateFormat.Hm( 'th' ), : 17:45 น. DateFormat.Hms( 'th' ), : 17:45:10 DateFormat.jm( 'th' ), : 17:49 น. DateFormat.jms( 'th' ), : 17:49:25 |
ตัวอย่างเช่น เรากำหนดเป็น
1 2 3 4 | // กำหนดรูปแบบการจัดการวันที่และเวลา มีเพิ่มเติมเล็กน้อยในในท้ายบทความ Intl.defaultLocale = 'th' ; initializeDateFormatting(); dateFormat = DateFormat.yMMMd( 'th' ); |
ผลลัพธ์ที่ได้

หรือกรณีเราต้องการรูปแบบที่มีข้อความกำหนดเอง เช่น
1 2 3 4 5 | // กำหนดรูปแบบการจัดการวันที่และเวลา มีเพิ่มเติมเล็กน้อยในในท้ายบทความ Intl.defaultLocale = 'th' ; initializeDateFormatting(); // dateFormat = DateFormat.yMMMd('th'); dateFormat = DateFormat( 'วันที่ d เดือน MMM ปี y' , 'th' ); |
จะได้เป็น

หวังว่าเนื้อหาตอนนี้ จะสามารถเป็นแนวทางนำไปปรับใช้งาน เช่น ต้องการให้ app สามารถทำงาน
ออฟไลน์ได้ โดยบันทึกลงในฐานข้อมูลไว้ และเมื่ออนไลน์หรือเชื่อมต่ออินเตอร์เน็ตก็สามารถ sync ข้อมูล
ขึ้นไปเก็บบน server ได้ หรือจะใช้เก็บข้อมูล cache เช่น ดึงข้อมูลจาก server กรณีที่ออนไลน์อยู่ มาเก็บ
บันทึกในฐานข้อมูล เมื่อออฟไลน์ก็ใช้ข้อมูลในฐานข้อมูลที่เครื่อง แบบนี้เป็นต้น
เนื้อหาตอนหน้าเป็นอะไร รอติดตาม