Flutter: passing future<int> as int to Charts

百般思念 提交于 2019-12-13 03:21:25

问题


I am making a mood checker application using flutter where user chose one of 5 emojis to tell their mood. I want to display a PieChart with data emoji vs num of Days it has been chosen. Problem is that I have to fetch data from sqflite Database to get numOfDays a particular emoji is chosen which will be of type Future but charts can't take Futures, I tried to use async-await but it didn't seem to work.

Error

E/flutter (27721): [ERROR:flutter/lib/ui/ui_dart_state.cc(148)] Unhandled Exception: type 'Future<dynamic>' is not a subtype of type 'int'
E/flutter (27721): #0      _MoodChartState.initData (package:pro_app/journal/view/mood_chart.dart:36:24)
E/flutter (27721): #1      _AsyncAwaitCompleter.start (dart:async/runtime/libasync_patch.dart:49:6)
E/flutter (27721): #2      _MoodChartState.initData (package:pro_app/journal/view/mood_chart.dart:31:16)
E/flutter (27721): #3      _MoodChartState.initState (package:pro_app/journal/view/mood_chart.dart:58:5)
E/flutter (27721): #4      StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:3846:58)
E/flutter (27721): #5      ComponentElement.mount (package:flutter/src/widgets/framework.dart:3711:5)
E/flutter (27721): #6      Element.inflateWidget (package:flutter/src/widgets/framework.dart:2956:14)
E/flutter (27721): #7      Element.updateChild (package:flutter/src/widgets/framework.dart:2759:12)
E/flutter (27721): #8      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3747:16)
E/flutter (27721): #9      Element.rebuild (package:flutter/src/widgets/framework.dart:3559:5)
E/flutter (27721): #10     StatelessElement.update (package:flutter/src/widgets/framework.dart:3796:5)
E/flutter (27721): #11     Element.updateChild (package:flutter/src/widgets/framework.dart:2748:15)
E/flutter (27721): #12     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3747:16)
E/flutter (27721): #13     Element.rebuild (package:flutter/src/widgets/framework.dart:3559:5)
E/flutter (27721): #14     ProxyElement.update (package:flutter/src/widgets/framework.dart:4006:5)
E/flutter (27721): #15     Element.updateChild (package:flutter/src/widgets/framework.dart:2748:15)
E/flutter (27721): #16     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3747:16)
E/flutter (27721): #17     Element.rebuild (package:flutter/src/widgets/framework.dart:3559:5)
E/flutter (27721): #18     ProxyElement.update (package:flutter/src/widgets/framework.dart:4006:5)
E/flutter (27721): #19     Element.updateChild (package:flutter/src/widgets/framework.dart:2748:15)
E/flutter (27721): #20     RenderObjectElement.updateChildren (package:flutter/src/widgets/framework.dart:4601:32)
E/flutter (27721): #21     MultiChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4992:17)
E/flutter (27721): #22     Element.updateChild (package:flutter/src/widgets/framework.dart:2748:15)
E/flutter (27721): #23     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3747:16)
E/flutter (27721): #24     Element.rebuild (package:flutter/src/widgets/framework.dart:3559:5)
E/flutter (27721): #25     StatefulElement.update (package:flutter/src/widgets/framework.dart:3894:5)
E/flutter (27721): #26     Element.updateChild (package:flutter/src/widgets/framework.dart:2748:15)
E/flutter (27721): #27     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3747:16)
E/flutter (27721): #28     Element.rebuild (package:flutter/src/widgets/framework.dart:3559:5)
E/flutter (27721): #29     ProxyElement.update (package:flutter/src/widgets/framework.dart:4006:5)
E/flutter (27721): #30     Element.updateChild (package:flutter/src/widgets/framework.dart:2748:15)
E/flutter (27721): #31     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3747:16)
E/flutter (27721): #32     Element.rebuild (package:flutter/src/widgets/framework.dart:3559:5)
E/flutter (27721): #33     StatefulElement.update (package:flutter/src/widgets/framework.dart:3894:5)
E/flutter (27721): #34     Element.updateChild (package:flutter/src/widgets/framework.dart:2748:15)
E/flutter (27721): #35     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4883:14)
E/flutter (27721): #36     Element.updateChild (package:flutter/src/widgets/framework.dart:2748:15)
E/flutter (27721): #37     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3747:16)
E/flutter (27721): #38     Element.rebuild (package:flutter/src/widgets/framework.dart:3559:5)
E/flutter (27721): #39     StatelessElement.update (package:flutter/src/widgets/framework.dart:3796:5)
E/flutter (27721): #40     Element.updateChild (package:flutter/src/widgets/framework.dart:2748:15)
E/flutter (27721): #41     SingleChildRenderObjectElement.update (package:flutter/src/widgets/framework.dart:4883:14)
E/flutter (27721): #42     Element.updateChild (package:flutter/src/widgets/framework.dart:2748:15)
E/flutter (27721): #43     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3747:16)
E/flutter (27721): #44     Element.rebuild (package:flutter/src/widgets/framework.dart:3559:5)
E/flutter (27721): #45     StatefulElement.update (package:flutter/src/widgets/framework.dart:3894:5)
E/flutter (27721): #46     Element.updateChild (package:flutter/src/wid

Mood Model file

import 'package:flutter/material.dart';

class Mood {
  int _moodID;
  int _emojiID;
  int _actID;
  int _moodDay;
  int _moodMonth;
  int _moodYear;

  Mood(this._emojiID, this._moodDay, this._moodMonth, this._moodYear,
      this._actID);

  Mood.withId(this._moodID, this._emojiID, this._moodDay, this._moodMonth,
      this._moodYear, this._actID);

  int get moodID => _moodID;
  int get emojiID => _emojiID;
  int get actID => _actID;
  int get moodDay => _moodDay;
  int get moodMonth => _moodMonth;
  int get moodYear => _moodYear;

// can define setters as well

  Map<String, int> toMap() {
    var map = Map<String, int>();
    if (_moodID != null) {
      map['moodId'] = _moodID;
    }
    map['emojiId'] = _emojiID;
    map['actId'] = _actID;
    map['moodDay'] = _moodDay;
    map['moodMonth'] = _moodMonth;
    map['moodYear'] = _moodYear;
    return map;
  }

  Mood.fromMap(Map<String, int> map) {
    this._moodID = map['moodId'];
    this._emojiID = map['emojiId'];
    this._actID = map['actId'];
    this._moodDay = map['moodMap'];
    this._moodMonth = map['moodMonth'];
    this._moodYear = map['moodYear'];
  }
}

*Database file

import 'package:path/path.dart';
import 'dart:async';
import 'package:path_provider/path_provider.dart';
import 'package:sqflite/sqflite.dart';
import 'dart:io';

import '../models/mood_model.dart';

class DatabaseHelper {
  static final DatabaseHelper _instance = new DatabaseHelper.internal();
  factory DatabaseHelper() => _instance;

  final String tableName = "moodTable";
  final String colMoodId = "moodId";
  final String colEmojiId = "emojiId";
  final String colActId = "actId";
  final String colMoodDay = "moodDay";
  final String colMoodMonth = "moodMonth";
  final String colMoodYear = "moodYear";

  static Database _db;

  Future<Database> get db async {
    if (_db == null) {
      return initDb();
    }
    return _db;
  }

  DatabaseHelper.internal();

  Future<Database> initDb() async {
    Directory documentDirectory = await getApplicationDocumentsDirectory();
    String path = join(documentDirectory.path, "mood.db");
    var ourDb = await openDatabase(path, version: 1, onCreate: _onCreate);
    return ourDb;
  }

  void _onCreate(Database db, int version) async {
    await db.execute(
        "CREATE TABLE moodTable (moodId INTEGER PRIMARY KEY, emojiId INTEGER, actId INTEGER, moodDay INTEGER, moodMonth INTEGER, moodYear INTEGER)");
    print("Table Created");
  }

  // insert
  Future<int> saveMood(Mood mood) async {  
    var dbClient = await this.db;
    int result = await dbClient.insert("$tableName", mood.toMap());
    print('Saved');
    return result;

  }



  // to get number of mood days
  Future<List<Map<String, dynamic>>> listOfMoods() async {
    Database db = await this.db;
    var result = await db.query(tableName, orderBy: '$colMoodId ASC');
    return result;
  }

  Future<int> numOfMoodDays(int emojiID) async {
    Database db = await this.db;
    var result = await db.query(tableName,
        orderBy: '$colMoodId ASC',
        where: '$colEmojiId = ?',
        whereArgs: [emojiID]);
    return result.length;
  }

  // close db
  Future close() async {
    var dbClient = await db;
    return dbClient.close();
  }
}

Mood_Chart file snippet

    import 'package:flutter/material.dart';
    import 'dart:math';
    import 'package:charts_flutter/flutter.dart' as charts;
    import '../view/mood.dart';
    import '../models/mood_db.dart';
    import 'dart:async';

    class Mood {
      String _emoji;
      int _numOfDays; // this has to int bcz charts can't take future<int>
      charts.Color _color;

      Mood(this._emoji, this._numOfDays, this._color);
    }

    class MoodChart extends StatefulWidget {
      @override
      _MoodChartState createState() => _MoodChartState();
    }

    class _MoodChartState extends State<MoodChart> {
      DatabaseHelper _databaseHelper = DatabaseHelper();
      List<Mood> _data;
      List<charts.Series<Mood, String>> _chartData;

      // Here I used async-await but this function still return Future<int>    
      numOfDaysFn(int id) async {
        int numOfDays =await _databaseHelper.numOfMoodDays(id);
        return numOfDays;
      }

      void initData() async {
        _chartData = List<charts.Series<Mood, String>>();

        _data = <Mood>[
          Mood(
              allMoods[0], numOfDaysFn(1), charts.MaterialPalette.red.shadeDefault),
          Mood(allMoods[1], numOfDaysFn(2),
              charts.MaterialPalette.blue.shadeDefault),
          Mood(allMoods[2], numOfDaysFn(3),
              charts.MaterialPalette.gray.shadeDefault),
          Mood(allMoods[3], numOfDaysFn(4),
              charts.MaterialPalette.indigo.shadeDefault),
          Mood(allMoods[4], numOfDaysFn(5),
              charts.MaterialPalette.green.shadeDefault),
        ];
        _chartData.add(charts.Series(
          id: 'Mood',
          data: _data,
          colorFn: (Mood mood, _) => mood._color,
          domainFn: (Mood mood, _) => mood._emoji,
          measureFn: (Mood mood, _) => **mood._numOfDays**, //this can't take futures
        ));
      }

      @override
      void initState() {
        super.initState();
        initData();
      }

      @override
      Widget build(BuildContext context) {
        return Container(
          child: charts.PieChart(
            _chartData,
            animate: true,
          ),
        );
      }
    }
List allMoods = ['Disgusting', 'Bad', 'Ok', 'Good', 'Amazing'];

回答1:


I do not know if this code runs because your sample code is not complete. You kinda need to learn how dart futures work. When you call it, the result will return later like Javascript promises

import 'package:flutter/material.dart';
import 'dart:math';
import 'package:charts_flutter/flutter.dart' as charts;
import '../view/mood.dart';
import '../models/mood_db.dart';
import 'dart:async';

class Mood {
  String _emoji;
  int _numOfDays; // this has to int bcz charts can't take future<int>
  charts.Color _color;

  Mood(this._emoji, this._numOfDays, this._color);
}

class MoodChart extends StatefulWidget {
  @override
  _MoodChartState createState() => _MoodChartState();
}

class _MoodChartState extends State<MoodChart> {
  DatabaseHelper _databaseHelper = DatabaseHelper();
  List<Mood> _data;
  List<charts.Series<Mood, String>> _chartData = null;

  // Here I used async-await but this function still return Future<int>    
  Future<List<int>> numOfDaysFn(List<int> days) async {
    return Future.wait(days.map((d) => _databaseHelper.numOfMoodDays(d)));
  }

  void initData( List<int> idx, List<int> days) {
    setState(() {


      _chartData = List<charts.Series<Mood, String>>();

      _data = <Mood>[
        Mood(
            allMoods[idx[0]-1], days[0], charts.MaterialPalette.red.shadeDefault),
        Mood(allMoods[idx[1]-1], days[1],
            charts.MaterialPalette.blue.shadeDefault),
        Mood(allMoods[idx[2]-1], days[2],
            charts.MaterialPalette.gray.shadeDefault),
        Mood(allMoods[idx[3]-1], days[3],
            charts.MaterialPalette.indigo.shadeDefault),
        Mood(allMoods[idx[4]-1], days[4],
            charts.MaterialPalette.green.shadeDefault),
      ];
      _chartData.add(charts.Series(
        id: 'Mood',
        data: _data,
        colorFn: (Mood mood, _) => mood._color,
        domainFn: (Mood mood, _) => mood._emoji,
        measureFn: (Mood mood, _) => mood._numOfDays, //this can't take futures
      ));
    });
  }

  @override
  void initState() {
    super.initState();
    var months = [1,2,3,4,5];
    numOfDaysFn(months).then((days) {
        initData(months, days);
    });
  }

  @override
  Widget build(BuildContext context) {
     if(_chartData != null ){
      return Container(
        child: charts.PieChart(
          _chartData,
          animate: true,
        ),
      );
    } else {
      return CircularProgressIndicator();
    }
  }
}

Revision 1

    import 'package:flutter/material.dart';
import 'dart:math';
import 'package:charts_flutter/flutter.dart' as charts;
import '../view/mood.dart';
import '../models/mood_db.dart';
import 'dart:async';

class Mood {
  String _emoji;
  int _numOfDays; // this has to int bcz charts can't take future<int>
  charts.Color _color;

  Mood(this._emoji, this._numOfDays, this._color);
}

class MoodChart extends StatefulWidget {
  @override
  _MoodChartState createState() => _MoodChartState();
}

class _MoodChartState extends State<MoodChart> {
  DatabaseHelper _databaseHelper = DatabaseHelper();
  List<Mood> _data;
  List<charts.Series<Mood, String>> _chartData = null;

  static List<charts.Color> DEFAULT_SHADE  = [
    null,
    charts.MaterialPalette.red.shadeDefault, 
    charts.MaterialPalette.blue.shadeDefault, 
    charts.MaterialPalette.gray.shadeDefault,
    charts.MaterialPalette.indigo.shadeDefault,
    charts.MaterialPalette.green.shadeDefault];

  Future<Mood> numOfDaysFn(int day) async {
    return Mood(  allMood[day-1] , _databaseHelper.numOfMoodDays(day), DEFAULT_SHADE[day] );
  }
  Future<List<Mood>> returnAllNumOfDaysFn( List<int> days) async {
    return Future.wait(days.map((d) => numOfDaysFn(d)));
  }

  @override
  void initState() {
    super.initState();
    var months = [1,2,3,4,5];
    returnAllNumOfDaysFn(months).then((moods) {
      var temp = charts.Series(
        id: 'Mood',
        data: _data,
        colorFn: (Mood mood, _) => mood._color,
        domainFn: (Mood mood, _) => mood._emoji,
        measureFn: (Mood mood, _) => mood._numOfDays, //this can't take futures
      );
      setState(() {
        _data = moods;
        _chartData = temp;
      });

    });
  }

  @override
  Widget build(BuildContext context) {
     if(_chartData != null ){
      return Container(
        child: charts.PieChart(
          _chartData,
          animate: true,
        ),
      );
    } else {
      return CircularProgressIndicator();
    }
  }
}

https://www.dartlang.org/guides/libraries/futures-error-handling

https://docs.flutter.io/flutter/widgets/State/initState.html

https://www.dartlang.org/tutorials/language/futures#calling-multiple-funcs

Edit: you need to understand setState too

https://docs.flutter.io/flutter/widgets/State/setState.html

Flutter charts provide sample with static data. However, you are fetching data dynamically so you need to call set state.



来源:https://stackoverflow.com/questions/54965567/flutter-passing-futureint-as-int-to-charts

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!