#dart #flutter #sqflite
#dart #flutter #sqflite
Вопрос:
Я пишу приложение Flutter, и одним из требований является сохранение данных в автономном режиме, чтобы читать их без Интернета, но проблема при загрузке из базы данных Sqflite, я получаю эту ошибку: type '_Type' is not a subtype of type 'FutureOr<Verse>'
. Что я делаю не так? Я использую шаблон БЛОКА.
Когда я проверяю переменную res в форме функции getDailyVerse, я вижу, что она пуста, но в getAllVerse я вижу, что получаю все стихи, но в ListView я не вижу, загружается или нет.
Это моя модель:
import 'dart:async';
import 'dart:io';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'package:http/http.dart' show Client;
import 'dart:convert';
import '../models/verse.dart';
class VerseProvider {
VerseProvider._();
static final VerseProvider db = VerseProvider._();
Client client = Client();
final String _urlApi = "https://arcane-tundra-45231.herokuapp.com";
Database _database;
Future<Database> get database async {
if (_database != null) return _database;
_database = await initDB();
return _database;
}
initDB() async {
Directory documentsDirectory = await getApplicationDocumentsDirectory();
String path = join(documentsDirectory.path, "DailyVerse.db");
return await openDatabase(
path,
version: 1,
onOpen: (db) {},
onCreate: (Database db, int version) async {
await db.execute("CREATE TABLE Verse ("
"id INTEGER PRIMARY KEY, "
"day INTEGER, "
"text TEXT, "
"text_es TEXT, "
"human_reference TEXT, "
"human_reference_es TEXT, "
"url TEXT, "
"url_es TEXT, "
"image_url TEXT"
")");
}
);
}
newVerse(Verse verse) async {
final db = await database;
// var res = await db.rawInsert(
// "INSERT INTO Verse (id, day, text, text_es, human_reference, human_reference_es, url, url_es, image_url)"
// " VALUES (${verse.id}, ${verse.day}, ${verse.text.replaceAll("'", "`")}, ${verse.textEs.replaceAll("'", "`")}, ${verse.humanReference.replaceAll("'", "`")}, ${verse.humanReferenceEs.replaceAll("'", "`")}, ${verse.url}, ${verse.urlEs}, ${verse.imageUrl})"
// );
var res = await db.insert(
"Verse",
verse.toMap(),
conflictAlgorithm: ConflictAlgorithm.replace
);
return res;
}
Future<Verse> getDailyVerse() async {
final db = await database;
final today = DateTime(DateTime.now().year, 1, 1, 0,).difference(DateTime(DateTime.now().year, 1, 1, 0, 0)).inDays;
var res = await db.query("Verse", where: "day = ?", whereArgs: [today]);
print(res);
return res.isNotEmpty ? Verse.fromJson(res.first) : Null;
}
Future<VerseList> getAllVerse() async {
final db = await database;
var res = await db.query("Verse");
print(res);
return res.isNotEmpty ? VerseList.fromJson(res) : Null;
}
Future<Verse> fetchDailyVerse() async {
final response = await client.get(_urlApi "/api/v0/verses/day");
print(response.body.toString());
print(DateTime.now());
print(DateTime.now());
print(DateTime(DateTime.now().year, 1, 1, 0,).difference(DateTime(DateTime.now().year, 1, 1, 0, 0)).inDays);
if (response.statusCode == 200) {
var jsonResponse = json.decode(response.body);
return Verse.fromJson(jsonResponse['data']);
} else {
throw Exception('Failed to Load Verse');
}
}
Future<VerseList> fetchAllVerses() async {
final response = await client.get(_urlApi "/api/v0/verses/");
if (response.statusCode == 200) {
var jsonResponse = json.decode(response.body);
return VerseList.fromJson(jsonResponse['data']);
} else {
throw Exception('Failed to load Verses');
}
}
}
Это когда я вызываю это, если данные загружены локально :
import 'dart:async';
import '../resources/verse_provider.dart';
import '../models/verse.dart';
import '../resources/config_provider.dart';
class Repository {
final verseProvider = VerseProvider.db;
fetchDailyVerse() async {
bool isOfflineSaved = false;
ConfigProvider().getSaveOffline().then((value) => isOfflineSaved = value ).then((onValue) async {
if (isOfflineSaved) {
return await verseProvider.getDailyVerse();
} else {
return await verseProvider.fetchDailyVerse();
}
});
}
fetchAllVerses() async {
bool isOfflineSaved = false;
ConfigProvider().getSaveOffline().then((value) => isOfflineSaved = value ).then((onValue) async {
if (isOfflineSaved) {
return await verseProvider.getAllVerse();
} else {
return await verseProvider.fetchAllVerses();
}
});
}
}
Это когда я сохраняю его локально:
Future saveVerseOffline() async {
// Show Dialog.waiting
showDialog(
context: context,
barrierDismissible: false,
builder: (context) {
return new Dialog(
child: new Row(
mainAxisSize: MainAxisSize.min,
children: [
new CircularProgressIndicator(),
new Text("Procesando..."),
],
),
);
},
);
// 1. Fetch the verses
final verses = fetchVerses();
print(verses);
// 2. Check if there any data saved
if (isDataSavedOnDB) {
// 3. If there are data. Do not save
new Future.delayed(new Duration(seconds: 2), () {
Navigator.pop(context); //pop dialog
});
} else {
print("something");
// 4. If there are not data. Begin to Save.
await verses.then((onValue) async {
int i = 0;
onValue.verses.forEach((f){
print("countiing $i");
// 5. Invocate the new verses and save it.
print(f);
VerseProvider.db.newVerse(f);
i = 1;
});
// 6. Dismmiss Dialog.
new Future.delayed(new Duration(seconds: 2), () {
Navigator.pop(context); //pop dialog
}).then((onValue) async {
await ConfigProvider().setSaveOffline(true).then((onValue){
setState((){
isDataSavedOnDB = true;
});
});
});
});
}
}
Ответ №1:
Сначала я отлаживал код и обнаружил, что
final today = DateTime(DateTime.now().year, 1, 1, 0,).difference(DateTime(DateTime.now().year, 1, 1, 0, 0)).inDays;
он возвращает 0
- Я замечаю здесь:
ConfigProvider().getSaveOffline().then((value) => isOfflineSaved = value ).then((onValue) async {
if (isOfflineSaved) {
return await verseProvider.getAllVerse();
} else {
return await verseProvider.fetchAllVerses();
}
});
возврат отсутствует, из-за этого ничего не отображается. Я решил так:
return ConfigProvider().getSaveOffline().then((value) => isOfflineSaved = value ).then((onValue) async {
if (isOfflineSaved) {
return await verseProvider.getAllVerse();
} else {
return await verseProvider.fetchAllVerses();
}
});
Ответ №2:
Future<VerseList> getAllVerse() async {
final db = await database;
var res = await db.query("Verse");
print(res);
return res.isNotEmpty ? VerseList.fromJson(res) : Null;
}
Точно так же, как и в приведенном выше методе, вы не можете возвращать, Null
потому что Null
это не VerseList
тип, вы должны изменить Null
на VerseList()
, или вы можете изменить Future<VerseList>
на Future<dynmic>
.