I am building a Flutter app with a ChangeNotifier provider.
When the app is started, I make a call to the Firebase api and save the results in a Provider variable:
Map<DateTime,List> datesMap;
How can I define another variable in the same Provider, based on the first variable?
for example:
List newList = datesMap[DateTime.now()]
If I try to do it I get an error:
The instance member 'params' can't be accessed in an initializer
And if I place the second variable in a Constructor, I will get an error because the first variable datesMap is null until the Firebase api is completed.
Example code:
class ShiftsProvider with ChangeNotifier {
Map<DateTime,List> datesMap;
List newList = datesMap[DateTime.now()];
Future<void> getDatesMapfromFirebase () {
some code...
datesMap = something;
notifyListeners();
return;
}
You can make getter:
List get newList {
return datesMap[DateTime.now()];
}
You can use late like this:
Map<DateTime,List>? datesMap;
late List? newList = datesMap?[DateTime.now()];
since like I see that datesMap variable is related to the specific class, you can mark it with static keyword, this will fix your problem:
class ShiftsProvider with ChangeNotifier {
static Map<DateTime,List> datesMap;
List? newList = datesMap[DateTime.now()];
Future<void> getDatesMapfromFirebase () {
some code...
datesMap = something;
notifyListeners();
return;
}
}
just note that if you want to use that static variable, you can access it like this:
ShiftsProvider.datesMap
Related
I cannot use the ".obs" property variables that I have created as parameters in my api service methods. and it gives the error The prefix 'coinTwo' can't be used here because it is shadowed by a local declaration.
Try renaming either the prefix or the local declaration.
I wrote the problem in getx, but they did not understand the problem.
I would appreciate it if you could take a look at my issue on github.
İssue link: text
I would appreciate it if you could take a look at my issue on github.
İssue link: text
Your problem is in the declaration of getOrderBookData
Instead of
getOrderBookData(coinOne.value, coinTwo.value) async {
...
you should either have
getOrderBookData() async {
...
//Do stuff with coinOne.value, coinTwo.value
...
OR
getOrderBookData(String firstCoin, String secondCoin) async {
coinOne.value = firstCoin;
coinTwo.value = secondCoin;
...
Edit
Seeing your post on GetX's Github, it looks like you're missing some basic understanding on how functions and methods work.
The code you wrote is the equivalent of the following method signature :
getOrderBookData("aValue", "anotherValue") async {
and it doesn't makes any sense.
Your method's signature should only declare the parameters it's expecting and their type.
You can also define a default value for those parameters if needed.
getOrderBookData({String firstCoin = coinOne.value, String secondCoin = coinTwo.value}) async {
in function declarations you just tell what type it is, and not actual values
So either do
getOrderbookData(String one, String two) async {
var res = await api.fetchOrderBookData(one, two);
purchase.value = res.result!.buy!;
sales.value = res.result!.sell!;
}
or hardcode it to always use coinOne and coinTwo and give no parameters
getOrderbookData() async {
var res = await api.fetchOrderBookData(coinOne.value, coinTwo.value);
purchase.value = res.result!.buy!;
sales.value = res.result!.sell!;
}
Make these changes and the error will be gone.
First, make a minor change to your getOrderBookData method:
void getOrderBookData() async {...} // Don't pass any parameter here.
And then make a change to your onInit method too.
#override
void onInit() {
getOrderBookData();
super.onInit();
}
Upon now I always use getx observable declarations like this:
var someString = ''.obs;
var someNumber = 0.obs;
and so on...
But what if some variables don't have an initial value at first, and I actually want them to be null and later change them?
For non null-safe (pre Dart 2.12), you can declare your observable variables like this:
final someVariable = Rx<Type>();
For example:
final someString = Rx<String>();
final someNumber = Rx<int>();
And for null-safety (Dart 2.12 or later), Just use Rxn<Type> instead of Rx<Type>.
For example:
final someString = Rxn<String>();
final someNumber = Rxn<int>();
If you don't have an initial value for your [Rx] value (at the first time), you need to use
final Rx<YourObject?> yourObject = (null as YourObject?).obs;
Or for more organizing your code, you can create a separate class, like this
class RxNullable<T> {
Rx<T> setNull() => (null as T).obs;
}
and use:
final Rx<YourObject?> yourObject = RxNullable<YourObject?>().setNull()
If anyone else does face this problem.
final Rx<YourObject?> yourObject = (null as YourObject?).obs;
will work.
but if there's any message that says "Unnecessary cast. Try removing the cast.", just add this comment
// ignore: unnecessary_cast
above the line, and then save.
You can declare your observable variables like this for (dart 2.18 and above):
Rx varName = (T()).obs;
Getx in flutter,
I search lot of time How class as observable
so fixed,
Like this ,
Rx<HomeModel?> mainModel =HomeModel(content: []).obs;
I am trying to access a variable called _countryfrom another file in dart, but an error occured: The getter '_country' isn't defined for the type 'CurrentCountry'.
Here's the code where the variable I want to access is(in another file):
class CurrentCountry {
static String _country = 'All';
}
And here's the code where I want to access the variable:
Future<Map<String, dynamic>> fetchWorldData() async {
Response activeResponse = await get(Uri.parse(
'https://disease.sh/v3/covid-19/countries/${CurrentCountry._country}'));
return json.decode(activeResponse.body);
}
If you can help me, I will be very grateful.
You should remove the underscore of the variable.
If an identifier starts with an underscore (_), it’s private to its
library
Reference here: Dart language Important concepts
In kotlin we can check if the 'late' type variables are initialized like below
lateinit var file: File
if (this::file.isInitialized) { ... }
Is it possible to do something similar to this in Dart..?
Unfortunately this is not possible.
From the docs:
AVOID late variables if you need to check whether they are initialized.
Dart offers no way to tell if a late variable has been initialized or
assigned to. If you access it, it either immediately runs the
initializer (if it has one) or throws an exception. Sometimes you have
some state that’s lazily initialized where late might be a good fit,
but you also need to be able to tell if the initialization has
happened yet.
Although you could detect initialization by storing the state in a
late variable and having a separate boolean field that tracks whether
the variable has been set, that’s redundant because Dart internally
maintains the initialized status of the late variable. Instead, it’s
usually clearer to make the variable non-late and nullable. Then you
can see if the variable has been initialized by checking for null.
Of course, if null is a valid initialized value for the variable, then
it probably does make sense to have a separate boolean field.
https://dart.dev/guides/language/effective-dart/usage#avoid-late-variables-if-you-need-to-check-whether-they-are-initialized
Some tips I came up with from advice of different dart maintainers, and my self-analysis:
late usage tips:
Do not use late modifier on variables if you are going to check them for initialization later.
Do not use late modifier for public-facing variables, only for private variables (prefixed with _). Responsibility of initialization should not be delegated to API users. EDIT: as Irhn mentioned, this rule makes sense for late final variables only with no initializer expression, they should not be public. Otherwise there are valid use cases for exposing late variables. Please see his descriptive comment!
Do make sure to initialize late variables in all constructors, exiting and emerging ones.
Do be cautious when initializing a late variable inside unreachable code scenarios. Examples:
late variable initialized in if clause but there's no initialization in else, and vice-versa.
Some control-flow short-circuit/early-exit preventing execution to reach the line where late variable is initialized.
Please point out any errors/additions to this.
Enjoy!
Sources:
eernstg's take
Hixie's take
lrhn's take
leafpetersen's final verdict as of 2021 10 22
Effective Dart
Self-analysis on how to approach this with some common-sense.
You can create a Late class and use extensions like below:
import 'dart:async';
import 'package:flutter/foundation.dart';
class Late<T> {
ValueNotifier<bool> _initialization = ValueNotifier(false);
late T _val;
Late([T? value]) {
if (value != null) {
this.val = value;
}
}
get isInitialized {
return _initialization.value;
}
T get val => _val;
set val(T val) => this
.._initialization.value = true
.._val = val;
}
extension LateExtension<T> on T {
Late<T> get late => Late<T>();
}
extension ExtLate on Late {
Future<bool> get wait {
Completer<bool> completer = Completer();
this._initialization.addListener(() async {
completer.complete(this._initialization.value);
});
return completer.future;
}
}
Create late variables with isInitialized property:
var lateString = "".late;
var lateInt = 0.late;
//or
Late<String> typedLateString = Late();
Late<int> typedLateInt = Late();
and use like this:
print(lateString.isInitialized)
print(lateString.val)
lateString.val = "initializing here";
Even you can wait for initialization with this class:
Late<String> lateVariable = Late();
lateTest() async {
if(!lateVariable.isInitialized) {
await lateVariable.wait;
}
//use lateVariable here, after initialization.
}
Someone may kill you if they encounter it down the road, but you can wrap it in a try/catch/finally to do the detection. I like it better than a separate boolean.
We have an instance where a widget is disposed if it fails to load and contains a late controller that populates on load. The dispose fails as the controller is null, but this is the only case where the controller can be null. We wrapped the dispose in a try catch to handle this case.
Use nullable instead of late:
File? file;
File myFile;
if (file == null) {
file = File();
}
myFile = file!;
Note the exclamation mark in myFile = file!; This converts File? to File.
I'm using boolean variable when I initiliaze late varible.
My case is :
I'm using audio player and I need streams in one dart file.
I'm sharing my code block this methodology easily implement with global boolean variables to projects.
My problem was the exception i got from dispose method when user open and close the page quickly
I am trying to convert a Stream<List<String>> to List<String> in flutter
here is my code
Stream<List<String>> _currentEntries;
/// A stream of entries that should be displayed on the home screen.
Stream<List<String>> get categoryEntries => _currentEntries;
_currentEntries is getting populated with data from a database.
I want to convert _currentEntries into List<String>
I tried the following code but doesn't work:
List<List<String>> categoryList () async {
return await _currentEntries.toList();
}
I get the following error:
A value of type List<List<String>> can't be returned from method categoryList because it has a return type of List<List<String>>
Can someone help how to solve this issues and convert a Stream<List<String> to List<String>?
The issue seems to be with your return type for categoryList. You're returning as List of Lists when the Stream only contains a single layer of List. The return type should be Future<List<String>>.
Use .first, .last, or .single in addition to await to get just a single element, and toList() should be removed.
Future<List<String>> categoryList () async {
return await _currentEntries.first;
}
Also a quick tip: Dart automatically generates getters and setters for all fields so the getter method you show isn't necessary.
As title said, question is how to convert stream of some items to item. So what Christopher answered it is ok but only if you want to take the first value from the stream. As streams are asynchronous, they can provide you a value in any point of a time, you should handle all events from the stream (not only the first one).
Let's say you are watching on a stream from database. You will receive new values from database on each database data modification, and by that you can automatically update GUI according to newly received values. But not if you are taking just first value from stream, it will be updated only the first time.
You can take any value and handle it ("convert it") by using listen() method on a stream. Also you can check this nicely written tutorial on Medium. Cheers!
Stream<List<String>> _currentEntries = watchForSomeStream();
_currentEntries.listen((listOfStrings) {
// From this point you can use listOfStrings as List<String> object
// and do all other business logic you want
for (String myString in listOfStrings) {
print(myString);
}
});
I have no idea that Stream can await for the API call from the server, in my case I'm using BLOC pattern and using Future<List<String>> getCategoryList async () {...} and to get the List I going to use like this:
Future<List<String>> getCategory() async {
var result = await http.get();
//Some format and casting code for the String type here
return result;
}
Hope this help