简体   繁体   中英

flutter how to make gridview show firebase data like buttons

I am trying to user Streambuilder to display gridview, but it return this error, I am calling the method classList() to container in scaffold body

database = FirebaseDatabase.instance

数据库映像

I want to show classData, show 0,1,2..etc I want to show ('className','classSection' in one button per child) in gridview as RaisedButtons

I get this error when the code below is executed

I/flutter ( 5433): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter ( 5433): The following NoSuchMethodError was thrown building HomePage(dirty, state: _HomePage#055be):
I/flutter ( 5433): The method 'split' was called on null.
I/flutter ( 5433): Receiver: null
I/flutter ( 5433): Tried calling: split("/")
I/flutter ( 5433): 
I/flutter ( 5433): When the exception was thrown, this was the stack:
I/flutter ( 5433): #0      Object.noSuchMethod (dart:core/runtime/libobject_patch.dart:50:5)
I/flutter ( 5433): #1      DatabaseReference.child (file:///G:/flutter/.pub-cache/hosted/pub.dartlang.org/firebase_database-2.0.3/lib/src/database_reference.dart:24:58)
I/flutter ( 5433): #2      _HomePage.classList (package:barcode_scan_example/home_page.dart:169:44)
I/flutter ( 5433): #3      _HomePage.build (package:barcode_scan_example/home_page.dart:265:30)
I/flutter ( 5433): #4      StatefulElement.build (package:flutter/src/widgets/framework.dart:3825:27)
I/flutter ( 5433): #5      ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3736:15)
I/flutter ( 5433): #6      Element.rebuild (package:flutter/src/widgets/framework.dart:3559:5)
I/flutter ( 5433): #7      ComponentElement._firstBuild (package:flutter/src/widgets/framework.dart:3716:5)
I/flutter ( 5433): #8      StatefulElement._firstBuild (package:flutter/src/widgets/framework.dart:3864:11)
I/flutter ( 5433): #9      ComponentElement.mount (package:flutter/src/widgets/framework.dart:3711:5)
I/flutter ( 5433): #10     Element.inflateWidget (package:flutter/src/widgets/framework.dart:2956:14)
I/flutter ( 5433): #11     Element.updateChild (package:flutter/src/widgets/framework.dart:2759:12)
I/flutter ( 5433): #12     ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3747:16)
I/flutter ( 5433): #13     Element.rebuild (package:flutter/src/widgets/framework.dart:3559:5)
I/flutter ( 5433): #14     BuildOwner.buildScope (package:flutter/src/widgets/framework.dart:2273:33)
I/flutter ( 5433): #15     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding&WidgetsBinding.drawFrame (package:flutter/src/widgets/binding.dart:700:20)
I/flutter ( 5433): #16     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding&PaintingBinding&SemanticsBinding&RendererBinding._handlePersistentFrameCallback (package:flutter/src/rendering/binding.dart:268:5)
I/flutter ( 5433): #17     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:988:15)
I/flutter ( 5433): #18     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:928:9)
I/flutter ( 5433): #19     _WidgetsFlutterBinding&BindingBase&GestureBinding&ServicesBinding&SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:840:5)
I/flutter ( 5433): #23     _invoke (dart:ui/hooks.dart:209:10)
I/flutter ( 5433): #24     _drawFrame (dart:ui/hooks.dart:168:3)
I/flutter ( 5433): (elided 3 frames from package dart:async)
classList() {
    StreamBuilder(
        stream:
            database.reference().child('user').child(userUid).child('classData').orderByKey().onValue,
        builder: (BuildContext context, AsyncSnapshot<Event> snapshot) {
          if (snapshot.hasData) {
            if (snapshot.data.snapshot.value != null) {
              Map<dynamic, dynamic> map = snapshot.data.snapshot.value;
              List<dynamic> list = map.values.toList();
              print("list is : $list");

              return GridView.builder(
                gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: 3),
                itemCount: list.length,
                padding: EdgeInsets.all(2.0),
                itemBuilder: (BuildContext context, int index) {
                  print("print job ${list[index]["className"]}");
                  return Container(
                    child: RaisedButton(
                      onPressed: null,
                      child: Text(
                          "${list[index]["className"]}\n ${list[index]["classSection"]}"),
                    ),
                    padding: EdgeInsets.all(2.0),
                  );
                },
              );
            } else {
              return Container(
                  child: Center(
                      child: Text(
                "There's no Class registered in the system",
                style: TextStyle(fontSize: 20.0, color: Colors.grey),
                textAlign: TextAlign.center,
              )));
            }
          } else {
            return CircularProgressIndicator();
          }
        });
  }

the entire dart file

import 'package:flutter/material.dart';
import 'auth.dart';
import 'auth_provider.dart';
import 'package:firebase_auth/firebase_auth.dart';
import 'package:flutter/services.dart';
import 'make_class.dart';
import 'dart:async';
import 'package:barcode_scan/barcode_scan.dart';
import 'package:firebase_database/firebase_database.dart';
import 'qr_screen.dart';

class HomePage extends StatefulWidget {
  @override
  _HomePage createState() => _HomePage();
}

enum ScaffoldType { student, lecturer }

ScaffoldType _scaffoldType = ScaffoldType.lecturer;

class _HomePage extends State<HomePage> {
  final FirebaseDatabase database = FirebaseDatabase.instance;

  String barcode = "";
  String userUid;
  var userClass;



  Future<void> _signOut(BuildContext context) async {
    try {
      final BaseAuth auth = AuthProvider.of(context).auth;
      await auth.signOut();
    } catch (e) {
      print(e);
    }
  }

  @override
  void initState() {
    super.initState();
    userUi();
    setState(() async* {
      FirebaseDatabase database;
      database = FirebaseDatabase.instance;
      database.setPersistenceEnabled(true);
      database.setPersistenceCacheSizeBytes(10000000);
    });
  }

  Future reUser() async {
    FirebaseUser user = await FirebaseAuth.instance.currentUser();
    print(user.uid);
    var userUid = user.uid;
    var userWho = await database
        .reference()
        .child('user')
        .child(userUid)
        .once()
        .then((DataSnapshot snapshot) {
      Map<dynamic, dynamic> data = snapshot.value;
      var isL = data.values.toList();
      print(isL[1]);
      print(data.values);
      if (isL[1].toString().toLowerCase() == "true") {
        _scaffoldType = ScaffoldType.lecturer;
        print('lecturer');
      } else if (isL[1].toString().toLowerCase() == "false") {
        _scaffoldType = ScaffoldType.student;
        print("student");
      }
    });
//        print(userWho);
  }



  userUi() async {
    FirebaseUser user = await FirebaseAuth.instance.currentUser();
    print(user.uid);
    return user.uid;
  }

  classList(userUid) {

    print(userUid);
    StreamBuilder(
        stream:
        database.reference().child('user').child(userUid).child('classData').orderByKey().onValue,
        builder: (BuildContext context, AsyncSnapshot<Event> snapshot) {
          if (snapshot.hasData) {
            if (snapshot.data.snapshot.value != null) {
              Map<dynamic, dynamic> map = snapshot.data.snapshot.value;
              List<dynamic> list = map.values.toList();
              print("list is : $list");

              return GridView.builder(
                gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                    crossAxisCount: 3),
                itemCount: list.length,
                padding: EdgeInsets.all(2.0),
                itemBuilder: (BuildContext context, int index) {
                  print("print job ${list[index]["className"]}");
                  return Container(
                    child: RaisedButton(
                      onPressed: (){},
                      child: Text(
                          "${list[index]["className"]}\n ${list[index]["classSection"]}"),
                    ),
                    padding: EdgeInsets.all(2.0),
                  );
                },
              );
            } else {
              return Container(
                  child: Center(
                      child: Text(
                        "There's no Class registered in the system",
                        style: TextStyle(fontSize: 20.0, color: Colors.grey),
                        textAlign: TextAlign.center,
                      )));
            }
          } else {
            return CircularProgressIndicator();
          }
        });
  }

  @override
  Widget build(BuildContext context) {
//    var userUid = userUi();
    reUser();
    return Scaffold(
      appBar: AppBar(
        title: Text('Welcome'),
        actions: <Widget>[
          FlatButton(
            child: Icon(Icons.exit_to_app),
            onPressed: () => _signOut(context),
          )
        ],
      ),
      bottomNavigationBar: BottomAppBar(
        notchMargin: 8.0,
        child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Padding(
            padding: const EdgeInsets.fromLTRB(35, 0, 35, 0),
            child: Row(
              mainAxisSize: MainAxisSize.max,
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                Column(
                  mainAxisSize: MainAxisSize.min,
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: buttonBelow(),
                ),
                Column(
                  mainAxisSize: MainAxisSize.min,
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: buttonBelow2(),
                ),
              ],
            ),
          ),
        ),
        shape: CircularNotchedRectangle(),
      ),
      resizeToAvoidBottomInset: true,
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
      floatingActionButton: Container(
        height: 80,
        width: 80,
        child: FittedBox(
          child: FloatingActionButton(
            onPressed: scan,
            child: Icon(
              Icons.camera,
              size: 35,
            ),
            elevation: 2.0,
          ),
        ),
      ),
      body: Container(child: classList(userUi()),),
    );
  }

  List<Widget> buttonBelow() {
    if (_scaffoldType == ScaffoldType.lecturer) {
      return <Widget>[
        FlatButton(
          child: Icon(
            Icons.add_circle,
            semanticLabel: "Add Class",
            size: 45,
          ),
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => MakeClass()),
            );
          },
          shape:
              RoundedRectangleBorder(borderRadius: BorderRadius.circular(180)),
        ),
        Text("Add Class")
      ];
    } else {
      return <Widget>[
        Opacity(
          opacity: 0,
          child: FlatButton(
            onPressed: () {},
            child: Icon(
              Icons.add_circle,
              semanticLabel: "Add Class",
              size: 45,
            ),
            shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(180)),
          ),
        ),
        Opacity(opacity: 0, child: Text("Add Class"))
      ];
    }
  }
  List<Widget> buttonBelow2() {
    if (_scaffoldType == ScaffoldType.lecturer) {
      return <Widget>[
        FlatButton(
          child: Icon(
            Icons.blur_on,
            semanticLabel: "QRCode",
            size: 45,
          ),
          onPressed: () {
            Navigator.push(
              context,
              MaterialPageRoute(builder: (context) => QrScreen()),
            );
          },
          shape:
          RoundedRectangleBorder(borderRadius: BorderRadius.circular(180)),
        ),
        Text("QRCode")
      ];
    }
  }

  Future scan() async {
    try {
      String barcode = await BarcodeScanner.scan();
      setState(() => this.barcode = barcode);
    } on PlatformException catch (e) {
      if (e.code == BarcodeScanner.CameraAccessDenied) {
        setState(() {
          this.barcode = 'The user did not grant the camera permission!';
        });
      } else {
        setState(() => this.barcode = 'Unknown error: $e');
      }
    } on FormatException {
      setState(() => this.barcode =
          'null (User returned using the "back"-button before scanning anything. Result)');
    } catch (e) {
      setState(() => this.barcode = 'Unknown error: $e');
    }
  }
}

Main problem is when we pass blank or null string in ".child()" method of firebase, it will give us split("/") error because internally it will try to split from string and get try to get data from it.

Now the problem in your code is you are calling "classList(userUid)" in the widget override method before the data come from firebase userid with use of StreamBuilder() but the userUid is blank and as i said above, firebase will give us split("/") error if we pass blank or null in that ".child()" method.

So the conclusion is we have to wait for firebase userid until we get it from async result because to get firebase userid which is async task and we have to wait for that until result come with using await keyword.

So Here is the answer, how to do that: You have to replace your body portion in widget with the use of future<> such as below:

@override
Widget build(BuildContext context) {
  return Scaffold(
      appBar: AppBar(
        title: Text('Welcome'),
        actions: <Widget>[
          FlatButton(
            child: Icon(Icons.exit_to_app),
            onPressed: () => _signOut(context),
          )
        ],
      ),
      bottomNavigationBar: BottomAppBar(
        notchMargin: 8.0,
        child: Padding(
          padding: const EdgeInsets.all(8.0),
          child: Padding(
            padding: const EdgeInsets.fromLTRB(35, 0, 35, 0),
            child: Row(
              mainAxisSize: MainAxisSize.max,
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: <Widget>[
                Column(
                  mainAxisSize: MainAxisSize.min,
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: buttonBelow(),
                ),
                Column(
                  mainAxisSize: MainAxisSize.min,
                  mainAxisAlignment: MainAxisAlignment.center,
                  children: buttonBelow2(),
                ),
              ],
            ),
          ),
        ),
        shape: CircularNotchedRectangle(),
      ),
      resizeToAvoidBottomInset: true,
      floatingActionButtonLocation: FloatingActionButtonLocation.centerDocked,
      floatingActionButton: Container(
        height: 80,
        width: 80,
        child: FittedBox(
          child: FloatingActionButton(
            onPressed: scan,
            child: Icon(
              Icons.camera,
              size: 35,
            ),
            elevation: 2.0,
          ),
        ),
      ),
      body: new FutureBuilder<FirebaseUser>(
       future: FirebaseAuth.instance.currentUser(),
       builder: (BuildContext context, AsyncSnapshot<FirebaseUser> snapshot) {
         if (snapshot.connectionState == ConnectionState.done) {
           return new Container(child: classList(snapshot.data.uid));
         }
         else {
           return new Text('Loading...');
         }
       },
      ),
    );
}

Also the best practice is that you have to get firebase userid only in "initState()" method which will call only once during lifecycle. so declare "FirebaseUser user" globally in your class and then call your "userUi()" in only "initState()" method.

The method 'split' was called on null. This type of exceptions occurs whenever you are referencing a path that doesn't exist. So make sure the path of your firebase database is correct.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM