DEV Community

Cover image for How to create a Offline Internationalization App:Use Sqlite database
nasa.wang
nasa.wang

Posted on • Edited on

How to create a Offline Internationalization App:Use Sqlite database

https://pub.dev/packages/floor

Configure the reference pubspec.yaml of the dependent library in the Flutter project

dependencies: flutter: sdk: flutter floor: ^1.2.0 dev_dependencies: floor_generator: ^1.2.0 build_runner: ^2.1.2 
Enter fullscreen mode Exit fullscreen mode

Create entity and view [project_root]/lib/app/data/entity/vegetalbe.dart

import 'package:floor/floor.dart'; @Entity(tableName: "vegetables") class Vegetable { @PrimaryKey(autoGenerate: true) final int? id; final String name; final String locale; final String desc; @ColumnInfo(name: 'created_at') final int createTime; @ColumnInfo(name: 'updated_at') final int updateTime; Vegetable( this.id, this.name, this.locale, this.desc, { int? createTime, int? updateTime, }) : this.createTime = createTime ?? DateTime.now().millisecondsSinceEpoch, this.updateTime = updateTime ?? DateTime.now().millisecondsSinceEpoch; } @DatabaseView( 'SELECT v.id, v.name, v.desc, v.locale, uf.hash, uf.ext, v.created_at, v.updated_at from vegetables v LEFT OUTER JOIN upload_file_morph ufm on v.id = ufm.related_id LEFT OUTER JOIN upload_file uf on ufm.upload_file_id = uf.id;', viewName: "vegetables_v") class VegetableV { final int id; final String name; final String locale; final String? desc; final String? hash; final String? ext; @ColumnInfo(name: 'created_at') final int createTime; @ColumnInfo(name: 'updated_at') final int updateTime; VegetableV( this.id, this.name, this.locale, this.desc, this.hash, this.ext, { int? createTime, int? updateTime, }) : this.createTime = createTime ?? DateTime.now().millisecondsSinceEpoch, this.updateTime = updateTime ?? DateTime.now().millisecondsSinceEpoch; } 
Enter fullscreen mode Exit fullscreen mode

For specific details, please refer to https://floor.codes/database-views/

Create "Data Access Objects" according to the view[project_root]/lib/app/data/dao/vegetalbe_dao.dart

import 'package:floor/floor.dart'; import 'package:strapi_flutter_internation_poc/app/data/entity/vegetable.dart'; @dao abstract class VegetableDao { @Query('SELECT * FROM vegetables_v') Future<List<VegetableV>> findAll(); } 
Enter fullscreen mode Exit fullscreen mode

Create Database management class [project_root]/lib/app/data/database.dart

import 'dart:async'; import 'package:floor/floor.dart'; import 'package:sqflite/sqflite.dart' as sqflite; // daos import 'dao/vegetable_dao.dart'; // entitys import 'entity/vegetable.dart'; part 'database.g.dart'; // the generated code will be there @Database(version: 1, entities: [Vegetable], views: [VegetableV]) abstract class AppDatabase extends FloorDatabase { VegetableDao get vegetableDao; } 
Enter fullscreen mode Exit fullscreen mode

Run Floor's code generator

flutter packages pub run build_runner build [INFO] Generating build script... [INFO] Generating build script completed, took 480ms [INFO] Initializing inputs [INFO] Reading cached asset graph... [INFO] Reading cached asset graph completed, took 67ms [INFO] Checking for updates since last build... [INFO] Checking for updates since last build completed, took 651ms [INFO] Running build... [INFO] 1.1s elapsed, 0/1 actions completed. [INFO] 2.2s elapsed, 0/1 actions completed. [INFO] 4.0s elapsed, 0/1 actions completed. [INFO] 8.4s elapsed, 0/1 actions completed. [INFO] Running build completed, took 8.8s [INFO] Caching finalized dependency graph... [INFO] Caching finalized dependency graph completed, took 34ms [INFO] Succeeded after 8.8s with 2 outputs (2 actions) 
Enter fullscreen mode Exit fullscreen mode

This will generate a database.g.dart in the same directory as database.dart

Use GetX's Service scheme to create db service [project_root]/lib/app/common/services/db_service.dart.dart

Please pay special attention here

Unlike the official documentation of Floor, Floor will generate a sqlite database based on the entity. I will provide the existing database files to Floor for use without generating new database files.

import 'dart:io'; import 'package:get/get.dart'; import 'package:path/path.dart'; import 'package:floor/floor.dart'; import 'package:flutter/services.dart'; import 'package:sqflite/sqflite.dart'; import 'package:strapi_flutter_internation_poc/app/data/database.dart'; class DbService extends GetxService { static DbService get to => Get.find(); late AppDatabase db; Future<DbService> init() async { final callback = Callback( onCreate: (database, version) {}, onOpen: (database) { print('onOpen database'); getDatabasesPath().then((value) => print(value)); }, onUpgrade: (database, startVersion, endVersion) {}, ); var dbDir = await getDatabasesPath(); var dbPath = join(dbDir, "app_database.db"); await deleteDatabase(dbPath); ByteData data = await rootBundle.load("assets/db/data.db"); List<int> bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes); await File(dbPath).writeAsBytes(bytes); db = await $FloorAppDatabase .databaseBuilder(dbPath) .addCallback(callback) .build(); return this; } } 
Enter fullscreen mode Exit fullscreen mode

Instantiate DbService [project_root]/lib/main.dart

Future<void> main() async { WidgetsFlutterBinding.ensureInitialized(); await initServices(); runApp( GetMaterialApp( title: "Application", initialRoute: AppPages.INITIAL, getPages: AppPages.routes, ), ); } Future<void> initServices() async { print('starting services ...'); await Get.putAsync(() => DbService().init()); print('All services started...'); } 
Enter fullscreen mode Exit fullscreen mode

Modify the home_controller code to read the Sqlite database [project_root]/lib/app/modules/home/controllers/home_controller.dart

import 'package:get/get.dart'; import 'package:strapi_flutter_internation_poc/app/common/services/db_service.dart'; import 'package:strapi_flutter_internation_poc/app/data/entity/vegetable.dart'; class HomeController extends GetxController { final vegetables = Rx<List<VegetableV>>([]); @override void onInit() { super.onInit(); } @override void onReady() { super.onReady(); } Future<void> getAllVegetables() async { final result = await DbService.to.db.vegetableDao.findAll(); vegetables.value = result; } @override void onClose() {} } 
Enter fullscreen mode Exit fullscreen mode

Test it briefly

controller.getAllVegetables(); Future<void> getAllVegetables() async { final result = await DbService.to.db.vegetableDao.findAll(); vegetables.value = result; print(result); } 
Enter fullscreen mode Exit fullscreen mode

out

I/flutter ( 7396): starting services ... I/flutter ( 7396): onOpen database I/flutter ( 7396): /data/user/0/com.nasawz.strapi_flutter_internation_poc.strapi_flutter_internation_poc/databases I/flutter ( 7396): All services started... [GETX] Instance "DbService" has been created [GETX] Instance "DbService" has been initialized [GETX] Instance "GetMaterialController" has been created [GETX] Instance "GetMaterialController" has been initialized [GETX] GOING TO ROUTE /home [GETX] Instance "HomeController" has been created [GETX] Instance "HomeController" has been initialized I/flutter ( 7396): [Instance of 'VegetableV', Instance of 'VegetableV', Instance of 'VegetableV', Instance of 'VegetableV', Instance of 'VegetableV', Instance of 'VegetableV', Instance of 'VegetableV', Instance of 'VegetableV'] 
Enter fullscreen mode Exit fullscreen mode

success! The data is read out.

Use GetX's Obx feature to display data on the interface

import 'package:flutter/material.dart'; import 'package:get/get.dart'; import '../controllers/home_controller.dart'; class HomeView extends GetView<HomeController> { @override Widget build(BuildContext context) { controller.getAllVegetables(); return Scaffold( appBar: AppBar( title: Text('Vegetables'), centerTitle: true, ), body: Obx(() => ListView.builder( itemCount: controller.vegetables.value.length, itemBuilder: (context, index) { var vegetable = controller.vegetables.value[index]; return Padding( padding: const EdgeInsets.all(18.0), child: Container( child: Row( children: [ Container( // color: Colors.red, child: Image.asset( 'strapi/public/uploads/thumbnail_${vegetable.hash}${vegetable.ext}', fit: BoxFit.contain, width: 140, height: 140, ), ), Container( width: Get.width - 18 * 2 - 140 - 18, child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( vegetable.name, style: Get.textTheme.headline6, ), Text( vegetable.desc!, style: Get.textTheme.subtitle1, maxLines: 1, overflow: TextOverflow.ellipsis, ), ], ), ), ], ), ), ); })), ); } } 
Enter fullscreen mode Exit fullscreen mode

image-20211010135908-5m68k62


Image description

Play Store

Apple Store

Top comments (0)