Как исправить, что ‘type ‘_Type’ не является подтипом типа ‘FutureOr» в Flutter

#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

  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();
    }
   });
  

Ответ №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> .