is there any way to save data locally when app closed - flutter

the app works with sqlite database and it shows the data that exits in the assets very fine even though when the app closed those data is still there , the problem is when connecting with server and loading data it is saved and displayed in the app very fine but only when the app running , if the app closed every thing lost and I just found the data that already exists in assets from the beginning .
how I can save the data that loading from the server in local database even if the app is closed?
here is my database initialize function
Future<Database> initDb() async {
if (kIsWeb) {
try {
} catch (_) {}
// Set web-specific directory Here
} else {
Directory documentDirectory = await getApplicationDocumentsDirectory();
String path = join(documentDirectory.path, "data_4us.db");
// Load database from asset and copy
ByteData data = await rootBundle.load(join('data', '4us.db'));
List<int> bytes =
data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
// Save copied asset to documents
await new File(path).writeAsBytes(bytes);
var ourDb = await openDatabase(path);
return ourDb;
} }

Ok guys, I think I solve the problem
I just add this if statement to check the existing of the database
if (FileSystemEntity.typeSync(path) == FileSystemEntityType.notFound){ }
now everything is fine.
thank you .

Related

Writing to file in Flutter multiple times updates the file. Reading from the file always gives me the initial content

SOLVED FOR MY SITUATION. MORE INFORMATION HERE AND THEN ORIGINAL QUESTION BELOW.
===Solution===
Due to settings with Android external storage, the file_picker plugin creates a cache of the file you pick and stores it in a cache directory within the app storage location. It will not overwrite this for files with the same name on subsequent reads. So for my read/write app, the solution was to do await file.delete(); when I was done with the read operation. This ensures that the next read will then create a cached version with the updated contents
===Original Question===
I have some content in a database on a Flutter app I am using to just practice some new stuff in FLutter. I have an export button that gets this data, JSON encodes it, and writes it to a file.
If I change the content and then export a second time, I can open the file on my device and see the updated content. I also have an import button. When I press that, I use FilePicker to select a file, read the contents of the file, and then JSON decode the data into an object.
I print out the file.readAsString and see the content from the initial write.
If I manually delete the file between writes then it works. If I use file.delete() before the write, it does not work. What can I do to get the updated text when I read from the file?
Getting file to write to. (I am aware this will only work on Android as is and that's fine)
Future<File?> _getBackupDataFile(String pathToTryFirst, ExportData data) async {
Directory? directory = Directory(pathToTryFirst);
if (!await directory.exists()) directory = await getExternalStorageDirectory();
if ((await directory?.exists() ?? false) == false) {
showErrorDialog(context: context, body: "Unable to find directory to save file.");
return null;
}
return File("${directory?.path}/pm-account-backup.json");
}
Write to file as such (without the delete code):
Future<void> _writeDataToFile(ExportData data) async {
try {
File? file = await _getBackupDataFile('/storage/emulated/0/Download', data);
if(file == null) { return; }
await file.writeAsString(jsonEncode(data));
await showSuccessDialog(context: context, title: "Success", body: "${data.accounts.length} accounts backed up successfully.");
} catch (e) {
showErrorDialog(context: context, body: "Failed to write data to file.");
}
}
Simplified file pick:
FilePickerResult? result = await FilePicker.platform.pickFiles();
if (result != null) {
String path = result.files.single.path ?? '';
if((path).endsWith(".json")) {
return File(path);
}
}
Read from file as such:
String fileData = await file.readAsString();
print(fileData);
Solution for my question found after more information provided by #pskink
Due to settings with Android external storage, the file_picker plugin creates a cache of the file you pick and stores it in a cache directory within the app storage location. It will not overwrite this for files with the same name on subsequent reads. So for my read/write app, the solution was to do await file.delete(); when I was done with the read operation. This ensures that the next read will then create a cached version with the updated contents

File stored in app document directory always exists although it hasn't been created (Flutter)

I am currently developing a mobile app with flutter and I want to display the profile picture of a user and their friends.
The pictures are stored in Firebase Storage, but to minimize the number of requests I want to load each image once and then store it locally.
I wrote a function to get the image from Firebase storage and store it in the app document directory, but I can't figure out how to execute the function only when the file doesn't already exist locally.
This is an excerpt of my code
Future<File?> getProfilePic(String? uid) async {
Directory appDocumentsDirectory = await getApplicationDocumentsDirectory();
String filepath = "${appDocumentsDirectory.path}/profiles/$uid.jpg";
if (await File(filepath).exists()) {
return File(filepath);
} else {
var success = await downloadFromFirebaseAndSaveToLocal(
"profilepic/$uid.jpg", filepath);
if (success) {
getProfilePic(uid);
}
}
return null;
}
Somehow the condition of the if statement (await File(filepath).exists()) is always true. I guess it makes sense. I think the file exists in the directory but doesn't have any content.
Does anyone know how to check if the file has content?
A normal null check doesn't work.
Thank you for helping!
To check the size of the file, you can
if (File(filepath).lengthSync() != 0)
or
You can await the file.length()

Flutter Desktop App (MacOS) - Unable to find SQLITE DB and creates empty db in MacOS /Users/<user>/Documents directory

There's some very odd problems when using flutter for MacOs apps.
I'm using the following Database initialisation:
_initDatabase() async {
Directory dbDirectory = await getApplicationDocumentsDirectory();
String path = join(dbDirectory.path, _databaseName);
//ByteData data = await rootBundle.load("assets/mydatabase.sqlite");
//List<int> bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
//await File(path).writeAsBytes(bytes);
return await openDatabase(path,
version: _databaseVersion,
//onCreate: _onCreate
);}
What is the issue?
I keep on getting error that it cannot find the table. The table absolutely exists.
But then I checked the logs and it appears it is using the /Users/myname/Documents to store the database file.
that's not what I want. The database file for this application is in the assets folder, and it should remain (when it is packaged) within the app bundle.
How do I specify the assets folder??
What am I doing wrong??
The create function, by the way, isn't working either.
Future _onCreate(Database db, int version) async {
await db.execute('''
CREATE TABLE $table (
$columnId INTEGER PRIMARY KEY,
$col1 TEXT,
$col2 TEXT,
$col3 TEXT
)
''');}
Im exhausted from trying...

Where is my sqflite database stored inside Flutter app?

I'm creating an encrypted sqflite database with sqflite_sqlcipher and would like to open it with the DB Browser for SQLCipher. For that i only need to find my .db file but I can't seem to figure out where this file is stored inside my app.
I have printed the path to the db in my init function and the output is below:
Future<Database> _initDatabase() async {
print("Database path: ${await getDatabasesPath()}");
final dbPath = await getDatabasesPath();
final path = join(dbPath, "documents.db");
final pw = await getPassword();
return await openDatabase(
path,
password: pw,
version: 1,
onCreate: _onCreate,
);
}
Database path: /data/user/0/com.example.did/databases
You could access it using Android Studio, look for Device File Manager and from there, you can access the file path.

Copying .sqlite db to documents directory on Phone

I have a routine that copies a local SQLite database (from the Android Studio Assets folder) to the phone's document directory.
The problem I have is that this code is not very good. Sometimes the database is copied completely, and sometimes it is copied partially, or not at all. Its very buggy and I have no idea on how to improve on it.
Many times I get an error saying that certain tables cannot be found.
Here is the code that Im using:
copyDB() async
{
// Construct a file path to copy database to
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, DBAssistanceClass.databaseName);
print('The DB path is: '+ path);
// Only copy if the database doesn't exist
if (FileSystemEntity.typeSync(path) == FileSystemEntityType.notFound)
{
try
{
print('Copying DB...');
// Load database from asset and copy
ByteData data = await rootBundle.load(
join('assets', DBAssistanceClass.databaseName));
List<int> bytes = data.buffer.asUint8List(data.offsetInBytes, data.lengthInBytes);
// Save copied asset to documents
await File(path).writeAsBytes(bytes);
}
catch (error)
{
print(error);
}
}
}
This is for flutter, and I cannot find anything at all in dart documentation to assist.
I think if it is important to flush when you write the file. There is an Opening an asset database document in sqflite with a complete example.