Provider resetting data during initial build

  1. Summary of my problem
    Provider gets data and then resets it while notifying listeners.
  • Details about my goal:
    I am currently working on an app that displays tasks that the user is suppose to mark as finished, the app currently consists of two views/screens that are suppose to show tasks that need to be done and tasks that are already finished. The data is stored in a local DB (sqflite) and a provider is used to get the data.

  • Expected Results
    During the initial load / first build of the app the provider is suppose to query the DB and get a list of tasks the user currently has and display it to the user. By default only tasks that are set for today are suppose to be shown, and if any tasks have a “new” mark they should be displayed differently. If a user chooses a different date the list should be rebuilt with corresponding data.

  • Actual Results
    During the initial load of the app, the provider queries the database and gets a list of said tasks (with all the data from the model). However the view displays the default message of no existing tasks. If any date is selected from the date picker the data is displayed correctly (date can be the same as today or any future or past date).

  • Error Messages
    No error messages

  1. What have I tried so far
  • Initializing the provider in initState before the build method - same result
  • debugging and going through code - the data (list that contains queried DB entries) is initially set properly however after the code goes through notifyListeners() the list is reset and has no data and that list is provided to the view/screen with the widget that has a future builder and a consumer
  1. Here’s the minimum code you would need to reproduce the problem

task.dart - provider with the model

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:mapp/helpers/db_helper.dart';
import 'package:mapp/helpers/http_helper.dart';
import 'package:path_provider/path_provider.dart' as sysPath;
import 'package:intl/intl.dart';

class TaskInfo {
  final int id;
  final String pop;
  final String dp;
  final String address;
  final String addressNo;
  final String? supplement;
  final int unit;
  final String phoneNum;
  final String dateToComplete;
  final String completedDate;
  final String? hbFinish;
  final String? tfbFinish;
  final String? fazFinish;
  final bool isMounting;
  final bool isActivation;
  final bool isMounted;
  final String? mountDate;
  final bool isActivated;
  final String? activDate;
  final String? comment;
  final bool isDone;
  final bool isSent;
  final bool? isNew;
  
  TaskInfo(
      {required this.id,
      required this.pop,
      required this.dp,
      required this.address,
      required this.addressNo,
      required this.unit,
      required this.phoneNum,
      required this.dateToComplete,
      required this.isMounting,
      required this.isActivation,
      required this.isMounted,
      required this.isActivated,
      required this.isDone,
      required this.comment,
      required this.supplement,
      required this.completedDate,
      required this.isSent,
      this.mountDate,
      this.activDate,
      this.hbFinish,
      this.tfbFinish,
      this.fazFinish,
      this.isNew
      });
}

class Task with ChangeNotifier {
  List<TaskInfo> _taskList = [];

  List<TaskInfo> get tasks {
    return [..._taskList];
  }

  Future<void> getAndSetTasks(bool finished, [String? selectedDate]) async {
    var tasks = await DBHelper.getTaskData(finished, selectedDate);
    _taskList = tasks
        .map((item) => TaskInfo(
            id: item['id'],
            pop: item['pop'],
            dp: item['dp'],
            address: item['address'],
            addressNo: item['addressNo'],
            unit: item['unit'],
            phoneNum: item['phoneNum'],
            dateToComplete: item['dateToComplete'],
            isMounting: item['isMounting'] == 1 ? true : false,
            isActivation: item['isActivation'] == 1 ? true : false,
            isMounted: item['isMounted'] == 1 ? true : false,
            isActivated: item['isActivated'] == 1 ? true : false,
            isDone: item['isDone'] == 1 ? true : false,
            activDate: item['activDate'],
            comment: item['comment'],
            fazFinish: item['fazFinish'],
            hbFinish: item['hbFinish'],
            mountDate: item['mountDate'],
            supplement: item['suppl'],
            tfbFinish: item['tfbFinish'],
            completedDate: item['completedDate'],
            isSent: item['isSent'] == 1 ? true : false,
            isNew: item['isNew'] == 1 ? true : false
            //cantComplete: item['cantComplete'] == 1? true:false,
            //reason: item['']
            ))
        .toList();

    notifyListeners();
  }

all_tasks_screen.dart - the screen view where the data is suppose to be shown



import 'package:provider/provider.dart';
import 'package:intl/intl.dart';
import 'package:shimmer/shimmer.dart';

import '../providers/task.dart';

import '/screens/task_details_screen.dart';

import '../widgets/task_card.dart';

class AllTasksScreen extends StatefulWidget {
 static const routeName = '/all-tasks-screen';

 @override
 _AllTasksScreenState createState() => _AllTasksScreenState();
}

class _AllTasksScreenState extends State<AllTasksScreen> {
 var _selectedDate = DateFormat('dd/MM/yyyy').format(DateTime.now());
 var stagod;
 @override
 void initState() {
   stagod = Provider.of<Task>(context, listen: false);
   _selectedDate = DateFormat('dd/MM/yyyy').format(DateTime.now());
   super.initState();
 }

 @override
 Widget build(BuildContext context) {
   return Container(
     child: Column(
       mainAxisAlignment: MainAxisAlignment.start,
       children: [
         Material(
           elevation: 10,
           child: Container(
             child: Row(
               mainAxisAlignment: MainAxisAlignment.spaceAround,
               children: [
                 Text(
                   _selectedDate,
                   style: TextStyle(fontSize: 19, fontWeight: FontWeight.w600),
                 ),
                 ElevatedButton.icon(
                     icon: Icon(Icons.watch_later),
                     label: Text('Odaberi datum'),
                     onPressed: () {
                       showDatePicker(
                               context: context,
                               initialDate: DateTime.now(),
                               firstDate: DateTime(2001),
                               lastDate: DateTime(2222))
                           .then((date) {
                         setState(() {
                           _selectedDate =
                               DateFormat('dd/MM/yyyy').format(date!);
                         });
                       });
                     }),
               ],
             ),
           ),
         ),
         SizedBox(
           height: 10,
         ),
         Expanded(
           child: FutureBuilder(
             future: stagod.getAndSetTasks(false, _selectedDate),
             builder: (ctx, dataSnapshot) {
               if (dataSnapshot.connectionState == ConnectionState.waiting) {
                 return Center(child: CircularProgressIndicator());
               } else {
                 if (dataSnapshot.error != null) {
                   print(dataSnapshot.error);
                   return Center(
                     child: Text('Something went bang'),
                   );
                 } else {
                   return Consumer<Task>(builder: (context, taskData, child) {
                     return taskData.tasks.length == 0
                         ? Center(
                             child: Text('Nemate termina'),
                           )
                         : ListView.builder(
                             itemBuilder: (context, i) {
                               bool isNew = taskData.tasks[i].isNew as bool;
                               return Padding(
                                 padding:
                                     const EdgeInsets.fromLTRB(5, 0, 5, 5),
                                 child: Container(
                                   child: GestureDetector(
                                     onTap: () => Navigator.of(context)
                                         .pushNamed(
                                             TaskDetailsScreen.routeName,
                                             arguments: taskData.tasks[i]),
                                     child: Card(
                                       elevation: 10,
                                       child: Stack(children: <Widget>[
                                         Shimmer.fromColors(
                                           baseColor: Colors.green[500]!
                                               .withOpacity(isNew ? 0.5 : 0.0),
                                           highlightColor: Colors.white,
                                           period: Duration(seconds: 2),
                                           child: Container(
                                             height: 65,
                                             width: double.infinity,
                                             color: Colors.green[500]!
                                                 .withOpacity(isNew ? 1 : 0.0),
                                           ),
                                         ),
                                         TaskCard(taskData.tasks[i])
                                       ]),
                                     ),
                                   ),
                                 ),
                               );
                             },
                             itemCount: taskData.tasks.length,
                           );
                   });
                 }
               }
             },
           ),
         ),
       ],
     ),
   );
 }
}

db_helper.dart - future function that returns data from the db

import 'package:path/path.dart' as path;
import 'package:sqflite/sqflite.dart' as sql;
import '../providers/task.dart';

static Future<sql.Database> taskDB() async {
    var dbPath = await sql.getDatabasesPath();

    return sql.openDatabase(
      path.join(dbPath, 'tasks.db'),
      onCreate: (db, version) async {
        await db.execute(
            'CREATE TABLE pictures(id INTEGER PRIMARY KEY AUTOINCREMENT, photoPath TEXT, taskId INTEGER NOT NULL)');
        await db.execute(
            'CREATE TABLE newTasks (id INTEGER PRIMARY KEY AUTOINCREMENT,isNew	INTEGER,taskId INTEGER NOT NULL)');
        return db.execute(
            'CREATE TABLE tasks(id INTEGER PRIMARY KEY, pop TEXT, dp TEXT, address TEXT, addressNo TEXT, suppl TEXT, unit INTEGER, phoneNum TEXT, hbFinish TEXT, tfbFinish INTEGER, fazFinish TEXT, dateToComplete TEXT, completedDate TEXT, isMounting INTEGER, isActivation INTEGER, isMounted INTEGER, mountDate TEXT, isActivated INTEGER, activDate TEXT, comment TEXT, isDone INTEGER, isSent INTEGER, cantComplete INTEGER, cantCompleteReason INTEGER )');
      },
      version: 1,
    );
  } ```