fllutter I18n is throwing an exception when used in nested widget - flutter

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.

Related

Threw an exception when the notifier tried to update its state error in flutter_riverpod

I am developing an app with flutter and I am using flutter_riverpod package for state managment. But I am getting an error.
I have 2 main widget inside my screen. These are "ReadTopBarW" widget and "ReadArticleW" widget.
I am getting datas with http post with futureprovider with riverpod. There is no problem so far.
My purpose is change the icon with a response value.
I am getting the value in "ReadArticleW" and I am writing the value for StateProvider. And I will watch the value in "ReadTopBarW".
This is my "ReadArticleW"
import 'dart:convert';
import 'package:eem_flutter_app/services/get_one_article.dart';
import 'package:eem_flutter_app/widgets/read/shimmer_read_w.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
final isSavedVider = StateProvider((_) => '');
class ReadArticleW extends ConsumerWidget {
const ReadArticleW({Key? key}) : super(key: key);
#override
Widget build(BuildContext context, WidgetRef ref) {
final futureCatFacts = ref.watch(singleArticleFProvider);
return SingleChildScrollView(
child: futureCatFacts.when(
data: (datax) {
final decodedData = json.decode(datax.body);
final isSaved = decodedData[1].toString();
ref.read(isSavedVider.notifier).state = isSaved;
return Column(
children: [
Text(
decodedData[0]['articleTitle'].toString(),
),
Image.network(
decodedData[0]['articleLImage'].toString()),
],
);
},
error: (err, stack) => Text('Error: $err'),
loading: () => const ShimmerReadW(),
),
);
}
}
This my "ReadTopBarW"
import 'package:eem_flutter_app/widgets/read/read_article_w.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
class ReadTopBarW extends ConsumerWidget {
const ReadTopBarW({Key? key}) : super(key: key);
#override
Widget build(BuildContext context, WidgetRef ref) {
final x = ref.watch(isSavedVider);
print(x);
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
InkWell(
onTap: () {
Navigator.pop(context);
},
child: const Icon(Icons.arrow_back_ios)),
Row(
children: const [
"0" == "1"
? Icon(Icons.bookmark_border)
: Icon(Icons.bookmark_outlined),
SizedBox(
width: 10,
),
Icon(Icons.ios_share),
],
),
],
);
}
}
This is error text. The error is vscode red error that you know
Exception has occurred.
StateNotifierListenerError (At least listener of the StateNotifier Instance of 'StateController<String>' threw an exception
when the notifier tried to update its state.
The exceptions thrown are:
setState() or markNeedsBuild() called during build.
This UncontrolledProviderScope widget cannot be marked as needing to build because the framework is already in the process of building widgets. A widget can be marked as needing to be built during the build phase only if one of its ancestors is currently building. This exception is allowed because the framework builds parent widgets before children, which means a dirty descendant will always be built. Otherwise, the framework might not visit this widget during this build phase.
The widget on which setState() or markNeedsBuild() was called was:
UncontrolledProviderScope
The widget which was currently being built when the offending call was made was:
ReadArticleW
Please focus on th isSavedVider because the problem is here. There is no problem in singleArticleProvider.
note:
I simplified the code to publish here.
You shouldn't update a StateProvider in the build method, the error is coming from here:
child: futureCatFacts.when(
data: (datax) {
final decodedData = json.decode(datax.body);
final isSaved = decodedData[1].toString();
ref.read(isSavedVider.notifier).state = isSaved;
What you can you is watch the singleArticleFProvider in isSavedVider and set the value from the extracted response, this way, when there is an update to the response, it isSavedVider gets the update value like so:
final isSavedVider = StateProvider((ref){
final futureCatFacts = ref.watch(singleArticleFProvider);
if(futureCatFacts is AsyncData){
final decodedData = json.decode(futureCatFacts.value.body);
final isSaved = decodedData[1].toString();
return isSaved;
}
return "";
});

BannerAd variable has not initialized error

i get an error that my BannerAd variable is not initialized and my app crash, so i move my _banner in top of code and still not work, i move it inside the state class and still not initialized what should need to do to be initialized ?
class _MyHomePageState extends State<MyHomePage> {
late BannerAd _banner;
#override
void didChangeDependencies(){
super.didChangeDependencies();
final adState = context.read(adStateProvider);
adState.initialization.then((value)
{
setState(() {
_banner = BannerAd(size: AdSize.banner, adUnitId: adState.bannerAdUniteId, listener: adState.adListener, request: AdRequest())..load();
});
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
new Text('pub'),
if(_banner == null)Text('null hhhhhhhhhhhhhhhhhhhhhhhhhhhhh')
else Expanded(child: AdWidget(ad: _banner),),
That's because your widget builds before _banner is initialized, even if you initialized it in initState, will still not work, because you initialize it after a future completes, and that future completes after the build method got executed. so the solution here is to remove the late keyword before BannerAd and also make it nullable. like this:
// this doesn't give you any initialization errors
// because _banner will have a default value of null
BannerAd? _banner;
now you will have a different problem, because AdWidget takes a non-null object, you need to assert that _banner is not null with null assertion operator !, like this:
AdWidget(ad: _banner!)
this way it's like you're telling the compiler that "I'm sure that _banner is not null", because you only build this widget if _banner is not null because of the if else clause
Note that when using !, you have to be completely sure that the object will actually be not null then, if it's null, it will throw a null assertion exception.
you can read and practice on null safety with this dart codelab

Bad state: Tried to read a provider that threw during the creation of its value. The exception occurred during the creation of type SomeBloc

I get this error while using bloc not provider.
while trying to add event to SomeBloc that is created before It gives this error :
======== Exception caught by gesture ===============================================================
The following StateError was thrown while handling a gesture:
Bad state: Tried to read a provider that threw during the creation of its value.
The exception occurred during the creation of type EditFooterCubit.
When the exception was thrown, this was the stack:
#0 _CreateInheritedProviderState.value (package:provider/src/inherited_provider.dart:661:7)
#1 _CreateInheritedProviderState.debugFillProperties (package:provider/src/inherited_provider.dart:750:44)
#2 _InheritedProviderScopeElement.debugFillProperties (package:provider/src/inherited_provider.dart:585:20)
#3 DiagnosticableNode.builder.<anonymous closure> (package:flutter/src/foundation/diagnostics.dart:2945:17)
#4 DiagnosticableNode.builder (package:flutter/src/foundation/diagnostics.dart:2948:8)
...
Handler: "onTap"
Recognizer: TapGestureRecognizer#445b5
debugOwner: GestureDetector
state: ready
won arena
finalPosition: Offset(188.8, 422.3)
finalLocalPosition: Offset(36.1, 20.3)
button: 1
sent tap down
====================================================================================================
This is where I create the bloc :
class EditFooterPage extends StatelessWidget {
static int pageNumber() => 5;
#override
Widget build(BuildContext context) {
return BlocProvider<EditFooterCubit>(
create: (context) => EditFooterCubit(
footerRepo: RepositoryProvider.of<FooterRepository>(context),
footerBloc: BlocProvider.of<FooterBloc>(context),
),
child: EditFooterForm(),
);
}
}
And here bloc is used to add event :
class EditFooterForm extends StatelessWidget {
#override
Widget build(BuildContext context) {
return Scaffold(
body: SingleChildScrollView(
child: Column(
children: [
ElevatedButton(
onPressed: () {
//here on button press error happens.
context.read<EditFooterCubit>().footerPreviewRequestedToState();
},
child: Text('UpdateFooterPart')),
SizedBox(height: 10),
FooterPart(),
],
),
),
);
}
}
I can't find why It gives error since I created this page like LoginPage and Login Form Example in https://bloclibrary.dev/
As the error indicates, error occurred during creation of SomeBloc .
So input parameters of SomeBloc are not passed correctly.
For example
SomeBloc({
#required this.blocA,
})
SomeBloc needs BLocA and when you want to create SomeBloc you have passed BlocA like this :
BlocProvider<SomeBloc >(
create: (context) => SomeBloc (//here SomeBloc is the error causing bloc because
blocA: BlocProvider.of<BlocA>(context),//here BlocA is not accessible in this page or subtree so will give error
),
child: _View(),
);
But BLocA is not accessible in this subTree.
So you should Check the input parameters of the bloc that causes error
and see whether you have passed the parameters correctly or not because the reason of error is that the passed parameters are not accessible in this subtree.

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

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.

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