I have got an error while working with Stream builders.
In my code, I used if(snapshot.data != null) { list.add(snapshot.data); } but I m getting a msg that add was called on null. I even added print('') statement to check if snapshot.data is null, but it is working fine with print() too. So I m not at all understanding how to solve this error. Someone please respond. Thanks in advance.
Here is my code
class Wrapper extends StatefulWidget {
#override
_WrapperState createState() => _WrapperState();
}
class _WrapperState extends State<Wrapper> {
Stream<FileSystemEntity> mystream;
var _directory;
void getfilesdata() async
{
_directory = await getApplicationDocumentsDirectory();
await Directory('${_directory.path}/data').create(recursive: true);
mystream = Directory('${_directory.path}/data').list().map((data) => data);
await Directory('${_directory.path}/documents').create(recursive: true);
}
#override
void initState() {
super.initState();
getfilesdata();
}
#override
Widget build(BuildContext context) {
List<FileSystemEntity> alldata;
return StreamBuilder<FileSystemEntity>(
stream: mystream,
builder: (context, snapshot) {
if(!snapshot.hasData)
{
print('No data yet');
return Loading();
}
else
{
if(snapshot.data != null && !snapshot.hasError)
{
print(snapshot.data);
alldata.add(snapshot.data);
}
if(snapshot.connectionState==ConnectionState.done)
{
return HomeScreen(alldata: alldata);
}
else return Loading();
}
}
);
}
}
And this is the result:
Performing hot restart...
Syncing files to device ZUK Z2132...
Restarted application in 1,734ms.
I/flutter (11840): No data yet
I/flutter (11840): No data yet
I/flutter (11840): File: '/data/user/0/com.example.easyscan/app_flutter/data/data[0]'
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following NoSuchMethodError was thrown building StreamBuilder<FileSystemEntity>(dirty, state: _StreamBuilderBaseState<FileSystemEntity, AsyncSnapshot<FileSystemEntity>>#25d1b):
The method 'add' was called on null.
Receiver: null
Tried calling: add(Instance of '_File')
The relevant error-causing widget was:
StreamBuilder<FileSystemEntity> file:///home/praneeth/AndroidStudioProjects/easyscan/lib/wrapper.dart:40:12
When the exception was thrown, this was the stack:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
#1 _WrapperState.build.<anonymous closure> (package:easyscan/wrapper.dart:53:25)
#2 StreamBuilder.build (package:flutter/src/widgets/async.dart:509:81)
#3 _StreamBuilderBaseState.build (package:flutter/src/widgets/async.dart:127:48)
#4 StatefulElement.build (package:flutter/src/widgets/framework.dart:4619:28)
...
════════════════════════════════════════════════════════════════════════════════════════════════════
Your error is because allData is null so you cannot call the add() method.
You can declare your variable as follow:
List<FileSystemEntity> alldata = [];
By doing this allData will be initialized as an empty list and you will be able to call its methods.
Related
I am trying to make a Flutter app that contains a login screen and then home screen (only two screens for now). I am using Flutter Secure Storage and Http libraries too.
Whenever the app launches, I want the app to check if two props, accessKey and accessId, are stored in the Secure storage. If accessId is not found, it is auto-generated and assigned with the Uuid library. Whereas the accessKey is not generated locally and is provided by an API.
App navigates to:
1). HomeScreen, if accessKey is stored in Secure Storage and authentication succeeds.
2). SignInScreen, if accessKey is not found or authentication fails.
My problem is, Secure Storage keeps throwing error "Null check operator used on a null value", everytime I perform a read operation. I have initialized the storage variable, yet this problem keeps happening.
Here is my Secure Storage class code:
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
class FAS {
static FlutterSecureStorage? _storage;
static void init() {
_storage = const FlutterSecureStorage(
aOptions: AndroidOptions(encryptedSharedPreferences: true),
);
}
static Future<String?> read(String key) async {
return _storage!.read(key: key);
}
static Future<Map<String, String>> readAll() async {
return _storage!.readAll();
}
static Future<void> write(String key, String value) async {
await _storage!.write(key: key, value: value);
}
static Future<void> delete(String key) async {
await _storage!.delete(key: key);
}
static Future<void> deleteAll() async {
await _storage!.deleteAll();
}
}
Before, the section of that code was this:
static const FlutterSecureStorage _storage = FlutterSecureStorage(aOptions: AndroidOptions(encryptedSharedPreferences: true));
There was no init method.
Yet I keep getting the same error.
Here is my main.dart:
import 'package:flutter/material.dart';
import 'package:unified_bot_app/pages/home_page.dart';
import 'package:uuid/uuid.dart';
import './models/fas.dart';
import './pages/sign_in_page.dart';
import './request_methods.dart';
Future<void> tryAssignAccessId() async {
String? accessId = await FAS.read("ACCESS_ID");
if (accessId == null) {
await FAS.write("ACCESS_ID", (const Uuid()).v4());
}
}
void main() {
FAS.init();
tryAssignAccessId(); // <- Error
runApp(
MaterialApp(
home: FutureBuilder<bool>(
builder: (ctx, a) {
if (a.connectionState == ConnectionState.done) {
if (a.data!) return HomePage();
return const SignInPage();
}
return const Center(child: CircularProgressIndicator());
},
future: () async {
try {
String? accessKey = await FAS.read("ACCESS_KEY");
if (accessKey == null) {
return false;
}
return await HTTP.authenticate(accessKey);
} catch (e) {
return false;
}
}(),
),
theme: ThemeData(fontFamily: "Josefin Sans"),
),
);
}
And here is the output I get when I restart the app:
Restarted application in 531ms. E/flutter (20760):
[ERROR:flutter/lib/ui/ui_dart_state.cc(209)] Unhandled Exception: Null
check operator used on a null value E/flutter (20760): #0
MethodChannel.binaryMessenger
package:flutter/…/services/platform_channel.dart:121 E/flutter
(20760): #1 MethodChannel._invokeMethod
package:flutter/…/services/platform_channel.dart:146 E/flutter
(20760): #2 MethodChannel.invokeMethod
package:flutter/…/services/platform_channel.dart:329 E/flutter
(20760): #3 MethodChannelFlutterSecureStorage.read
package:flutter_secure_storage_platform_interface/src/method_channel_flutter_secure_storage.dart:49
E/flutter (20760): #4 FlutterSecureStorage.read
package:flutter_secure_storage/flutter_secure_storage.dart:91
E/flutter (20760): #5 FAS.read
package:unified_bot_app/models/fas.dart:13 E/flutter (20760): #6
tryAssignAccessId package:unified_bot_app/main.dart:10 E/flutter
(20760): #7 main package:unified_bot_app/main.dart:18 E/flutter
(20760): #8 _runMainZoned..
(dart:ui/hooks.dart:145:25) E/flutter (20760): #9 _rootRun
(dart:async/zone.dart:1428:13) E/flutter (20760): #10
_CustomZone.run (dart:async/zone.dart:1328:19) E/flutter (20760): #11 _runZoned (dart:async/zone.dart:1863:10) E/flutter (20760): #12 runZonedGuarded (dart:async/zone.dart:1851:12) E/flutter (20760): #13
_runMainZoned. (dart:ui/hooks.dart:141:5) E/flutter (20760): #14 _delayEntrypointInvocation.
(dart:isolate-patch/isolate_patch.dart:283:19) E/flutter (20760): #15
_RawReceivePortImpl._handleMessage (dart:isolate-patch/isolate_patch.dart:184:12) E/flutter (20760):
D/EGL_emulation(20760): app_time_stats: avg=14143.50ms min=14143.50ms
max=14143.50ms count=1
However, the error disappears when I place first two lines in the end (after runApp(..)):
void main() {
runApp(
MaterialApp(
home: FutureBuilder<bool>(
builder: (ctx, a) {
if (a.connectionState == ConnectionState.done) {
if (a.data!) return HomePage();
return const SignInPage();
}
return const Center(child: CircularProgressIndicator());
},
future: () async {
try {
String? accessKey = await FAS.read("ACCESS_KEY"); // <- Error re-appears here
if (accessKey == null) {
return false;
}
return await HTTP.authenticate(accessKey);
} catch (e) {
return false;
}
}(),
),
theme: ThemeData(fontFamily: "Josefin Sans"),
),
);
FAS.init();
tryAssignAccessId();
}
But doing that, the error then re-appears on the marked line.
I am confused. What's happening?
Any help is appreciated.
Edit 1:
I tried calling the init() method before I call the second read() method, yet the same error is thrown.
Updated section:
future: () async {
try {
FAS.init();
String? accessKey = await FAS.read("ACCESS_KEY");
if (accessKey == null) {
return false;
}
return await HTTP.authenticate(accessKey);
} catch (e) {
print(e);
return false;
}
}(),
Console output:
Restarted application in 510ms. I/flutter (20760): Null check operator
used on a null value D/EGL_emulation(20760): app_time_stats:
avg=1899.03ms min=1899.03ms max=1899.03ms count=1
I solved this by adding
WidgetsFlutterBinding.ensureInitialized();
to the main() method before runApp().
I fixed this issue by adding a new Blank page containing all the methods.
Blank page file:
import 'package:flutter/material.dart';
import 'package:uuid/uuid.dart';
import '../models/fas.dart';
import '../request_methods.dart';
import './home_page.dart';
import './sign_in_page.dart';
class BlankPage extends StatelessWidget {
Future<void> _tryAssignAccessId() async {
String? accessId = await FAS.read("ACCESS_ID");
if (accessId == null) {
await FAS.write("ACCESS_ID", (const Uuid()).v4());
}
}
Future<bool> _checkAuth() async {
try {
String? accessKey = await FAS.read("ACCESS_KEY");
if (accessKey == null) {
return false;
}
return await HTTP.authenticate(accessKey);
} catch (e) {
return false;
}
}
#override
Widget build(BuildContext context) {
FAS.init();
_tryAssignAccessId();
_checkAuth().then((result) {
if (result) {
Navigator.of(context)
.pushReplacement(MaterialPageRoute(builder: (ctx) => HomePage()));
} else {
Navigator.of(context).pushReplacement(
MaterialPageRoute(builder: (ctx) => const SignInPage()));
}
});
return Scaffold();
}
}
Updated main.dart (for ref.):
import 'package:flutter/material.dart';
import './pages/blank.dart';
void main() {
runApp(
MaterialApp(
home: BlankPage(),
theme: ThemeData(fontFamily: "Josefin Sans"),
),
);
}
I am trying to fetch data from api its splash screen of my app I want user wait 5 second when app is launched and then go to next screen but when I tried fetch data from api I received The getter 'length' was called on null. please help me here is my code I tried resolve it number of other resources but failed to find solution that's why I am posting my question is here please check and help
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter_app/main.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
void main() {
runApp(new MaterialApp(
home: new SplashScreen(),
debugShowCheckedModeBanner: false,
routes: <String, WidgetBuilder>{
'/MyHomePage': (BuildContext context) => new MyHomePage()
},
));
}
class SplashScreen extends StatefulWidget {
#override
_SplashScreenState createState() => new _SplashScreenState();
}
class _SplashScreenState extends State<SplashScreen> {
startTime() async {
var _duration = new Duration(seconds: 5);
return new Timer(_duration, navigationPage);
}
void navigationPage() {
Navigator.of(context).pushReplacementNamed('/MyHomePage');
}
bool _loading=true;
Map data;
List userData=null;
Future getData() async {
http.Response response = await http.get("https://livinghopemobile.com/public/api/fetch-site-settings?token=123ab_#_#AbCD");
data = json.decode(response.body);
debugPrint(response.body);
setState(() {
userData = data["data"];
_loading=false;
// print(userData[0]['title']);
});
}
#override
void initState() {
super.initState();
//startTime();
getData();
}
#override
Widget build(BuildContext context) {
return new Scaffold(
body: ListView.builder(
itemCount:userData.length,
itemBuilder: (context, index) {
return Container(
child: Image.network(userData[index]['site_logo']),
);
}
)
);
}
}
Launching lib/ui/SplashScreen.dart on iPhone 11 Pro Max in debug mode...
Running Xcode build...
Xcode build done. 23.8s
Debug service listening on ws://127.0.0.1:60469/bL7bmRYyhoc=/ws
Syncing files to device iPhone 11 Pro Max...
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following NoSuchMethodError was thrown building SplashScreen(dirty, state: _SplashScreenState#5fa75):
The getter 'length' was called on null.
Receiver: null
Tried calling: length
The relevant error-causing widget was:
SplashScreen file:///Users/apple/livinghopev4/livinghope4ios/lib/ui/SplashScreen.dart:10:15
When the exception was thrown, this was the stack:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:54:5)
#1 _SplashScreenState.build (package:flutter_app/ui/SplashScreen.dart:61:30)
#2 StatefulElement.build (package:flutter/src/widgets/framework.dart:4612:27)
#3 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:4495:15)
#4 StatefulElement.performRebuild (package:flutter/src/widgets/framework.dart:4667:11)
...
════════════════════════════════════════════════════════════════════════════════════════════════════
flutter: {"status":200,"message":"Data fetched successfully","data":{"id":1,"site_logo":"https:\/\/livinghopemobile.com\/public\/storage\/site_logo\/270421_122025_image.png","site_name":"Living hope","created_at":null,"updated_at":"2021-04-27T07:20:26.000000Z"}}
[VERBOSE-2:ui_dart_state.cc(186)] Unhandled Exception: type '_InternalLinkedHashMap<String, dynamic>' is not a subtype of type 'List<dynamic>'
#0 _SplashScreenState.getData.<anonymous closure> (package:flutter_app/ui/SplashScreen.dart:41:7)
#1 State.setState (package:flutter/src/widgets/framework.dart:1267:30)
#2 _SplashScreenState.getData (package:flutter_app/ui/SplashScreen.dart:40:5)
<asynchronous suspension>
This is because data is not type List, and userData is null hence there is no length to it when you are calling userData.length in ListView.builder.
Change null to [].
{"status":200,"message":"Data fetched successfully","data":{"id":1,"site_logo":"https:\/\/livinghopemobile.com\/public\/storage\/site_logo\/270421_122025_image.png","site_name":"Living hope","created_at":null,"updated_at":"2021-04-27T07:20:26.000000Z"}}
You could append the received data to userData, like: userData.add(data).
You try it:
itemCount:userData.length == null ? 0 : userData.length
Data is returning in Object and you are taking it as List. This is the reason you are getting the error.
Solution:
Don't use Listview.builder as api response is just an object(Map<String, dynamic>).
You can simply use
Image.network(userData['site_logo']),
and everthing will be fine.
I'm Using provider in initState() to call the api but if I use listen:false then it does not update UI and it always shows me loader but if I use listen:true then app works fine but in the terminal it shows me exception and tells me write listen:false.
My UI,
class ChopperNewsCard extends StatefulWidget {
#override
_ChopperNewsCardState createState() => _ChopperNewsCardState();
}
class _ChopperNewsCardState extends State<ChopperNewsCard> {
ScrollController scrollController = ScrollController();
int currentPage = 5;
ChopperApiStore _apiStore = ChopperApiStore();
#override
void initState() {
super.initState();
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
_apiStore = Provider.of<ChopperApiStore>(context,);//<--- here it tells me to write listen:false
});
_apiStore.getResponse(currentPage);
scrollController.addListener(() {
if (scrollController.position.pixels ==
scrollController.position.maxScrollExtent) {
if (currentPage < 20) {
currentPage = currentPage + 5;
_apiStore.getResponse(currentPage);
}
}
});
}
#override
void dispose() {
scrollController.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
var height = MediaQuery.of(context).size.height;
var width = MediaQuery.of(context).size.width;
return Observer(builder: (context) {
return Container(
height: height * 0.37,
width: double.infinity,
child: _apiStore.res.articles == null
? CircularProgressIndicator()
: ListView.builder(...),
);
});
}
}
api calling class,
class ChopperApiStore extends _ChopperApiStore with _$ChopperApiStore{}
abstract class _ChopperApiStore with Store{
ApiCall apiCall = ApiCall();
#observable
ChopperNews res = ChopperNews();
#action
Future<void> getResponse(int page) async {
var data = await apiCall.getNews(page);
res = data;
}
}
the error I'm getting,
======== Exception caught by scheduler library =====================================================
The following assertion was thrown during a scheduler callback:
Tried to listen to a value exposed with provider, from outside of the widget tree.
This is likely caused by an event handler (like a button's onPressed) that called
Provider.of without passing `listen: false`.
To fix, write:
Provider.of<ChopperApiStore>(context, listen: false);
It is unsupported because may pointlessly rebuild the widget associated to the
event handler, when the widget tree doesn't care about the value.
The context used was: ChopperNewsCard(dependencies: [MediaQuery], state: _ChopperNewsCardState#8f6cd)
'package:provider/src/provider.dart':
Failed assertion: line 262 pos 7: 'context.owner.debugBuilding ||
listen == false ||
debugIsInInheritedProviderUpdate'
When the exception was thrown, this was the stack:
#2 Provider.of (package:provider/src/provider.dart:262:7)
#3 _ChopperNewsCardState.initState.<anonymous closure> (package:fruitley/week-5/bonus/chopper/widgets/chopper_news_card.dart:32:28)
#4 SchedulerBinding._invokeFrameCallback (package:flutter/src/scheduler/binding.dart:1117:15)
#5 SchedulerBinding.handleDrawFrame (package:flutter/src/scheduler/binding.dart:1063:9)
#6 SchedulerBinding._handleDrawFrame (package:flutter/src/scheduler/binding.dart:971:5)
...
I think if you want to use listen:true to have the build method called you are suppose to override didChangeDependencies rather then initState Checkout this article it might help https://medium.com/swlh/flutter-provider-and-didchangedependencies-15678f502262
ok I'm dumb. I didn't even need to use addPostFrameCallback.
I just removed it and if I want to use provider outside of widget tree that I must use listen:false as it was showing in the exception so now everything makes sense.
I am trying to achieve a functionality where the app displays all the users' details in a grid view except the current user's. I have been trying to assign snapshots to _stream and then apply the _stream value in StreamBuilder(). But it throws an error instead.
Database _database = Database();
Stream _stream;
String currentUserId;
#override
void initState() {
getCurrentUserId(); //currentUserId gets its value here
getAllUsers();
super.initState();
}
getAllUsers() async {
Stream<QuerySnapshot> snapshots = await _database.getAllUsers();
_stream = snapshots.map((querySnapshot) => querySnapshot.documents.where((documentSnapshot)
=> documentSnapshot.data["userId"] != currentUserId
).toList())
}
//..
StreamBuilder(
stream: _stream,
builder: (context, snapshot) {
if (snapshot.data != null)
//..
}
//..
)
NEW: if I add as QuerySnapshot, the snapshot in the StreamBuilder will be null instead of throwing an exception.
// NEW
_stream = snapshots.map((querySnapshot) => querySnapshot.documents.where((documentSnapshot)
=> documentSnapshot.data["userId"] != currentUserId
).toList() as QuerySnapshot);
Database class
getAllUsers() async {
return await _firestore.collection("users").snapshots();
}
Exception
════════ Exception caught by widgets library ═══════════════════════════════════════════════════════
The following NoSuchMethodError was thrown building StreamBuilder<dynamic>(dirty, state: _StreamBuilderBaseState<dynamic, AsyncSnapshot<dynamic>>#6e31f):
Class 'List<DocumentSnapshot>' has no instance getter 'documents'.
Receiver: Instance(length:2) of '_GrowableList'
Tried calling: documents
The relevant error-causing widget was:
StreamBuilder<dynamic> file:///Users/suriantosurianto/AndroidStudioProjects/apui/lib/fragments/home_fragment.dart:66:12
When the exception was thrown, this was the stack:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:53:5)
#1 _HomeFragmentState.build.<anonymous closure> (package:apui/fragments/home_fragment.dart:80:42)
#2 StreamBuilder.build (package:flutter/src/widgets/async.dart:509:81)
#3 _StreamBuilderBaseState.build (package:flutter/src/widgets/async.dart:127:48)
#4 StatefulElement.build (package:flutter/src/widgets/framework.dart:4619:28)
...
════════════════════════════════════════════════════════════════════════════════════════════════════
We do not know which line is this error pointing, however if I understand correctly the reason might be type of StreamBuilder property stream that should be of Stream class (reference).
Seems _stream is a list created from stream using toList method (reference). I would try to remove this toList method, and see what will happen.
I hope it will help!
// NEW
_stream = snapshots.map((querySnapshot) => querySnapshot.documents.where((documentSnapshot)
=> documentSnapshot.data["userId"] != currentUserId
).toList() as QuerySnapshot);
here the querySnapshot is a List<DocumentSnapshot>!!!
you are probably have to use querySnapshot.where()
As others point out, querySnapshot is a List<DocumentSnapshot> and not DocumentSnapshot, so you can't use the getter .documents(that getter is for DocumentSnapshot only, not for a List), This is becasue is retrieving the DocumentSnapshot of every user except the current user (a DocumentSnapshot for each user, so a List<DocumentSnapshot>).
If you want to return a Stream of type of List<DocumentSnapshot> then
_stream = snapshots
.map<List<DocumentSnapshot>>((querySnapshot) =>
querySnapshot.where((documentSnapshot) =>
documentSnapshot.data["userId"] != currentUserId)
);
I'm using the following FutureBuilder to handle fetching 'squad' info from a Firebase database, but the Future is saying it's done before I can process all the data form the database:
#override
Widget build(BuildContext context) {
return FutureBuilder(
future: _getUserSquads(),
builder: (ctx, snapshot) {
if (snapshot.connectionState == ConnectionState.waiting) {
return Center(
child: CircularProgressIndicator(),
);
} else {
if (_userSquads == null) {...} else {
print(snapshot.connectionState);
return Text(_userSquads.length.toString());
}
}
},
);
... the following two functions are the functions I need to be completed before the FutureBuilder is done:
Future<void> _getUserSquads() async {
print('1');
final squadIdsResult = await _userSquadsRef.once();
print('2');
if (squadIdsResult.value == null) {
print('3');
return;
}
print('4');
_userSquadIds = squadIdsResult.value;
print('5');
final test = await _test();
print('6');
}
Future<void> _test() {
print('7');
_userSquadIds.forEach((key, value) async {
print('itter');
final result = await _squadsRef.child(key).once();
_userSquads.add(result.value);
print(result.value);
print(_userSquads);
});
print('8');
print('9');
}
The two print statements print(result.value) and print(_useraSquads) don't execute until after the Future's connection state is done:
I/flutter (29217): 2
I/flutter (29217): 4
I/flutter (29217): 5
I/flutter (29217): 7
I/flutter (29217): itter
I/flutter (29217): 8
I/flutter (29217): 9
I/flutter (29217): 6
I/flutter (29217): ConnectionState.done
I/flutter (29217): {squadName: SAFTS}
I/flutter (29217): [{squadName: SAFTS}]
It seems like the problem is in the _test() function, but I've tried a hundred different ways to write this, and I can't figure out how to make sure that the code is done fetching the data from the database in the forEach block before the Future is set to done.
Your _userSquadIds's foreach is creating issue. If you want to make it async the you can use Future.forEach.
Change following code.
_userSquadIds.forEach((key, value) async {
print('itter');
final result = await _squadsRef.child(key).once();
_userSquads.add(result.value);
print(result.value);
print(_userSquads);
});
With Following one.
await Future.forEach(_userSquadIds, (key,value) async {
print('itter');
final result = await _squadsRef.child(key).once();
_userSquads.add(result.value);
print(result.value);
print(_userSquads);
});