0

I am trying to access a static database that is stored in assets using this answer. I therefore set up my main() function like this:

main() async {
  // Construct a file path to copy database to
  Directory documentsDirectory = await getApplicationDocumentsDirectory();
  String path = join(documentsDirectory.path, "asset_worldcities.db");

  // Only copy if the database doesn't exist
  if (FileSystemEntity.typeSync(path) == FileSystemEntityType.notFound) {
    // Load database from asset and copy
    ByteData data = await rootBundle.load(join('assets', 'worldcities.db'));
    List<int> bytes = data.buffer.asUint8List(
        data.offsetInBytes, data.lengthInBytes);

    // Save copied asset to documents
    await new File(path).writeAsBytes(bytes);
  }
  Directory appDocDir = await getApplicationDocumentsDirectory();
  String databasePath = join(appDocDir.path, 'asset_database.db');
  this.db = await openDatabase(databasePath);
  initialized = true;
  runApp(Globeye());
}

However this seems not to be allowed as Android Studio marks this as illegal reference and also complains about that the name initialize is undefined. How can I correctly set this up?

Axel
  • 1,415
  • 1
  • 16
  • 40

1 Answers1

1

You can copy paste run full code below
You can use DatabaseHelper to do this
code snippet

class DatabaseHelper {
  static final DatabaseHelper _instance = DatabaseHelper.internal();
  factory DatabaseHelper() => _instance;

  static Database _db;

  Future<Database> get db async {
    if (_db != null) {
      return _db;
    }
    _db = await initDb();
    return _db;
  }

  DatabaseHelper.internal();

  initDb() async {
    var databasesPath = await getDatabasesPath();
    var path = join(databasesPath, "asset_database.db");
    print(path);
    // delete existing if any
    await deleteDatabase(path);

    // Make sure the parent directory exists
    try {
      await Directory(dirname(path)).create(recursive: true);
    } catch (_) {}

    // Copy from asset
    ByteData data = await rootBundle.load(join("assets", "worldcities.db"));
    List<int> bytes =
        data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
    await File(path).writeAsBytes(bytes, flush: true);

    // open the database
    var db = await openDatabase(path);
    return db;
  }
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  Database db = await DatabaseHelper().db;
  print(db.path);
  runApp(MyApp());
}

output

I/flutter ( 6569): /data/user/0/yourdomain.projecct/databases/asset_database.db
I/flutter ( 6569): /data/user/0/yourdomain.projecct/databases/asset_database.db

full code

import 'dart:io';

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';

class DatabaseHelper {
  static final DatabaseHelper _instance = DatabaseHelper.internal();
  factory DatabaseHelper() => _instance;

  static Database _db;

  Future<Database> get db async {
    if (_db != null) {
      return _db;
    }
    _db = await initDb();
    return _db;
  }

  DatabaseHelper.internal();

  initDb() async {
    var databasesPath = await getDatabasesPath();
    var path = join(databasesPath, "asset_database.db");
    print(path);
    // delete existing if any
    await deleteDatabase(path);

    // Make sure the parent directory exists
    try {
      await Directory(dirname(path)).create(recursive: true);
    } catch (_) {}

    // Copy from asset
    ByteData data = await rootBundle.load(join("assets", "worldcities.db"));
    List<int> bytes =
        data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
    await File(path).writeAsBytes(bytes, flush: true);

    // open the database
    var db = await openDatabase(path);
    return db;
  }
}

void main() async {
  WidgetsFlutterBinding.ensureInitialized();
  Database db = await DatabaseHelper().db;
  print(db.path);
  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: MyHomePage(title: 'Flutter Demo Home Page'),
    );
  }
}

class MyHomePage extends StatefulWidget {
  MyHomePage({Key key, this.title}) : super(key: key);

  final String title;

  @override
  _MyHomePageState createState() => _MyHomePageState();
}

class _MyHomePageState extends State<MyHomePage> {
  int _counter = 0;

  void _incrementCounter() {
    setState(() {
      _counter++;
    });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text(widget.title),
      ),
      body: Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: <Widget>[
            Text(
              'You have pushed the button this many times:',
            ),
            Text(
              '$_counter',
              style: Theme.of(context).textTheme.headline4,
            ),
          ],
        ),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: _incrementCounter,
        tooltip: 'Increment',
        child: Icon(Icons.add),
      ),
    );
  }
}
chunhunghan
  • 51,087
  • 5
  • 102
  • 120
  • Thanks for your answer! Can I then pass the `db` variable to the `MyApp` class to display data from the database? – Axel Oct 16 '20 at 19:54
  • 1
    You do not need to pass. it's a singleton. every time you call Database db = await DatabaseHelper().db; you will get db instance from cache of singleton. – chunhunghan Oct 19 '20 at 00:43
  • Thanks for reply! – Axel Oct 20 '20 at 13:54