错误:flutter/lib/ui/ui_dart_state.cc(177) 未处理的异常:NoSuchMethodError:在 null

时间:2020-12-31 05:37:25

标签: flutter google-cloud-firestore firebase-storage

我首先清除了所有缓存记录。当我第一次登录执行我的APP时,代码弹出一个错误说foreach方法等于null,但是我跳转到其他页面时可以读取数据。我无法理解原因。我该怎么做才能解决这个问题?

这是我的代码

路径参考

advanced() async {
final FirebaseAuth _auth = FirebaseAuth.instance;
final FirebaseUser currentUser = await _auth.currentUser();
final db = Firestore.instance;
(new Offline(currentUser.uid)).getData().then((data) {  //call data at this line
  var vip = new Vip(currentUser.uid);
  vip.isVip().then((vipStatus) {
    if (vipStatus) {
      setState(() {
        _advancedWidget = Container(
          child: Center(
            child: Container(
              padding: const EdgeInsets.only(left: 8.0, top: 8),
              child: Text(
                'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
                style: AppTheme.getTextStyle(themeData.textTheme.subtitle1,
                    fontWeight: FontWeight.w500),
                maxLines: 5,
              ),
            ),
          ),
        );
      });
      for (var course in data['course']) {
        if (course['start'].millisecondsSinceEpoch <=
                DateTime.now().millisecondsSinceEpoch &&
            DateTime(
                        DateTime.fromMillisecondsSinceEpoch(
                                course['start'].millisecondsSinceEpoch)
                            .year,
                        DateTime.fromMillisecondsSinceEpoch(
                                course['start'].millisecondsSinceEpoch)
                            .month,
                        DateTime.fromMillisecondsSinceEpoch(
                                    course['start'].millisecondsSinceEpoch)
                                .day +
                            course['period'] -
                            1,
                        23,
                        59,
                        00)
                    .millisecondsSinceEpoch >=
                DateTime.now().millisecondsSinceEpoch) {
          // 期間內
          final dayFromRegister = ((DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day).millisecondsSinceEpoch -
                      course['start'].millisecondsSinceEpoch) /
                  1000 /
                  60 /
                  60 /
                  24)
              .round();
          _advancedList.clear();
          for (var i = 0; i < 28; i++) {
            DateTime date = DateTime(DateTime.now().year, DateTime.now().month, DateTime.now().day)
                .add(new Duration(days: (dayFromRegister - i) * -1));
            List<dynamic> result = data['records'].reversed.toList();
            int completion = 0;
            for (var r in result) {
              if (r['year'] == date.year &&
                  r['month'] == date.month &&
                  r['day'] == date.day &&
                  r['time_period'] == 'am') {
                completion += 1;
                break;
              }
            }
            for (var r in result) {
              if (r['year'] == date.year &&
                  r['month'] == date.month &&
                  r['day'] == date.day &&
                  r['time_period'] == 'pm') {
                completion += 1;
                break;
              }
            }
            setState(() {
              _advancedList.add({
                'index': i,
                'name': '第 ${i + 1} 天',
                'date':
                    '${date.year}/${date.month < 10 ? '0${date.month}' : date.month}/${date.day < 10 ? '0${date.day}' : date.day}',
                '_date': date,
                'completion': completion,
              });
            });
          }
          setState(() {
            _advancedWidget = Container(
              child: Container(
                child: ListView(
                  children: <Widget>[
                    if (data['advanceType'] != null)
                      Container(
                        margin: EdgeInsets.all(4),
                        child: Center(
                          child: Text('進階肌膚分類: ${data['advanceType']}', style: TextStyle(fontSize: 18),),
                        ),
                      ),
                    for (var AList in _advancedList)
                      InkWell(
                        child: Card(
                          margin: EdgeInsets.all(4),
                          color: AList['completion'] > 0
                              ? Colors.lightGreen
                              : themeData.cardColor,
                          child: Row(
                            mainAxisSize: MainAxisSize.min,
                            children: <Widget>[
                              Expanded(
                                child: Column(
                                  mainAxisSize: MainAxisSize.min,
                                  crossAxisAlignment:
                                      CrossAxisAlignment.start,
                                  children: <Widget>[
                                    Container(
                                      padding: const EdgeInsets.only(
                                          left: 8.0, top: 8),
                                      child: Text(
                                        '${AList['name']}',
                                        style: AppTheme.getTextStyle(
                                            themeData.textTheme.subtitle1,
                                            fontWeight: FontWeight.w500),
                                        maxLines: 5,
                                      ),
                                    ),
                                    Container(
                                      padding: const EdgeInsets.only(
                                          left: 8.0, top: 8, bottom: 8),
                                      child: Text(
                                        '${AList['date']}',
                                        style: AppTheme.getTextStyle(
                                            themeData.textTheme.subtitle2,
                                            fontWeight: FontWeight.w400),
                                        maxLines: 5,
                                      ),
                                    ),
                                  ],
                                ),
                              ),
                              Padding(
                                padding:
                                    const EdgeInsets.fromLTRB(0, 0, 10, 0),
                                child: Icon(
                                  AList['completion'] == 0
                                      ? MdiIcons.circleOutline
                                      : AList['completion'] == 1
                                          ? MdiIcons.circleHalfFull
                                          : MdiIcons.circle,
                                  color: themeData.colorScheme.onBackground
                                      .withAlpha(200),
                                  size: 24.0,
                                ),
                              ),
                            ],
                          ),
                        ),
                        onTap: () {
                          if (DateTime.parse(AList['_date'].toString())
                              .isBefore(DateTime.now())) {
                            Navigator.push(
                                context,
                                MaterialPageRoute(
                                    builder: (context) => Advanced(
                                        index: AList['index'],
                                        date: AList['_date'])));
                          }
                        },
                      )
                  ],
                ),
              ),
            );
          });
        }
      }
    } else {
      // 期間內
      _advancedList.clear();
      for (var i = 0; i < 28; i++) {
        DateTime date = DateTime.now().add(new Duration(days: i));
        setState(() {
          _advancedList.add({
            'index': i,
            'name': '第 ${i + 1} 天',
            'date':
                '${date.year}/${date.month < 10 ? '0${date.month}' : date.month}/${date.day < 10 ? '0${date.day}' : date.day}',
            '_date': date,
            'completion': 0,
          });
        });
      }
      setState(() {
        _advancedWidget = Container(
          child: Container(
            child: ListView.builder(
              itemCount: _advancedList.length,
              itemBuilder: (context, index) {
                return InkWell(
                  child: Card(
                    margin: EdgeInsets.all(4),
                    color: _advancedList[index]['completion'] > 0
                        ? Colors.lightGreen
                        : themeData.cardColor,
                    child: Row(
                      mainAxisSize: MainAxisSize.min,
                      children: <Widget>[
                        Expanded(
                          child: Column(
                            mainAxisSize: MainAxisSize.min,
                            crossAxisAlignment: CrossAxisAlignment.start,
                            children: <Widget>[
                              Container(
                                padding: const EdgeInsets.only(
                                    left: 8.0, top: 8),
                                child: Text(
                                  '${_advancedList[index]['name']}',
                                  style: AppTheme.getTextStyle(
                                      themeData.textTheme.subtitle1,
                                      fontWeight: FontWeight.w500),
                                  maxLines: 5,
                                ),
                              ),
                              Container(
                                padding: const EdgeInsets.only(
                                    left: 8.0, top: 8, bottom: 8),
                                child: Text(
                                  '${_advancedList[index]['date']}',
                                  style: AppTheme.getTextStyle(
                                      themeData.textTheme.subtitle2,
                                      fontWeight: FontWeight.w400),
                                  maxLines: 5,
                                ),
                              ),
                            ],
                          ),
                        ),
                        Padding(
                          padding: const EdgeInsets.fromLTRB(0, 0, 10, 0),
                          child: Icon(
                            _advancedList[index]['completion'] == 0
                                ? MdiIcons.circleOutline
                                : _advancedList[index]['completion'] == 1
                                    ? MdiIcons.circleHalfFull
                                    : MdiIcons.circle,
                            color: themeData.colorScheme.onBackground
                                .withAlpha(200),
                            size: 24.0,
                          ),
                        ),
                      ],
                    ),
                  ),
                  onTap: () {},
                );
              },
            ),
          ),
        );
      });
    }
  });
});
import 'package:cloud_firestore/cloud_firestore.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:sembast/sembast_io.dart';
import 'package:sembast/timestamp.dart' as ts;
import 'package:shared_preferences/shared_preferences.dart';
import 'package:sembast/sembast.dart';
import 'dart:io';
import 'package:path_provider/path_provider.dart';

class Offline {

  String _uid; //使用者 ID
  DocumentReference _userDoc;
  
  Offline(this._uid) {
    final db = Firestore.instance;
    if (this._uid != null) this._userDoc = db.collection('users').document(this._uid);
  }

  Future<void> run() async {
    final path = await this.checkPath();
    switch (path) {
      case 1:
        this.localToRemote();
        break;
      case 2:
        this.remoteToLocal();
        break;
      default:
        // none;
    }
  }

  Future<int> checkPath() async {
    final data = await _userDoc.get();
    var prefs = await SharedPreferences.getInstance();
    int originalRemoteDataDate = data.data['remote_data_date'] == null ? 0 : data.data['remote_data_date'];
    int originalLocalDataDate = prefs.getInt('_local_data_date') == null ? 0 : prefs.getInt('_local_data_date');
    if (originalRemoteDataDate == 0) {
      int newRemoteDataDate = DateTime.now().millisecondsSinceEpoch.toInt();
      await Firestore.instance.collection('users').document(_uid).updateData({'remote_data_date': newRemoteDataDate});
      originalRemoteDataDate = newRemoteDataDate;
    }
    if (originalLocalDataDate > originalRemoteDataDate) {
      // 本地至雲端
      return 1;
    } else if (originalLocalDataDate < originalRemoteDataDate) {
      // 雲端至本地
      return 2;
    } else {
      // 不動作
      return 0;
    }
  }

  Future<void> localToRemote() async {
    var prefs = await SharedPreferences.getInstance();
    int originalLocalDataDate = prefs.getInt('_local_data_date') == null ? 0 : prefs.getInt('_local_data_date');

    Directory appDocDirectory = await getApplicationDocumentsDirectory();
    String dbPath = appDocDirectory.path + '/temp$_uid.db';
    DatabaseFactory dbFactory = databaseFactoryIo;
    Database db = await dbFactory.openDatabase(dbPath);

    var store = StoreRef<String, dynamic>.main();
    var vip = await store.record('vip').get(db);
    var course = await store.record('course').get(db);
    var records = await store.record('records').get(db);
    var advanceType = await store.record('advanceType').get(db);
    var basicType = await store.record('basicType').get(db);

    var courseList = [];
    await course.forEach((each) {
      courseList.add({
        'period': each['period'],
        'records': each['records'],
        'resultData': each['resultData'],
        'start': DateTime.fromMicrosecondsSinceEpoch(each['start'].microsecondsSinceEpoch),
        'survey': each['survey']
      });
    });

    await _userDoc.updateData({
      'vip': vip!=false?{
        'buy_time': DateTime.fromMicrosecondsSinceEpoch(vip['buy_time'].microsecondsSinceEpoch),
        'expire_time': DateTime.fromMicrosecondsSinceEpoch(vip['expire_time'].microsecondsSinceEpoch),
        'status': vip['status']
      }:false,
      'course': courseList,
      'records': records,
      'advanceType': advanceType,
      'basicType': basicType,
      'remote_data_date': originalLocalDataDate,
    });

    //await db.close();
  }

  Future<void> remoteToLocal() async {
    final data = await _userDoc.get();
    var prefs = await SharedPreferences.getInstance();
    int originalRemoteDataDate = data.data['remote_data_date'] == null ? 0 : data.data['remote_data_date'];

    Directory appDocDirectory = await getApplicationDocumentsDirectory();
    String dbPath = appDocDirectory.path + '/temp$_uid.db';
    DatabaseFactory dbFactory = databaseFactoryIo;
    Database db = await dbFactory.openDatabase(dbPath);

    var store = StoreRef<String, dynamic>.main();

    await store.record('vip').put(db, data.data['vip']!=false?{
      'buy_time': ts.Timestamp.parse(data.data['vip']['buy_time'].toDate().toString()),
      'expire_time': ts.Timestamp.parse(data.data['vip']['expire_time'].toDate().toString()),
      'status': data.data['vip']['status']
    }:false);

    var course = List();
    await data.data['course'].forEach((each) {
      course.add({
        'period': each['period'],
        'records': each['records'],
        'resultData': each['resultData'],
        'start': ts.Timestamp.parse(each['start'].toDate().toString()),
        'survey': each['survey'],
      });
    });
    await store.record('course').put(db, course);
    await store.record('records').put(db, data.data['records']);
    await store.record('advanceType').put(db, data.data['advanceType']);
    await store.record('basicType').put(db, data.data['basicType']);
    await store.record('staff').put(db, data.data['staff']);
    await store.record('admin').put(db, data.data['admin']);

    await prefs.setInt('_local_data_date', originalRemoteDataDate);
    //await db.close();
  }

  Future<Map<String, dynamic>> getData() async {
    Directory appDocDirectory = await getApplicationDocumentsDirectory();
    String dbPath = appDocDirectory.path + '/temp$_uid.db';
    DatabaseFactory dbFactory = databaseFactoryIo;
    Database db = await dbFactory.openDatabase(dbPath);

    var store = StoreRef<String, dynamic>.main();
    var vip = await store.record('vip').get(db);
    var course = await store.record('course').get(db);
    var records = await store.record('records').get(db);
    var advanceType = await store.record('advanceType').get(db);
    var basicType = await store.record('basicType').get(db);
    var staff = await store.record('staff').get(db);
    var admin = await store.record('admin').get(db);

    var courseList = List();
    await course.forEach((each) {
      courseList.add({
        'period': each['period'],
        'records': each['records'],
        'resultData': each['resultData'],
        'start': DateTime.fromMicrosecondsSinceEpoch(each['start'].microsecondsSinceEpoch),
      });
    });

    if (staff == true || admin == true) {
      return {
        'staff': staff,
        'admin': admin,
      };
    } else {
      return {
        'vip': vip!=false?{
          'buy_time': DateTime.fromMicrosecondsSinceEpoch(vip['buy_time'].microsecondsSinceEpoch),
          'expire_time': DateTime.fromMicrosecondsSinceEpoch(vip['expire_time'].microsecondsSinceEpoch),
          'status': vip['status']
        }:false,
        'course': courseList,
        'records': records,
        'advanceType': advanceType,
        'basicType': basicType,
        'staff': staff,
        'admin': admin,
      };
    }
  }

  Future<void> updateData(Map<String, dynamic> updateData) async {
    updateData.forEach((key, value) async {
      Directory appDocDirectory = await getApplicationDocumentsDirectory();
      String dbPath = appDocDirectory.path + '/temp$_uid.db';
      DatabaseFactory dbFactory = databaseFactoryIo;
      Database db = await dbFactory.openDatabase(dbPath);

      var store = StoreRef<String, dynamic>.main();

      await store.record(key).update(db, value);

      //await db.close();

      var prefs = await SharedPreferences.getInstance();
      await prefs.setInt('_local_data_date', DateTime.now().millisecondsSinceEpoch.toInt());
    });
  }

  Future<void> newSession() async {
    var prefs = await SharedPreferences.getInstance();
    await prefs.setInt('_local_data_date', 0);
    //Directory appDocDirectory = await getApplicationDocumentsDirectory();
    //String dbPath = appDocDirectory.path + '/temp.db';
    //await File(dbPath).delete();
  }
}

请帮帮我,谢谢大家

0 个答案:

没有答案