I/flutter ( 4037): The method '[]' was called on null - flutter

I am getting an error trying to run this code about the method '[]' being null. Is it maybe the list view? The output doesn't even show up in debug console anymore. Sorry I'm new to this.
The code:
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;
import 'dart:convert';
class GetStats extends StatefulWidget {
#override
_GetStatsState createState() => _GetStatsState();
}
class _GetStatsState extends State<GetStats> {
Map data;
Future<String> getData() async {
var response = await http.get(
Uri.encodeFull(
'http://api.steampowered.com/ISteamUserStats/GetUserStatsForGame/v0002/?appid=730&key=D5F4E0DED484F47380C2804A529BAEDC&steamid=76561198406742636'),
headers: {"Accept": "application/json"});
setState(() {
data = json.decode(response.body);
});
print(data["playerstats"]["stats"][0]["value"]);
}
#override
void initState() {
getData();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('CSGO STATS'),
centerTitle: true,
),
body: ListView.builder(
itemCount: 20,
itemBuilder: (
BuildContext context,
int index,
) {
return Card(
child: Text(
data["playerstats"],
),
);
}),
);
}
}
Error
I/flutter ( 4037): ══╡ EXCEPTION CAUGHT BY WIDGETS LIBRARY ╞═══════════════════════════════════════════════════════════
I/flutter ( 4037): The following NoSuchMethodError was thrown building:
I/flutter ( 4037): The method '[]' was called on null.
I/flutter ( 4037): Receiver: null
I/flutter ( 4037): Tried calling: []("playerstats")
I/flutter ( 4037):
I/flutter ( 4037): When the exception was thrown, this was the stack:
What am I doing wrong? Do I need to initialize something?

You are making correct http request and getting data too
However the problem lies in your widget , I checked the API response it is throwing a response of Map<String,dynamic>
While displaying the data you are accessing the data using playerstats key which in turn is giving you a Map which is not a String as required by Text Widget in order to display it !
You can display the data by simply converting it to String by using toString() method like this
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('CSGO STATS'),
centerTitle: true,
),
body: ListView.builder(
itemCount: 20,
itemBuilder: (
BuildContext context,
int index,
) {
return Card(
child: Text(
data["playerstats"].toString(),
),
);
}),
);
}
Also, I would like to suggest you some Improvements in your Code
Use type annotation as much as possible, It makes your code more safe and robust , Like you have declared data variable as Map data; , You should declare it like Map<String,dynamic> data;
I think you forget to call super.initState() in your initState() method , Make sure to call it before all your methods.
Method getData doesn't return anything, So make it as Future<void> instead of Future<String>
Since you are new contributor to StackOverflow , I welcome you !
Happy Fluttering !

data["playerstats"] is a Map while the Text widget needs String.

Your method is ok, but the problem is in initiating the text widget.
child: Text(
data["playerstats"],
),
['playerstats'] is not a single text, its a map of list. You need to specify the exact text field name you want to see. Still it will show you full data if you add .toString() with the field name.

Related

NoSuchMethodError when taking Screenshot

I am trying to take a Screanshot of a Stak with a list of iteams in it. It displays normaly and works, but when i try to take screenshot of the Widget I resive:
NoSuchMethodError (NoSuchMethodError: The getter 'stateWidget' was called on null.
Receiver: null
Tried calling: stateWidget)
(I use a Inhereted widget)
Her is the Widget I am trying to take a Screenshot of
class BlinkSkjerm extends StatelessWidget {
#override
Widget build(BuildContext context) {
final provider = InheritedDataProvider.of(context);
final data = provider.historikken[provider.index];
return SizedBox(
height: 400,
child: Stack(
children: data.inMoveableItemsList,
));
}
}
and her is the onPress funtion:
onPressed: () async {
final controler = ScreenshotController();
final bytes = await controler.captureFromWidget(BlinkSkjerm());
setState(() {
this.bytes = bytes;
});
}
you used InheritedDataProvider in wrong way. you did not provide data that needed in BlinkSkjerm.
you want to take screen shot from widget that not in the tree, but that widget need data that should provide before build it which you did not provide it.
this approach work this way:
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => InheritedDataProvider(
child: BlinkSkjerm(),
data:'some string',
)),
);
this way you can use
final provider = InheritedDataProvider.of(context);
and make sure it is not null.
for your situation I recommended to do something like this:
onPressed: () async {
final controler = ScreenshotController();
final bytes = await controler.captureFromWidget(InheritedDataProvider(
child: BlinkSkjerm(),
data:'some string',
));
setState(() {
this.bytes = bytes;
});
}
for more information see this page

can not retrieve model correctly through ScanStreamTransformer

I'm trying to retrieve an ItemModel class from my repository using streams implementing the BLoC logic in Flutter.
The problem is that the ItemModel is found but not retrieved . Therefore there is another loop triggered and tries to return a different Object, which is not retrieve on the Widgets.
Sample output:
I/flutter ( 4520): trying to get 25314126 from cache
I/flutter ( 4520): 25314126 in transformer
I/flutter ( 4520): 25314126 found !! returning: {id: 25314126, type: story, by: xucheng, time: 1607172267, text: , parent: null, kids: [25314805,25314781,25314684,25314664], dead: 0, deleted: 0, url: https://bitbashing.io/std-visit.html, score: 24, title: std::visit is everything wrong with modern C++ (2017), descendants: 4}
I/flutter ( 4520): ----------item to find: 25314126 and found: Instance of 'ItemModel'
I/flutter ( 4520): returned item Instance of 'ItemModel'
Here the correct Object is found and retrieved but not received on the UI and therefore there is another search right away:
I/flutter ( 4520): trying to get 25314805 from cache
I/flutter ( 4520): 25314805 found !! returning: {id: 25314805, type: comment, by: vasama, time: 1607178963, text: We got here because adding library features is a lot easier and less risky than adding language features. Work on pattern matching [1] is ongoing, but the bar for entry for a language feature is much higher and as such takes a longer time.<p>1. http://wg21.link/p1371, parent: 25314126, kids: [], dead: 0, deleted: 0, url: null, score: null, title: null, descendants: 0}
I/flutter ( 4520): ----------item to find: 25314805 and found: Instance of 'ItemModel'
I/flutter ( 4520): returned item Instance of 'ItemModel'
Which is not the Object I'm trying to retrieve!!!
There is always 'Loading 1' String shown
Here is my main Widget
class NewsDetail extends StatelessWidget{
final int itemId;
NewsDetail({ this.itemId}) ;
#override
Widget build(BuildContext context) {
final bloc = CommentsProvider.of(context);
// TODO: implement build
return Scaffold(
appBar: AppBar(
title: Text('Detail'),
),
body: buildBody(bloc),
);
}
Widget buildBody(CommentsBloc bloc){
return StreamBuilder(
stream: bloc.itemWithComments,
builder:
(context, AsyncSnapshot<Map<int,Future<ItemModel>>> snapshot){
if (!snapshot.hasData){
return Text('Loading 1');
}
final itemFuture = snapshot.data[itemId];
return FutureBuilder(
future: itemFuture,
builder: (context,AsyncSnapshot<ItemModel> itemSnapshot){
if(!itemSnapshot.hasData){
return Text('Loading 2');
}
return buildTitle(itemSnapshot.data);
}
);
},);
}
which indicates that is something wrong with the stream: bloc.itemWithComments,
Here is my BLOC class:
class CommentsBloc{
final _repository = Repository();
final _commentsFetcher = PublishSubject<int>();
final _commentsOutput = BehaviorSubject<Map<int,Future<ItemModel>>>();
//Streams
get itemWithComments => _commentsOutput.stream;
//Sink
Function(int) get fetchItemWithComments => _commentsFetcher.sink.add;
CommentsBloc(){
_commentsFetcher.stream.transform(_commentsTransformer()).pipe(_commentsOutput);
}
_commentsTransformer (){
return ScanStreamTransformer(
(cache,int id,index){
cache[id] = _repository.fetchItem(id);
print('$id in transformer');
cache[id].then((ItemModel item){
item.kids.forEach((kidId)=>fetchItemWithComments(kidId));
});
},
<int,Future<ItemModel>>{},
);
}
dispose(){
_commentsFetcher.close();
_commentsOutput.close();
}
}
And here is how i fetch items in my Repository class
List<Source> sources = <Source>[
newsDbProvider,
NewsApiProvider(),
];
List<Cache> caches = <Cache>[
newsDbProvider,
];
Future<ItemModel> fetchItem(int id) async{
ItemModel item;
var source;
for(source in sources) {
item = await source.fetchItem(id);
print('----------item to find: $id and found: ${item}');
if(item!=null){
break;
}
}
for(var cache in caches) {
if(cache!=source) {
cache.addItem(item);
}
}
print('returned item ${item}');
return item;
}
Even though there is an Instance returned every time why is the snapshot.hasData false?
Also please note that the widget gets invoked just once with the correct id by using onTap method. What have i completely missed?
Even though i used the fetchItemWithComments to sink the items, I still had to add a return statement in the ScanStreamTransformer
_commentsTransformer (){
return ScanStreamTransformer<int,Map<int,Future<ItemModel>>>(
(Map<int,Future<ItemModel>>cache,int id,index){
print(index);
cache[id] = _repository.fetchItem(id);
cache[id].then((ItemModel item){
item.kids.forEach( (kidId) => fetchItemWithComments(kidId) );
});
return cache; //was missing this
},
<int,Future<ItemModel>>{},
);
}
This had been bugging me for days, I went over everything and couldn't find anything so if you are using a ScanStreamTransformer class
Always have a return statement

fllutter I18n is throwing an exception when used in nested widget

I am writing a flutter app, where I am using the flutter I18n package. It works fine on the most placed, but when I try to use it in a method, which creates an other widget, it crashes with the following error.
The following NoSuchMethodError was thrown building LightLocationWidget(dirty, dependencies: [_LocalizationsScope-[GlobalKey#ced6b]], state: _LightLocationWidgetState#3b5b6):
The getter 'decodedMap' was called on null.
Receiver: null
Tried calling: decodedMap
When the exception was thrown, this was the stack:
Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
FlutterI18n._translateWithKeyFallback (package:flutter_i18n/flutter_i18n.dart:162:43)
FlutterI18n.translate (package:flutter_i18n/flutter_i18n.dart:139:26)
In the package its this method:
static String _translateWithKeyFallback(
final BuildContext context, final String key) {
final Map<String, dynamic> decodedStrings =
_retrieveCurrentInstance(context).decodedMap;
String translation = _decodeFromMap(decodedStrings, key);
if (translation == null) {
print("**$key** not found");
translation = key;
}
return translation;}
My code which throws the exception:
#override
Widget build(BuildContext context) {
return Row(
children: [
Padding(
padding: EdgeInsets.all(10),
child: getLightButton(1),
)
...
ButtonTheme getLightButton(int typeNumber) {
return ButtonTheme(
child: FlatButton(
child: Column(children: [Text(FlutterI18n.translate(context, "lightlocation")
...
When I use this key directly on the widget it works without problems.
I found the problem. I was using MaterialApp twice. One Time in my main and also on another screen. Switching to Scaffold on the other screen solved the problem.

Race condition in Stateful widget with parameter

I'm having a race condition of data from a BehaviorSubject's stream not populating/updating the state before the build function returns.
content-detail.dart
import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:domain_flutter/application-bloc.dart';
import 'package:domain_flutter/content.dart';
import 'package:domain_flutter/tag_chips.dart';
import 'package:cached_network_image/cached_network_image.dart';
class ContentDetail extends StatefulWidget {
final String slug;
ContentDetail({Key key, this.slug}) : super(key: key);
#override
State<StatefulWidget> createState() => _ContentDetailState();
}
class _ContentDetailState extends State<ContentDetail> {
Content _content = Content();
_getContent() {
print(widget.slug);
applicationBloc.contentOutput.map( (contents) =>
contents.where((item) => item.slug == widget.slug).toList())
.listen((data) => {
if (this.mounted) {
setState(() => _content = data.first)
}
});
}
#override
void initState() {
super.initState();
_getContent();
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: _content != null ? Text(_content.title) : Text(''),
),
body:
SafeArea(
child: Card(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
mainAxisAlignment: MainAxisAlignment.start,
children: <Widget>[
Container(
child: ListTile(
contentPadding: EdgeInsets.all(0),
title: Text(_content.title,style: TextStyle(fontWeight: FontWeight.bold)),
subtitle: Text(
DateFormat('dd.MM.yyyy').format(_content.changed),
style: TextStyle(fontSize: 12),
),
)),
TagChips(_content.tags),
CachedNetworkImage(
placeholder: (context, url) => CircularProgressIndicator(),
imageUrl: 'https://domain.tld/files/${_content.image}'),
],
),
),
),
);
}
}
The widget renders, but before it's rendered I receive an error.
If content isn't initialized I receive a different error.
What I mean by content initialized is
Content _content = Content();
content initialized:
The following assertion was thrown building ContentDetail(dirty, state: _ContentDetailState#15727):
A non-null String must be provided to a Text widget.
'package:flutter/src/widgets/text.dart':
Failed assertion: line 269 pos 10: 'data != null'
Either the assertion indicates an error in the framework itself, or we should provide substantially more information in this error message to help you determine and fix the underlying cause.
In either case, please report this assertion by filing a bug on GitHub:
https://github.com/flutter/flutter/issues/new?template=BUG.md
User-created ancestor of the error-causing widget was:
MaterialApp file:///home/darko/AndroidStudioProjects/domain_flutter/lib/main.dart:24:12
When the exception was thrown, this was the stack:
#2 new Text (package:flutter/src/widgets/text.dart:269:10)
#3 _ContentDetailState.build (package:domain_flutter/content_detail.dart:41:35)
#4 StatefulElement.build (package:flutter/src/widgets/framework.dart:4047:27)
#5 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3941:15)
#6 Element.rebuild (package:flutter/src/widgets/framework.dart:3738:5)
...
content uninitialized:
The following NoSuchMethodError was thrown building ContentDetail(dirty, state: _ContentDetailState#2be0b):
The getter 'title' was called on null.
Receiver: null
Tried calling: title
User-created ancestor of the error-causing widget was:
MaterialApp file:///home/darko/AndroidStudioProjects/domain_flutter/lib/main.dart:24:12
When the exception was thrown, this was the stack:
#0 Object.noSuchMethod (dart:core-patch/object_patch.dart:51:5)
#1 _ContentDetailState.build (package:domain_flutter/content_detail.dart:53:38)
#2 StatefulElement.build (package:flutter/src/widgets/framework.dart:4047:27)
#3 ComponentElement.performRebuild (package:flutter/src/widgets/framework.dart:3941:15)
#4 Element.rebuild (package:flutter/src/widgets/framework.dart:3738:5)
...
So yeah, there is no data when it's trying to render the component... or Widget/s rather.
I should probably show my applicationBloc
import 'dart:async';
import 'package:domain_flutter/application-entities.dart';
import 'package:domain_flutter/content.dart';
import 'package:domain_flutter/tag.dart';
import 'package:rxdart/rxdart.dart';
class ApplicationBloc {
final _applicationEntities = ApplicationEntities();
Sink<List<Content>> get contentInput => _contentInputController.sink;
Sink<List<Tag>> get tagInput => _tagInputController.sink;
Stream<List<Content>> get contentOutput => _contentOutputSubject.stream;
Stream<List<Tag>> get tagOutput => _tagOutputSubject.stream;
final _contentInputController = StreamController<List<Content>>();
final _tagInputController = StreamController<List<Tag>>();
final _contentOutputSubject = BehaviorSubject<List<Content>>();
final _tagOutputSubject = BehaviorSubject<List<Tag>>();
ApplicationBloc() {
_contentInputController.stream.listen(_handleContentInput);
_tagInputController.stream.listen(_handleTagInput);
}
void dispose() {
_contentInputController.close();
_contentOutputSubject.close();
_tagInputController.close();
_tagOutputSubject.close();
}
void _handleContentInput(List<Content> contentList) {
_applicationEntities.updateContent(contentList);
_contentOutputSubject.add(contentList);
}
void _handleTagInput(List<Tag> tagList) {
_applicationEntities.updateTags(tagList);
_tagOutputSubject.add(tagList);
}
}
final applicationBloc = ApplicationBloc();
You probably guessed, the idea is to load the JSON from a web service then provide it application wide via global variable.
That works without errors for everything but the ContentDetail class.
This ContentDetail class is almost a copy of another component that does almost the same, it filters by a tag slug and renders a list of Content.
This here only wants 1 item from the stream, Content with a specific slug property.
class Content {
// ...
final String slug;
}
As you can see I'm passing the slug in the ContentDetail constructor and my _ContentDetailState is accessing its property via widget.slug.
The _getContent() function of the ContentListByTagSlug class in comparison:
void _getContent() {
applicationBloc.contentOutput.map(
(contents) => contents.where(
(item) => item.tags.any((tag) => tag.slug == widget.tag.slug)
).toList()
)
.listen((data) => {
if (this.mounted) {
setState(() => {content = data})
}
});
}
This works, while only getting 1 item from it doesn't (see 1st code snippet).
This is how I define the FlatButton to open the ContentDetail page:
FlatButton(
child: Text('Read more'),
onPressed: () => Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
ContentDetail(slug: content[index].slug))),
),
It's valid, the slug is passed as the result of the print function indicates.
I'm not sure what to do to ascertain that the _content variable is populated before the build function is executed.
In Angular one creates a resolver, which then populates data before the component is created/initialized.
In Flutter?
Note I'm not using the bloc package, but put the streams in a dedicated class, then use setState to update the state in the listening classes, as the bloc package seems overkill for this scenario.
3 widgets (4 if you count the drawer)
1 displaying an unfiltered list
2 displaying a list filtered by tag slug
3 displaying one item filtered by tag slug
only the latter has errors.
update1: I even removed the if (this.mounted) check in _getContent() and I'm calling _getContent() again in the builder if _content is null.
Then I have changed _content to be a List and am getting _content.first.title which results in
Bad state: No element
But the widget is still rendered correctly.
So it seems that there are 2 invocations of the widget. One that throws errors, which is discarded and one that doesn't which is kept. I'm not familiar with the internals so that's my best guess.
This is answered in this answer.
What I'm taking away from it is
don't initialize variables that are meant to be filled by a stream
provide a check in the builder whether the value to be filled in null
if null render a loading screen else render the desired widget with populated state

Flutter Application showing blank screen when trying to invoke a Future Builder

I am trying to build a futureBuilder with a Future Function that I have which passes through a list of objects which contain the surveyName parameter, I am trying to display that surveyName descriptor into a listView but am noticing that I am getting a blank white screen that isn't showing both the container which is just supposed to show some basic loading functionality and it isn't displaying the information of the getSurveys function either.
I am new to both dart and flutter, so this may just have some basic simple resolution but any information would be helpful. The method getSurveys below in the print displays both names in the print so I know the information is coming in correct for that specific function but I am wondering why it isn't working within the futureBuilder.
The 1 and 2 print statements are running but I am noticing the 3 print statement isn't so that listView Builder is not being invoked for some starnge reason, which may be the cause of this dilemma but I wonder why the container which is just supposed to showcase a loading... is not working correctly either. Output is below this function.
Future<List<Survey_List>> getSurveys() async{
Map map = {
'Type': "getSurveys"
};
var _list = [];
List<Survey_List> surveys = [];
getPost(map).then((Map value){
_list.addAll(value["survey"]);
for (int i = 0; i < _list.length; i++){
Survey_List survey_list = Survey_List(surveyName: _list[i].toString() ,surveyDescription: "", surveyVersion: "");
surveys.add(survey_list);
print(survey_list.surveyName);
}
});
return surveys;
}
Output is as follows:
I/flutter ( 2020): 2
I/flutter ( 2020): 1
I/flutter ( 2020): {"survey":["Survey","Surve3ww"]}
I/flutter ( 2020): Survey
I/flutter ( 2020): Surve3ww
import 'dart:convert';
import 'dart:io';
import 'package:flutter/cupertino.dart';
import 'package:flutter_application/Http.dart';
import 'Config.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
class Survey_List extends StatefulWidget {
String surveyName;
String surveyDescription;
String surveyVersion;
Survey_List({
this.surveyName,
this.surveyDescription,
this.surveyVersion,
Key key,
}) : super (key: key);
#override
_SurveyListState createState() => _SurveyListState();
}
class _SurveyListState extends State<Survey_List> {
#override
Widget build(BuildContext context) {
return new Scaffold(
appBar: new AppBar(
title: new Text("Surveys"),
),
body: new Container(
child: new FutureBuilder <List<Survey_List>>(
future: getSurveys(),
builder: (BuildContext context, AsyncSnapshot snapshot) {
List<Survey_List> surveys = snapshot.data;
if (snapshot.hasData) {
print(1);
return new ListView.builder(
itemCount: snapshot.data.length,
itemBuilder: (BuildContext context, int index) {
print(3);
Survey_List survey_list = surveys[index];
print(survey_list.toString());
return new ListTile(
title: new Text(survey_list.surveyName)
);
},
);
}
else{
print(2);
return new Container(
child: new Center(
child: new Text("Loading...")
)
);
}
},
),
),
);
}
}