เนื้อหาตอนต่อไปนี้จะมาแนะนำ การบันทึกข้อมูลไว้ใน 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 ไปใช้งาน
// สำหรับ 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
// กำหนดชื่อตารางไว้ในตัวแปร 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
BookFields.in_stock: in_stock ? 1 : 0, BookFields.publication_date: publication_date.toIso8601String(),
และเวลาแปลงกลับมาจาก json เป็น object ก็ต้องแปลงเป็นชนิดข้อมูลที่กำหนดด้วย
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
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(); } }
ในไฟล์นี้ จะเป็นการทำงานของฝั่งฐานข้อมูลทั้งหมด สามารถปรับประยุกต์ จากตัวอย่างได้เลย
เพราะรองรับการเพิ่ม ลบ แก้ไขรายการ ในกรณีแสดงทั้งหมด สามารถเลือกกำหนดจำนวน เงื่อนไข
จัดกลุ่ม เหล่านี้เพิ่มเติมได้ เช่น
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
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
และ ส่วนของการกำหนดปุ่ม
import './book.dart';
และ ส่วนของการกำหนดปุ่ม
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 ที่ได้ติดตั้งไปตอนต้น
ซึ่งรองรับการกำหนดและแสดงเป็นภาษาไทย มีรูปแบบการใช้งานไม่ยุ่งยาก
ตัวอย่างการกำหนดรูปแบบโดยใช้ค่าคงที่
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
ตัวอย่างเช่น เรากำหนดเป็น
// กำหนดรูปแบบการจัดการวันที่และเวลา มีเพิ่มเติมเล็กน้อยในในท้ายบทความ Intl.defaultLocale = 'th'; initializeDateFormatting(); dateFormat = DateFormat.yMMMd('th');
ผลลัพธ์ที่ได้
หรือกรณีเราต้องการรูปแบบที่มีข้อความกำหนดเอง เช่น
// กำหนดรูปแบบการจัดการวันที่และเวลา มีเพิ่มเติมเล็กน้อยในในท้ายบทความ Intl.defaultLocale = 'th'; initializeDateFormatting(); // dateFormat = DateFormat.yMMMd('th'); dateFormat = DateFormat('วันที่ d เดือน MMM ปี y','th');
จะได้เป็น
หวังว่าเนื้อหาตอนนี้ จะสามารถเป็นแนวทางนำไปปรับใช้งาน เช่น ต้องการให้ app สามารถทำงาน
ออฟไลน์ได้ โดยบันทึกลงในฐานข้อมูลไว้ และเมื่ออนไลน์หรือเชื่อมต่ออินเตอร์เน็ตก็สามารถ sync ข้อมูล
ขึ้นไปเก็บบน server ได้ หรือจะใช้เก็บข้อมูล cache เช่น ดึงข้อมูลจาก server กรณีที่ออนไลน์อยู่ มาเก็บ
บันทึกในฐานข้อมูล เมื่อออฟไลน์ก็ใช้ข้อมูลในฐานข้อมูลที่เครื่อง แบบนี้เป็นต้น
เนื้อหาตอนหน้าเป็นอะไร รอติดตาม