my home screen
class Autentificacion extends StatelessWidget {
@override
Widget build(BuildContext context) {
final Auth auth = Provider.of(context).auth;
return StreamBuilder<String>(
stream: auth.onAuthStateChanged,
builder: (context, AsyncSnapshot<String> snapshot) {
if (snapshot.connectionState == ConnectionState.active) {
final bool loggedIn = snapshot.hasData;
if (loggedIn == true) {
return Home();
} else {
return Inicio_sesion();
}
}
return CircularProgressIndicator();
},
);
}
}
When having a session started, it sends to the following Home screen
The screen has a Drawer
list of items something similar to the following
int _SelectDrawerItem = 0;
_getDrawerItemWidget(int pos) {
switch (pos) {
case 0:
return PruebaPantalla();
case 1:
return Data_List(null);
}
}
@override
Widget build(BuildContext context) {
cargarData();
// print('userId de sharedPreferens =>${userId}');
return Scaffold(
appBar: AppBar(
title: Text(titulo),
),
drawer: Drawer(
child: ListView(...),
),
body: _getDrawerItemWidget(_SelectDrawerItem),
);
By default it sends toPruebaPantalla()
which contains a list of items.
class _PruebaPantallaState extends State<PruebaPantalla> {
GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey();
int count = 0;
@override
Widget build(BuildContext context) {
print("6.-Pantalla prueba");
// TODO: implement build
return Scaffold(
key: _scaffoldKey,
body: getApidataList(),
);
}
FutureBuilder getApidataList() {
return FutureBuilder(
future: ApiService.getdataList(),
builder: (context, snapshot) {
if (snapshot.connectionState == ConnectionState.done) {
print("3.-Entrada (conexion establecida)");
final data = snapshot.data;
return ListView.separated(
separatorBuilder: (context, index) {
return Divider(
height: 2,
color: Colors.black,
);
},
itemBuilder: (context, index) {
return ListTile(
title: Text(
data[index]['dataTitulo'].toString(),
style: TextStyle(
color: Colors.black, fontWeight: FontWeight.bold),
),
subtitle: Text(data[index]['dataTextoBiblico'].toString()),
onTap: () {
datadb datadb =
datadb("", 0, 0, "", "", "", "", "", "", "", 0);
datadb.setdataId = data[index]["dataId"];
datadb.setdataTipo = data[index]["dataTipo"];
datadb.setdataNum = data[index]["dataNum"];
datadb.setdataNumMasc = data[index]["dataNumMasc"];
datadb.setdataTitulo = data[index]["dataTitulo"];
datadb.setdataContenido = data[index]["dataContenido"];
datadb.setdataPartitura = data[index]["dataPartitura"];
datadb.setdataTextPublic =
data[index]["dataTextoBiblico"];
datadb.setdataDatosPublic =
data[index]["dataDatosComplementarios"];
datadb.setdataNota = data[index]["dataNota"];
datadb.setdataFechaActualizacion =
data[index]["dataFechaActualizacion"];
datadb.setdataStatus = 1;
navigateToDetail(datadb);
},
trailing: PopupMenuButton<dynamic>(
onSelected: showMenuSelection,
itemBuilder: (newContext) => [
PopupMenuItem(
child: Text("Agregar a mis listas"),
value: data[index],
)
]),
);
},
itemCount: data.length,
);
}
return Center(
child: CircularProgressIndicator(),
);
},
);
}
void navigateToDetail(datadb data) async {
bool result =
await Navigator.push(context, MaterialPageRoute(builder: (context) {
return dataDetalle(todo: data);
}));
}
// Envia a la interfaz Datalist para llevar el data seleccionado
void showMenuSelection(dynamic value) async {
bool result = await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => Data_List(value),
),
);
if (result) {
SnackBar snackBar = SnackBar(
content: Text('Se agrego correctamente a la Datalist'),
);
_scaffoldKey.currentState.showSnackBar(snackBar);
print(
"Se agrego correctamente a la Datalist--------------------------------");
// _showSnackBar();
}
}
void updateListView() {
final Future<Database> dbFuture = databaseHelper.initializeDatabase();
dbFuture.then((databse) {
Future<List<datadb>> dataListFuture = databaseHelper.getdataList();
dataListFuture.then((dataList) {
setState(() {
this.dataList = dataList;
this.count = dataList.length;
});
});
});
}
}
At the time of using showMenuSelection
it is found in each element of the list with a PopupMenuButton
command to the interface Data_list
. In Data_list
an element is selected and the data sent is added
Once added, the following line is used to return a true confirming the addition
Navigator.pop(context, true);
Returning to the screen _PruebaPantallaState
to generate the SnackBar
one found in the method showMenuSelection
to inform the user of the result where an exception is generated in the following line
_scaffoldKey.currentState.showSnackBar(snackBar);
The exception is the following.
NoSuchMethodError (NoSuchMethodError: The method 'showSnackBar' was called on null.
Receiver: null
Tried calling: showSnackBar(Instance of 'SnackBar'))
After reviewing your code, the error is the rebuilding of the widgets inside
StreamBuilder
this causes inconsistencies, the context is easily lost.I recommend you review the concepts of
StatefulWidget
so that later you can review a package/pattern/architecture for managing states, which can be 'Provider'.To fix it, don't use this validation
snapshot.connectionState == ConnectionState.active
, because at every widget refresh, the stream state always goes fromwaiting
toactive
, this causes unnecessary rebuild of the widgets, it's best to do it as follows.Put a null initialData, then in your validation you do a
if(snapshot !=null)
to check that it's loading.