Riverpod is not updating UI widget on state change - flutter

main.dart
void main() {
runApp(ProviderScope(child: MyApp()));
}
class MyApp extends ConsumerWidget {
MyApp({Key? key}) : super(key: key);
final _appProvider =
ChangeNotifierProvider<AppProvider>((ref) => AppProvider());
final _profileProvider = ChangeNotifierProvider<ProfileProvider>((ref) {
return ProfileProvider();
});
#override
Widget build(BuildContext context, WidgetRef ref) {
AppProvider appProvider = ref.watch(_appProvider);
ProfileProvider profileManager = ref.watch(_profileProvider);
print(appProvider.appLocale);
}
appProvider.dart
class AppProvider extends ChangeNotifier {
Locale? _appLocale = const Locale('en');
Locale get appLocale => _appLocale ?? const Locale("en");
static const supportedLanguage = [Locale('en', 'US'), Locale('km', 'KH')];
void changeLanguage(Locale type) async {
_appLocale = type;
notifyListeners();
}
}
// when i log value of _appLocale here , I can see the update value based on the state change. but it does not re render UI widgeet.

I fixed it by declaring global provider, remove any deplicated provider, same name, in other files.

Related

"'key' is required, but there's no corresponding argument" flutter error

How to solve this error?
The named parameter 'key' is required, but there's no corresponding argument. (Documentation) Try adding the required argument.
error
Future<void> onJoin() async {
// update input validation
setState(() {
_channelController.text.isEmpty
? _validateError = true
: _validateError = false;
});
if (_channelController.text.isNotEmpty) {
await _handleCameraAndMic(Permission.camera);
await _handleCameraAndMic(Permission.microphone);
await Navigator.push(
context,
MaterialPageRoute(
builder: (context) => VideoCall(
channelName: _channelController.text,
role: _role,
),
),
);
}
}
class VideoCall
class VideoCall extends StatefulWidget {
final String channelName;
final ClientRole role;
const VideoCall({Key key, required this.channelName, required this.role})
: super(key: key);
#override
_VideoCallState createState() => _VideoCallState();
}
class _VideoCallState extends State<VideoCall> {
final _users = <int>[];
final _infoStrings = <String>[];
bool muted = false;
late RtcEngine _engine;
#override
void dispose() {
// clear users
_users.clear();
// destroy sdk
_engine.leaveChannel();
_engine.destroy();
super.dispose();
}
#override
void initState() {
super.initState();
// initialize agora sdk
initialize();
}
this is the videoCall class in there no any error shows.
when add "key" show this
When remove required property from key in video call class
show this error
In VideoCall class, key property set as a required, change it to optional:
class VideoCall extends StatefulWidget {
final String? channelName;
final ClientRole? role;
const VideoCall({Key? key, this.channelName, this.role})
: super(key: key);
#override
_VideoCallState createState() => _VideoCallState();
}

Error: The getter 'title' isn't defined for the type 'RSSParser'

I wanted to implements a simple tutorial of how parsing an Rss Feed with Flutter, here is my code:
import 'package:flutter/material.dart';
import 'package:webfeed/webfeed.dart';
import 'package:http/http.dart' as http;
import 'package:url_launcher/url_launcher.dart';
import 'package:cached_network_image/cached_network_image.dart';
class RSSParser extends StatefulWidget {
#override
_RSSParserState createState() => _RSSParserState();
}
class _RSSParserState extends State<RSSParser> {
final String url = "https://www.90min.com/posts.rss";
RssFeed _feed;
String _title;
static const String loadingFeedMsg = 'Loading Feed...';
static const String feedLoadErrorMsg = 'Error Loading Feed.';
static const String feedOpenErrorMsg = 'Error Opening Feed.';
Future<RssFeed> loadFeed() async{
try{
final client = http.Client();
final response = await client.get(url);
return RssFeed.parse(response.body);
}
catch(e){
}
return null;
}
updateTitle(title){
setState(() {
_title = title;
});
}
#override
void initState() {
// TODO: implement initState
super.initState();
updateTitle(widget.title);
}
updateFeed(feed){
setState(() {
_feed = feed;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(_title),
),
);
}
}
The problem is that i got a compilation error in that instruction
updateTitle(widget.title);
with the following error message:
The getter 'title' isn't defined for the type 'RSSParser'
In the tutorial, it works fine!!
Do you have an idea how to solve this?
Thank you
You haven't declared title for you RSS widget. It should look something like ths:
class RSSParser extends StatefulWidget {
final String title;
const RSSParser({required this.title});
This should solve your error.
This is not working because there is not title in RSS class.
I think you are not clear with use of widget.something. It means that in the class which extends StatefulWidget there is a something parameter which i need to get in stateObject.
See the code to understand.
class YellowBird extends StatefulWidget {
const YellowBird({ Key? key }) : super(key: key);
String someData = 'SomeData'; // Some data
#override
_YellowBirdState createState() => _YellowBirdState();
}
//This is the state object
class _YellowBirdState extends State<YellowBird> {
// Now that if you need some data from the above class. You use use this widget.someData to get it here
String getHere = widget.someData ;
#override
Widget build(BuildContext context) {
return Container(color: const Color(0xFFFFE306));
}
}

pass one variables value to another variable in flutter

In my flutter app I created variables var from, to; and pass those with their values to the next page. which I used it with the widget.from & widget.to.
but how can i pass this widget.from & widget.to variables to var newFrom, newTo; these variables?
class FirstPage extends StatelessWidget {
#override
Widget build(BuildContext context) {
var from = "Five", to = "Ten";
return SecondPage(from: from, to: to);
}
}
class SecondPage extends StatefulWidget {
final from, to;
const SecondPage({Key key, this.from, this.to}) : super(key: key);
#override
_SecondPageState createState() => _SecondPageState();
}
class _SecondPageState extends State<SecondPage> {
var newFrom = "", newTo = "";
#override
void initState() {
setState(() {
newFrom = widget.from;
newTo = widget.to;
});
super.initState();
}
#override
Widget build(BuildContext context) {
return Container(
child: Text("$newFrom $newTo"),
);
}
}

The value of local variable isn't used

I am new to flutter and I was following a tutorial when this error popped up. The ancestorRenderObjectOfType has deprecated and been replaced by findAncestorRenderObjectOfType so dart is throwing me errors.
What the tutor did in his video of old dart:
static T of<T extends BlocBase>(BuildContext context) {
final type = _typeOf<BlocProvider<T>>();
BlocProvider<T> provider = context
.context.ancestorRenderObjectOfType(type);
return provider.bloc;
}
static Type _typeOf() => T;
}
What I did in my code
static T of<T extends BlocBase>(BuildContext context) {
final type = _typeOf<BlocProvider<T>>();
BlocProvider<T> provider = context
.findAncestorRenderObjectOfType();
return provider.bloc;
}
static Type _typeOf<T>() => T;
}
If I put
BlocProvider<T> provider = context
.findAncestorRenderObjectOfType(type);
I get an error saying
Too many positional arguements. 0 expected, but 1 found.
The ENTIRE code
abstract class BlocBase {
void dispose();
}
//Genric Bloc provider
class BlocProvider<T extends BlocBase> extends StatefulWidget {
BlocProvider({
Key key,
#required this.child,
#required this.bloc,
}) : super(key: key);
final T bloc;
final Widget child;
#override
_BlocProviderState<T> createState() => _BlocProviderState<T>();
static T of<T extends BlocBase>(BuildContext context) {
final type = _typeOf<BlocProvider<T>>();
BlocProvider<T> provider = context
.findAncestorRenderObjectOfType(); //context.ancestorRenderObjectOfType(type); GOTCHA
return provider.bloc;
}
static Type _typeOf<T>() => T;
}
class _BlocProviderState<T> extends State<BlocProvider<BlocBase>> {
#override
void dispose() {
widget.bloc.dispose();
super.dispose();
}
#override
Widget build(BuildContext context) {
return widget.child;
}
}
Thank you!
findAncestorRenderObjectOfType doesnt take the type as argument instead it is a generic method where you can provide the type while calling the method. So your code will be as below:
static T of<T>(BuildContext context) {
BlocProvider<T> provider = context
.findAncestorRenderObjectOfType<BlocProvider<T>>();
return provider.bloc;
}

Passing data to StatefulWidget and accessing it in it's state in Flutter

I have 2 screens in my Flutter app: a list of records and a screen for creating and editing records.
If I pass an object to the second screen that means I am going to edit this and if I pass null it means that I am creating a new item. The editing screen is a Stateful widget and I am not sure how to use this approach https://flutter.io/cookbook/navigation/passing-data/ for my case.
class RecordPage extends StatefulWidget {
final Record recordObject;
RecordPage({Key key, #required this.recordObject}) : super(key: key);
#override
_RecordPageState createState() => new _RecordPageState();
}
class _RecordPageState extends State<RecordPage> {
#override
Widget build(BuildContext context) {
//.....
}
}
How can I access recordObject inside _RecordPageState?
To use recordObject in _RecordPageState, you have to just write widget.objectname like below
class _RecordPageState extends State<RecordPage> {
#override
Widget build(BuildContext context) {
.....
widget.recordObject
.....
}
}
Full Example
You don't need to pass parameters to State using it's constructor.
You can easily access these using widget.myField.
class MyRecord extends StatefulWidget {
final String recordName;
const MyRecord(this.recordName);
#override
MyRecordState createState() => MyRecordState();
}
class MyRecordState extends State<MyRecord> {
#override
Widget build(BuildContext context) {
return Text(widget.recordName); // Here you direct access using widget
}
}
Pass your data when you Navigate screen :
Navigator.of(context).push(MaterialPageRoute(builder: (context) => MyRecord("WonderWorld")));
class RecordPage extends StatefulWidget {
final Record recordObject;
RecordPage({Key key, #required this.recordObject}) : super(key: key);
#override
_RecordPageState createState() => new _RecordPageState(recordObject);
}
class _RecordPageState extends State<RecordPage> {
Record recordObject
_RecordPageState(this. recordObject); //constructor
#override
Widget build(BuildContext context) {. //closure has access
//.....
}
}
example as below:
class nhaphangle extends StatefulWidget {
final String username;
final List<String> dshangle;// = ["1","2"];
const nhaphangle({ Key key, #required this.username,#required this.dshangle }) : super(key: key);
#override
_nhaphangleState createState() => _nhaphangleState();
}
class _nhaphangleState extends State<nhaphangle> {
TextEditingController mspController = TextEditingController();
TextEditingController soluongController = TextEditingController();
final scrollDirection = Axis.vertical;
DateTime Ngaysx = DateTime.now();
ScrollController _scrollController = new ScrollController();
ApiService _apiService;
List<String> titles = [];
#override
void initState() {
super.initState();
_apiService = ApiService();
titles = widget.dshangle; //here var is call and set to
}
I have to Navigate back to any one of the screens in the list pages but when I did that my onTap function stops working and navigation stops.
class MyBar extends StatefulWidget {
MyBar({this.pageNumber});
final pageNumber;
static const String id = 'mybar_screen';
#override
_MyBarState createState() => _MyBarState();
}
class _MyBarState extends State<MyBar> {
final List pages = [
NotificationScreen(),
AppointmentScreen(),
RequestBloodScreen(),
ProfileScreen(),
];
#override
Widget build(BuildContext context) {
var _selectedItemIndex = widget.pageNumber;
return Scaffold(
bottomNavigationBar: BottomNavigationBar(
elevation: 0,
backgroundColor: Colors.white,
unselectedItemColor: Colors.grey.shade700,
selectedItemColor: Color(kAppColor),
selectedIconTheme: IconThemeData(color: Color(kAppColor)),
currentIndex: _selectedItemIndex,
type: BottomNavigationBarType.fixed,
onTap: (int index) {
setState(() {
_selectedItemIndex = index;
});
},
You should use a Pub/Sub mechanism.
I prefer to use Rx in many situations and languages. For Dart/Flutter this is the package: https://pub.dev/packages/rxdart
For example, you can use a BehaviorSubject to emit data from widget A, pass the stream to widget B which listens for changes and applies them inside the setState.
Widget A:
// initialize subject and put it into the Widget B
BehaviorSubject<LiveOutput> subject = BehaviorSubject();
late WidgetB widgetB = WidgetB(deviceOutput: subject);
// when you have to emit new data
subject.add(deviceOutput);
Widget B:
// add stream at class level
class WidgetB extends StatefulWidget {
final ValueStream<LiveOutput> deviceOutput;
const WidgetB({Key? key, required this.deviceOutput}) : super(key: key);
#override
State<WidgetB> createState() => _WidgetBState();
}
// listen for changes
#override
void initState() {
super.initState();
widget.deviceOutput.listen((event) {
print("new live output");
setState(() {
// do whatever you want
});
});
}
In my app, often instead of using stateful widgets, I use mainly ChangeNotifierProvider<T> in main.dart, some model class
class FooModel extends ChangeNotifier {
var _foo = false;
void changeFooState() {
_foo = true;
notifyListeners();
}
bool getFoo () => _foo;
}
and
var foo = context.read<FooModel>();
# or
var foo = context.watch<FooModel>();
in my stateless widgets. IMO this gives me more precise control over the rebuilding upon runtime state change, compared to stateful widgets.
The recipe can be found in the official docs, the concept is called "lifting state up".