Strapi助力Flutter开发国际化App - 使用Sqlite数据库

https://pub.dev/packages/floor

在Flutter项目中配置依赖库的引用pubspec.yaml

dependencies:
  flutter:
    sdk: flutter
  floor: ^1.2.0

dev_dependencies:
  floor_generator: ^1.2.0
  build_runner: ^2.1.2

创建实体与视图[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;
}

具体详情可参考 https://floor.codes/database-...

根据视图创建"Data Access Objects"[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> findAll();
}

创建Database管理类[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;
}

运行Floor的代码生成器

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)

这里会生成一个与database.dart同目录的database.g.dart

使用GetX的Service方案创建db的service [project_root]/lib/app/common/services/db_service.dart.dart

这里要特别注意一下

和Floor官方的文档介绍不同,Floor会根据实体生成一个sqlite数据库,我这里会将现有的数据库文件提供给Floor使用不生成新的数据库文件。

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 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 bytes =
        data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
    await File(dbPath).writeAsBytes(bytes);

    db = await $FloorAppDatabase
        .databaseBuilder(dbPath)
        .addCallback(callback)
        .build();
    return this;
  }
}

实例化DbService [project_root]/lib/main.dart

Future main() async {
  WidgetsFlutterBinding.ensureInitialized();
  await initServices();

  runApp(
    GetMaterialApp(
      title: "Application",
      initialRoute: AppPages.INITIAL,
      getPages: AppPages.routes,
    ),
  );
}

Future initServices() async {
  print('starting services ...');
  await Get.putAsync(() => DbService().init());
  print('All services started...');
}

修改home_controller代码读取Sqlite数据库 [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>([]);

  @override
  void onInit() {
    super.onInit();
  }

  @override
  void onReady() {
    super.onReady();
  }

  Future getAllVegetables() async {
    final result = await DbService.to.db.vegetableDao.findAll();
    vegetables.value = result;
  }

  @override
  void onClose() {}
}

简单测试一下

controller.getAllVegetables();

  Future getAllVegetables() async {
    final result = await DbService.to.db.vegetableDao.findAll();
    vegetables.value = result;
    print(result);
  }

得到

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']

成功! 数据都读取出来了。

使用GetX的Obx特性把数据显示到界面上

import 'package:flutter/material.dart';

import 'package:get/get.dart';
import '../controllers/home_controller.dart';

class HomeView extends GetView {
  @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,
                          ),
                        ],
                      ),
                    ),
                  ],
                ),
              ),
            );
          })),
    );
  }
}

Strapi助力Flutter开发国际化App - 使用Sqlite数据库_第1张图片


上一篇:整理Sqlite数据库与图片

你可能感兴趣的