How to fix slow issue storing cache? - sqlite

Response time is 18 seconds but storing to cache time is 3 minutes. Why is that? I used sqflite plugin to store data.
This is my function calling server with an insert to cache
storeWoDescription(String url,String token) async {
final response = await http.get(
'${url}/v1.0/WoDescription',
headers: {'Authorization': 'Bearer ${token}'},);
final jsonResponse = json.decode(response.body);
WoDescription model = WoDescription.fromJson(jsonResponse);
int length = model.data.length;
for(int i=0; i<length; i++) {
var data = DataWoDescription(
i: model.data[i].i,
d: model.data[i].d,
e: model.data[i].e,
w: model.data[i].w,
a: model.data[i].a,
r: model.data[i].r,
t: model.data[i].t,
du: model.data[i].du,
s: model.data[i].s,
ra: model.data[i].ra,
cul: model.data[i].cul,
);
await HelperDefCatMaster().insertWoDescription(data);
}
}
after click button calling like this:
await storeWoDescription(_url,tokens);
HelperDefCatMaster
this is my database provider. I created multiple tables in one database. and before insert, I deleted the database and after that I inserted.
class HelperDefCatMaster {
static final HelperDefCatMaster _instance = HelperDefCatMaster.internal();
factory HelperDefCatMaster() => _instance;
static Database _db;
Future<Database> get db1 async {
if (_db != null) return _db;
_db = await initDb();
return _db;
}
HelperDefCatMaster.internal();
initDb() async {
io.Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, "HelperDefCatMasterDB.db");
var theDb = await openDatabase(path, version: 1, onCreate: _onCreate);
return theDb;
}
void _onCreate(Database db, int version) async {
await db.execute(
"""CREATE TABLE WoDescriptionTable(i INTEGER, d STRING, e INTEGER, w STRING, a INTEGER, r INTEGER, t INTEGER, du DOUBLE, s INTEGER, ra INTEGER, cul INTEGER)""");
}
Future<void> insertWoDescription(DataWoDescription assetregister) async {
var db = await db1;
await db.insert(
'WoDescriptionTable',
assetregister.toMap()
// conflictAlgorithm: ConflictAlgorithm.replace,
);
}
Future<void> deleteWoDescription() async {
var db = await db1;
await db.delete('WoDescriptionTable');
}
Future<List<DataWoDescription>> displayWoDescription() async {
var db = await db1;
final List<Map<String, dynamic>> maps = await db.query('WoDescriptionTable');
return List.generate(maps.length, (i) {
return DataWoDescription(
i: maps[i]['i'],
d: '${maps[i]['d']}',
e: maps[i]['e'],
w: '${maps[i]['w']}',
a: maps[i]['a'],
r: maps[i]['r'],
t: maps[i]['t'],
du: maps[i]['du'],
s: maps[i]['s'],
ra: maps[i]['ra'],
cul: maps[i]['cul'],
);
});
}
}

Related

Flutter SQLITE how to delete with limit

In my database I have several times the same value which returns, I want to delete the most recent value but when I want to perform a LIMIT I have an error.
My databaseHelper :
class DatabaseHelper{
static final _dbName = AppConfig.DATABASE_NAME;
static final _dbVersion = AppConfig.DATABASE_VERSION;
static final tableName = 'counter';
static final columnId = '_id';
static final columnType = 'type';
static final columnStatus = 'status';
DatabaseHelper._privateConstructor();
static final DatabaseHelper instance = DatabaseHelper._privateConstructor();
static Database _database;
Future<Database> get database async{
if(_database != null) return _database;
_database = await _initiateDatabase();
return _database;
}
_initiateDatabase() async{
return await openDatabase(join(await getDatabasesPath(), _dbName), version: _dbVersion, onCreate: _onCreate);
}
Future _onCreate(Database db, int version) async{
await db.execute('''
CREATE TABLE $tableName (
$columnId ID INTEGER PRIMARY KEY,
$columnType TEXT NOT NULL,
$columnStatus TEXT NOT NULL
)
'''
);
}
Future<int> insert(Map<String, dynamic> row) async
{
Database db = await instance.database;
return await db.insert(tableName, row);
}
Future<List<Map<String, dynamic>>> queryAll() async
{
Database _db = await instance.database;
return await _db.query(tableName);
}
Future<int> delete(int id) async
{
Database _db = await instance.database;
return await _db.delete(tableName, where: '$columnId = ?', whereArgs: [id]);
}
Future<void> deleteAll() async
{
Database _db = await instance.database;
return await _db.delete(tableName);
}
// Here is my problem
Future<int> deletePersonnel(String type) async
{
Database _db = await instance.database;
return await _db.rawDelete("DELETE FROM $tableName WHERE $columnType = $type LIMIT 1");
}
}
In my deletePersonnel function, The request works if I write this :
wait _db.rawDelete("DELETE FROM $tableName");
But I have an error if I write this :
wait _db.rawDelete("DELETE FROM $tableName WHERE $columnType = $type LIMIT 1");
Here is an exemple of the value in my database:
[
{type: Test, status: High},
{type: Test, status: High},
{type: Active, status: Low},
{type: Test, status: High}
]
As you can see I have several times the same values ​​which appear in my database, so I want to delete a value which corresponds to my type by deleting the last entry
The error that I have :
E/SQLiteLog(10576): (1) near "LIMIT": syntax error
BUT if I remove the LIMIT 1 in my request I have an error too :
no such column: Test

Saving to Firebase storage not possible in an isolate

I have an app feature where the user picks images from his phone and then uploads them to Firebase Storage.
I thought that the upload process should be done in a separate isolate.
I keep getting an exception which I think is related to the Multi Image Picker package.
The exception is:
E/flutter (12961): [ERROR:flutter/lib/ui/ui_dart_state.cc(177)]
Unhandled Exception: Exception: NoSuchMethodError: The getter
'defaultBinaryMessenger' was called on null.
When the user presses on the upload button, this method is called:
Future<void> _initIsolate() async {
ReceivePort receivePort = ReceivePort();
receivePort.listen(
(message) {
print(message.toString());
},
onDone: () => print('Done'),
onError: (error) => print('$error'),
);
await compute(
_function, // This function is called in the separate isolate
{
'sendingPort': receivePort.sendPort,
'images': images,
},
);
}
The _function method is as follows:
static void _function(Map<String, dynamic> parameterMap) async {
SendPort sendingPort = parameterMap['sendingPort'];
List<Asset> images = parameterMap['images'];
List<String> urls = [];
int index = 0;
images.forEach(
(image) async {
String url = await getDownloadUrl(image); // a helper method
urls.add(url);
sendingPort.send('Image number: $index uploaded');
index += 1;
},
);
final CollectionReference collectionRef = FirebaseFirestore.instance.collection('offers');
final user = CurrentUser.getCurrentUser();
await collectionRef.doc(user.uid).set(
{
'time': FieldValue.serverTimestamp(),
'urls': urls,
},
);
}
The helper method _getDownloadUrl is as follows:
Future<String> getDownloadUrl(Asset image) async {
String rannum = Uuid().v1();
final ByteData byteData = await image.getByteData(); // --> This produces a defaultBinaryMessenger
final List<int> imageData = byteData.buffer.asUint8List();
Reference reference = FirebaseStorage.instance.ref().child("offers/$rannum");
UploadTask uploadTask = reference.putData(imageData);
TaskSnapshot downloadUrl = await uploadTask.whenComplete(() => null);
Future<String> futureUrl = downloadUrl.ref.getDownloadURL();
return futureUrl;
}
The getByteData method is part of the multi_image_picker package.
The source code is:
Future<ByteData> getByteData({int quality = 100}) async {
if (quality < 0 || quality > 100) {
throw new ArgumentError.value(
quality, 'quality should be in range 0-100');
}
Completer completer = new Completer<ByteData>();
ServicesBinding.instance.defaultBinaryMessenger // --> Exception here. ServicesBinding.instance is null
.setMessageHandler(_originalChannel, (ByteData message) async {
completer.complete(message);
ServicesBinding.instance.defaultBinaryMessenger
.setMessageHandler(_originalChannel, null);
return message;
});
await MultiImagePicker.requestOriginal(_identifier, quality);
return completer.future;
}
Why is the ServicesBinding.instance null?
Since this method is working fine without using Isolates, does this have something to do with the isolates?

Import csv to sqlite in Flutter (insert issue)

I've already read the related article and solution + mentioned method, but still I don't get it what should I add to my code for importing csv to sqlite table List<<Map<String, dynamic>. I need to replace existing table with a new one and insert each lines of converted csv. How can I solve it? Here's my code below.The problem is importVoca() of db.dart.
db.dart
class DBHelper {
var _db;
// create database
Future<Database> get database async {
if (_db != null) return _db;
_db = openDatabase(
join(await getDatabasesPath(), 'vocas.db'),
onCreate: (db, version) {
return db.execute(
"CREATE TABLE vocas(id TEXT PRIMARY KEY, word TEXT, meaning TEXT, createTime TEXT)",
);
},
version: 1,
);
return _db;
}
// insert voca
Future<void> insertVoca(Voca voca) async {
final db = await database;
await db.insert('vocas', voca.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace);
}
// Voca list
Future<List<Voca>> vocas() async {
final db = await database;
final List<Map<String, dynamic>> maps = await db.query('vocas');
return List.generate(maps.length, (i) {
return Voca(
id: maps[i]['id'],
word: maps[i]['word'],
meaning: maps[i]['meaning'],
createTime: maps[i]['createTime']);
});
}
//update voca list
Future<void> updateVoca(Voca voca) async {
final db = await database;
await db.update(
'vocas',
voca.toMap(),
where: "id = ?",
whereArgs: [voca.id],
);
}
//delete voca
Future<void> deleteVoca(String id) async {
final db = await database;
await db.delete(
'vocas',
where: "id = ?",
whereArgs: [id],
);
}
//find voca to edit
Future<List<Voca>> findVoca(String id) async {
final db = await database;
final List<Map<String, dynamic>> maps =
await db.query('vocas', where: 'id = ?', whereArgs: [id]);
return List.generate(maps.length, (i) {
return Voca(
id: maps[i]['id'],
word: maps[i]['word'],
meaning: maps[i]['meaning'],
createTime: maps[i]['createTime'],
);
});
}
//export voca to csv
Future exportVoca() async {
var year = DateFormat('yy').format(DateTime.now());
var month = DateFormat('MM').format(DateTime.now());
var day = DateFormat('d').format(DateTime.now());
final db = await database;
var result = await db.query('vocas');
var csv = mapListToCsv(result);
final directory = await getApplicationDocumentsDirectory();
final pathOfFile = await directory.path;
File file = File("$pathOfFile/dontForget_$year$month$day.csv");
file.writeAsString(csv);
}
//import csv to sqlite
Future importVoca() async {
File file = await FilePicker.getFile(
type: FileType.custom, allowedExtensions: ['csv']);
final data = file.openRead();
final fields = await data
.transform(utf8.decoder)
.transform(new CsvToListConverter())
.toList();
Database _db = await openDatabase(
join(await getDatabasesPath(), 'vocas.db'),
version: 1, onCreate: (Database db, int version) async {
await db.execute("DROP TABLE IF EXISTS vocas");
await db.execute(
"CREATE TABLE vocas(id TEXT PRIMARY KEY, word TEXT, meaning TEXT, createTime TEXT)");
});
}
}

Using SQLite in main.dart from seperate file?

I've followed this easy example from the flutter documentation. However, this is wrote in a separate file (db_test.db). I'm aiming to convert data into a ListView at some point. So, how would I use CRUD operations like retrieving data in my main.dart? I could add this to my main.dart file but I'd like to keep it clean and separate.
Official Flutter tutorial
My db.dart file
void main () async {
final database = openDatabase(
join(await getDatabasesPath(), 'to_do.db'),
onCreate: (db, version) {
return db.execute("CREATE TABLE tasks(id INTEGER PRIMARY KEY, title TEXT, created TEXT, INTEGER is_complete)");
},
version: 1,
);
Future<void> insertTask (Task task) async {
final Database db = await database;
await db.insert(
'tasks',
task.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace
);
}
Future<List<Task>> tasks () async {
final Database db = await database;
final List<Map<String, dynamic>> maps = await db.query('tasks');
return List.generate(maps.length, (i) {
return Task(
id: maps[i]['id'],
title: maps[i]['title'],
created: maps[i]['created'],
isComplete: maps[i]['is_complete']
);
});
}
Future<void> updateTask(Task task) async {
// Get a reference to the database.
final db = await database;
// Update the given Dog.
await db.update(
'tasks',
task.toMap(),
// Ensure that the Dog has a matching id.
where: "id = ?",
// Pass the Dog's id as a whereArg to prevent SQL injection.
whereArgs: [task.id],
);
}
Future<void> deleteTask(int id) async {
// Get a reference to the database.
final db = await database;
// Remove the Dog from the database.
await db.delete(
'tasks',
// Use a `where` clause to delete a specific dog.
where: "id = ?",
// Pass the Dog's id as a whereArg to prevent SQL injection.
whereArgs: [id],
);
}
}
You can create a new file containing Class with static members to help. Static members ensure that only one instance of database is created in your whole app.
class DatabaseHelper {
static Database _database;
///Returns db instance if already opened
///else call the initDatabase
static Future<Database> getDBConnector() async {
if (_database != null) {
return _database;
}
return await _initDatabase();
}
///Open DB Connection, returns a Database instance.
///
static Future<Database> _initDatabase() async {
_database = await openDatabase(
join(await getDatabasesPath(), "my_path.db"),
onCreate: (db, version) async {
//on create
},
version: 1,
);
return _database;
}
//put your CRUD in static function
static Future<void> insertTask (Task task) async {
final Database db = await getDBConnector();
await db.insert(
'tasks',
task.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace
);
}
//the same with edit, delete
}
Then in your other file (like main.dart) you can just call it like this:
import "./databaseHelper.dart";
void caller() async{
//create task
//insert
await DatabaseHelper.insertTask(task);
}
Make sure the caller is asynchronous.

How to get element/value from a future of a list

I used SQLite for the cache. Everything is working well. But I don't know how to display value from this promise? (display() returns Future<List<Token>>)
What I want is properly something like var value = display().refreshToken
print statement printing List values
print(await display());
Database.dart
// Open the database and store the reference
import 'dart:async';
import 'package:path/path.dart';
import 'package:reborn_next_job02/models/Token.dart';
import 'package:sqflite/sqflite.dart';
databaseToken(
String tokenModel, String refreshTokenModel, String method) async {
final database = openDatabase(
join(await getDatabasesPath(), 'tokenDB.db'),
onCreate: (db, version) {
return db.execute(
"CREATE TABLE tokenTable(id INTEGER PRIMARY KEY, token TEXT, refreshToken TEXT)",
);
},
version: 1,
);
Future<void> insert(Token token) async {
final Database db = await database;
await db.insert(
'tokenTable',
token.toMap(),
//same use insert multiple times using ConfiictAlgorithm
conflictAlgorithm: ConflictAlgorithm.replace,
);
}
Future<List<Token>> display() async {
final Database db = await database;
final List<Map<String, dynamic>> maps = await db.query('tokenTable');
return List.generate(maps.length, (i) {
return Token(
id: maps[i]['id'],
token: maps[i]['token'],
refreshToken: maps[i]['refreshToken'],
);
});
}
Future<void> update(Token token) async {
final db = await database;
await db.update(
'tokenTable',
token.toMap(),
where: "id = ?",
whereArgs: [token.id],
);
}
Future<void> delete(int id) async {
final db = await database;
await db.delete(
'tokenTable',
where: "id = ?",
whereArgs: [id],
);
}
if (method == "insert") {
var token = Token(
id: 1,
token: tokenModel,
refreshToken: refreshTokenModel,
);
await insert(token);
print(await display());
} else if (method == "update") {
var token = Token(
id: 1,
token: tokenModel,
refreshToken: refreshTokenModel,
);
await update(token);
print(await display());
}
}
Model.dart
class Token {
int id;
String token;
String refreshToken;
Token({this.id,this.token, this.refreshToken});
factory Token.fromJson(Map<String, dynamic> json){
return Token(
id: json['id'],
token:json['token'],
refreshToken: json['refreshToken']
);
}
Map<String, dynamic> toMap() {
return {
'id': id,
'token': token,
'refreshToken': refreshToken,
};
}
#override
String toString() {
return 'Token{id: $id, token: $token, refreshToken: $refreshToken}';
}
}
You can get it with
print((await display())?.elementAt(0)?.refreshToken);
display() returns a future of list, so you have to wrap (await display()) before doing list manipulation, such as get an element from a list. list[0] is equivalent to list.elementAt(0), but list.elementAt(0)? is null-safe and out-of-bound-safe.

Resources