flutter future builder 不断加载一对多关系

flutter future builder keeps loading one-to-many relationship

我正在尝试使用 rest api dart django 在单独的屏幕上查看来自数据的任务 project_id 它的一对多关系项目有很多任务,所以我想在使用 future builder

单击项目小部件时显示这些任务

编辑:我发现问题在下面检查我的答案 这是未来构建器和任务列表的用法

import 'package:flutter/material.dart';
import 'package:project/model/task_model.dart';
import 'package:project/project_dtetailForTest.dart';
import 'package:provider/provider.dart';
import 'new_project.dart';
import 'package:flutter/foundation.dart';
import 'package:http/http.dart' as http;
class  TaskById extends StatefulWidget {
  //const TaskById({ Key? key }) : super(key: key);
  final int project_id;
  //final Task task =Task();
  TaskById({required this.project_id}):super();
  @override
  State<TaskById> createState() => _TaskByIdState();
}

class _TaskByIdState extends State<TaskById> {

  @override
  Widget build(BuildContext context) {
    final taskP= Provider.of<TaskProvider>(context);
    return Scaffold(
      backgroundColor: Colors.white,
      appBar: AppBar(
        elevation: 0,
        bottom: PreferredSize(
        child: Container(
         color: const Color(0xff94adb4),
         height: 2,
         width: 320,
      ),
      preferredSize: const Size.fromHeight(4.0)),
        centerTitle: true,
        backgroundColor:const Color(0xff076792),
        title: const Text(
          'Project1',
           style: TextStyle(color: Colors.white,
             fontSize: 35,
             fontWeight:FontWeight.w700,
             shadows: [
               Shadow(
                  color: Color(0xa6A2B6D4),
                  blurRadius:20),
              ] ),
        ),
        leading: IconButton(
          onPressed: () {
            Navigator.pop(context);
          },
          icon: const Icon(
            Icons.arrow_back,
            size: 44,
          ),
        ),
       actions:[Container(padding: const EdgeInsets.fromLTRB(0, 0, 6, 3),
         child: IconButton(
            color:Colors.white ,
            icon: const Icon(
              Icons.search,
              size: 44,
            ),
            onPressed: () {},
          ),
       ),] 
      ),
      //TaskProvider(){
  //   this.fetchTask();
  // }
      body: FutureBuilder(
        future: TaskProvider().fetchTask(widget.project_id),
        builder: (context, snapshot){
          if (snapshot.hasError) print(snapshot.error);
          return snapshot.hasData && snapshot is List<Task>
          ?TaskList(task:snapshot.data as List<Task>)
          :Center(child: CircularProgressIndicator());
        }),

    //    FutureProvider(
    //     create: (context) => TaskProvider().fetchTask() ,
    //     initialData:  [CircularProgressIndicator()],
    //     child:Center(child: Consumer<Task>( 
    //       builder: (context, task, widget) {
    //         return (taskP !=null) ? Column(
    //     children: [
    //       Row(
    //         children:  const [
    //           Padding(padding: EdgeInsets.all(7),
    //            child: Padding(
    //             padding: EdgeInsets.fromLTRB(24,10,10,8),
    //             child: Text('Project1',
    //             style: TextStyle(
    //               color: Color(0xff076792),
    //               fontSize: 40,
    //               fontWeight: FontWeight.w600
    //             ),
    //             ),
    //            ),
    //           ),              
    //         ],
    //       ),
    //       // dynamic list
    //      Expanded(
    //        child: ListView.builder(
    //        itemCount: taskP.task.length ,
    //        itemBuilder: (BuildContext context, int index) {
    //          return  Padding(
    //         padding:  const EdgeInsets.fromLTRB(28, 12, 28, 0),
    //         child: GestureDetector(
    //           onTap: () {
               
    //             Navigator.push(context, MaterialPageRoute(builder: (context) => projectDetails()));
    //           },
    //            child: Card(child:Container(padding: const EdgeInsets.fromLTRB(18,8,9,4),
    //             width: 100,
    //             height: 100,
    //              decoration: BoxDecoration(
    //              borderRadius: BorderRadius.circular(19.0),
    //               color: const Color(0xff076792),
    //               boxShadow:  const [
    //               BoxShadow(color: Colors.black, spreadRadius: 1),
    //               BoxShadow(color: Color(0xa6A2B6D4),               
    //                  offset: Offset(7,5),
    //                  blurRadius:20),
    //               ],
    //               ),
    //             child: Column(children: [
    //               Row(mainAxisAlignment: MainAxisAlignment.start,
    //                 children: [
    //                   Text('Starting '+taskP.task[index].start.toString(),style:
    //                     const TextStyle(color: Color.fromARGB(255, 133, 186, 202),fontSize: 18,),
    //                    ),
    //                 ],
    //               ),
    //               const Spacer(),
    //               Row(mainAxisAlignment: MainAxisAlignment.center,
    //                 children: [
    //                   Text(taskP.task[index].title??'',style:
    //                    const TextStyle(color: Colors.white,fontSize: 34,)),
    //                 ],
    //               ),
    //               const Spacer(),
    //               Row(mainAxisAlignment: MainAxisAlignment.end,
    //                 children: [
    //                   Text('Ending '+taskP.task[index].end.toString(),style:
    //                    const TextStyle(color: Color.fromARGB(255, 133, 186, 202),
    //                    fontSize: 18,
    //                    )),
    //                 ],
    //               ),
    //             ]),
    //           ),),
    //         ),
    //       );
    //        }),
    //      )
    //      ],
    //   )
    //         : CircularProgressIndicator();
    //       },
    //     ) ,
        
    //     ) 
    // //         widget.project_id),
          
    // //       builder: (context, snapshot){
    // //         if (snapshot.hasError) print(snapshot.error);
    // //         return snapshot.hasData
    // //             ? TaskList(taskP: snapshot.data)
    // //             : Center(child: CircularProgressIndicator());
    // //       }),
    // )
    ); 
  }
}
class TaskList extends StatelessWidget {

  final List <Task> task;
  TaskList({Key? key, required this.task}) : super(key: key);
  @override
  Widget build(BuildContext context) {
      final taskP= Provider.of<TaskProvider>(context );
    // TODO: implement build
    return Column(
        children: [
          Row(
            children:  const [
              Padding(padding: EdgeInsets.all(7),
               child: Padding(
                padding: EdgeInsets.fromLTRB(24,10,10,8),
                child: Text('Project1',
                style: TextStyle(
                  color: Color(0xff076792),
                  fontSize: 40,
                  fontWeight: FontWeight.w600
                ),
                ),
               ),
              ),              
            ],
          ),
          // dynamic list
         Expanded(
           child: ListView.builder(
           itemCount: taskP.task.length ,
           itemBuilder: (BuildContext context, int index) {
             return  Padding(
            padding:  const EdgeInsets.fromLTRB(28, 12, 28, 0),
            child: GestureDetector(
              onTap: () {
               
                Navigator.push(context, MaterialPageRoute(builder: (context) => projectDetails()));
              },
               child: Card(child:Container(padding: const EdgeInsets.fromLTRB(18,8,9,4),
                width: 100,
                height: 100,
                 decoration: BoxDecoration(
                 borderRadius: BorderRadius.circular(19.0),
                  color: const Color(0xff076792),
                  boxShadow:  const [
                  BoxShadow(color: Colors.black, spreadRadius: 1),
                  BoxShadow(color: Color(0xa6A2B6D4),               
                     offset: Offset(7,5),
                     blurRadius:20),
                  ],
                  ),
                child: Column(children: [
                  Row(mainAxisAlignment: MainAxisAlignment.start,
                    children: [
                      Text('Starting '+taskP.task[index].start.toString(),style:
                        const TextStyle(color: Color.fromARGB(255, 133, 186, 202),fontSize: 18,),
                       ),
                    ],
                  ),
                  const Spacer(),
                  Row(mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      Text(taskP.task[index].title??'',style:
                       const TextStyle(color: Colors.white,fontSize: 34,)),
                    ],
                  ),
                  const Spacer(),
                  Row(mainAxisAlignment: MainAxisAlignment.end,
                    children: [
                      Text('Ending '+taskP.task[index].end.toString(),style:
                       const TextStyle(color: Color.fromARGB(255, 133, 186, 202),
                       fontSize: 18,
                       )),
                    ],
                  ),
                ]),
              ),),
            ),
          );
           }),
         )
         ],
      );
  }
}

这里是api和任务模型

// To parse this JSON data, do
//
//     final task = taskFromJson(jsonString);
import 'dart:collection';
import 'dart:core';
import 'package:flutter/foundation.dart';
import 'dart:convert';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

//List<Task> taskFromJson(String str) => List<Task>.from(json.decode(str).map((x) => Task.fromJson(x)));

//String taskToJson(List<Task> data) => json.encode(List<dynamic>.from(data.map((x) => x.toJson())));

class Task {
  String? url;
  int? id;
  String? owner;
  String? project;
  String? title;
  DateTime? start;
  DateTime? end;
  String? desc;
  int? project_id;

  Task(
      {this.url,
      this.id,
      this.owner,
      this.project,
      this.title,
      this.start,
      this.end,
      this.desc,
      this.project_id});

  
  factory Task.fromJson(Map<String, dynamic> json) => Task(
    url :json["url"],
    id: json["id"],
    owner: json["owner"],
    project: json["project"],
    title: json["title"],
    start: DateTime.parse(json["start"]),
    end: DateTime.parse(json["end"]),
    desc: json["desc"],
    project_id: json["project_id"],
    
    
  );

  Map<String, dynamic> toJson() => {
    "url": url,
    "id": id,
    "owner": owner,
    "project": project, 
    "title": title,
    "start": start?.toIso8601String(),
    "end": end?.toIso8601String(),
    "desc": desc,
    "project_id": project_id,
  };
}
class TaskProvider with ChangeNotifier{
  TaskProvider(){
    this.fetchTask();
  }


  List<Task> _task = [];
  List<Task> get task {
    return [..._task];
  }

    void addTask(Task task) async {
    final response = await http.post(Uri.parse('http://mostafahamed.pythonanywhere.com/project/task'),
        headers: {"Content-Type": "application/json"}, body: json.encode(task));
    if (response.statusCode == 201) {
      task.id = json.decode(response.body)['id'];
      _task.add(task);
      notifyListeners();
      print('suceeed add ed task');
      print(response.body);
    }else{
      print(response.body);
       print('failed add ed task');
    }
  }

  void deleteTask(Task task) async {
    final response =
        await http.delete(Uri.parse('http://mostafahamed.pythonanywhere.com/project/task${task.id}/'));
    if (response.statusCode == 204) {
      _task.remove(task);
      notifyListeners();
    }
  }


     Future<List<Task>> fetchTask([project_id]) async{
     final response = await http
      .get(Uri.parse('http://mostafahamed.pythonanywhere.com/tasks/?format=json'));
    if (response.statusCode==200){
      var data = json.decode(response.body)as List;
      _task=data.map<Task>((json) => Task.fromJson(json)).toList();
      
      
      notifyListeners();
       print('sucess view task list');
       print(response.body);
       return _task;
    }
   else {
     print(response.body);
     print(response.statusCode);
    // If the server did not return a 200 OK response,
    // then throw an exception.
    throw Exception('Failed to load tasks');
    
  }
  }
}

当我点击 project wiget 时,屏幕不断加载

我删除了条件 && snapshot is List from future builder 它工作得很好但是 如果你有可变的值,请确保防止使用未来的构建器作为未来的构建器获取数据,一旦我现在正在努力将未来的构建器转换为流构建器

如果你遇到同样的问题,请确保所有类型都相同 祝大家好运:)