1

我正在编写一个 Flutter 应用程序,其中一个要求是离线保存数据以在没有互联网的情况下读取它,但是当我从 Sqflite 的数据库加载时出现问题,我收到此错误:type '_Type' is not a subtype of type 'FutureOr<Verse>'. 我究竟做错了什么?我正在使用 BLOC 模式。

当我检查 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;
            });
          });
        });
      });
    }
  }
4

2 回答 2

0

首先,我在调试代码,我发现

final today = DateTime(DateTime.now().year, 1, 1, 0,).difference(DateTime(DateTime.now().year, 1, 1, 0, 0)).inDays;

它返回0

  1. 我在这里注意:
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();
    }
   });
于 2019-04-09T05:44:34.123 回答
0
Future<VerseList> getAllVerse() async {
    final db = await database;

    var res = await db.query("Verse");

    print(res);

    return res.isNotEmpty ? VerseList.fromJson(res) : Null;
  }

和上面的方法一样,不能return Null,因为Null不是VerseList类型,要改成NullVerseList()也可以 Future<VerseList>改成Future<dynmic>

于 2019-07-16T08:38:51.033 回答