flutter/dart static list or list of singleton object always return it's default values when calling it from another class - flutter

i am trying to use static list as global variable that can be accessible through all the dart classes , so i have done like that:
class MyData {
// initialize it to an empty list
static var List<MyObject> myObjectList = new List<MyObject>();
}
then in another class I load that empty list with list of MyObject (no doubt that it loaded with success)
I do add objects to that list , the list will not remain empty !!
when it comes the time to use the myObjectList in another class it returns an empty list with 0 length
class SomeClass {
.....
void getMyObjectsList(){
.....
// this display 0 length and has no data
print("my static object list length == ${MyData.myObjectList.length}");
}
}
i have also tried using a singleton instance and it return the same result :
class MyData {
static final MyData _singleton = MyData._internal();
factory MyData() {
return _singleton;
}
MyData._internal();
// object property
var List<MyObject> myObjectList = new List<MyObject>();
}
well this also return the default value which is an empty list:
class SomeClass {
.....
void getMyObjectsList(){
....
// this display 0 length and has no data
print("my singleton object list length == ${MyData().myObjectList.length}");
}
}

I think you missed to Store/Copy/Add objects in the List
class MyData {
// initialize it to an empty list
static List<MyObject> myObjectList = [];
}
Add some Objects to List before accessing the List
class SomeClass {
.....
/// Add Object to List using this Method
void addDataToList(MyObject data){
myObjectList.add(data);
}
void getMyObjectsList(){
.....
// this display 0 length and has no data
print("my static object list length == ${MyData.myObjectList.length}");
}
}
Note : if there is no Data list will return 0
so please add some data before using the .length() on List.
Hope this Solve your Issue

the problem was not in the static list , it was inside the TextField onTap event ,
i was using the static list inside it so i tried to use a local variable and i faced the same problem , the variable return the default value always.

Related

Duplicate Array list value automatically changed in Flutter

I'm very surprised after this issue. First, inform all things I have used in my project.
I have used Getx in my project. I have called the API using the Getx controller file.
Below code used in getx controller file. "PLTimeSlotModel" is model and. it has two params (name, isselect).
var futureTimeSlot_PL_C_D = Future.value(<PLTimeSlotModel>[]).obs;
callTimeSlotAPI() async {
futureTimeSlot_PL_C_D.value = FetchTimeSlotList();
}
Future<List<PLTimeSlotModel>> FetchTimeSlotList() async {
// Fetching data with API calling
}
Screen A:
List<PLTimeSlotModel> listA = [];
List<PLTimeSlotModel> listB = [];
#override
void initState() {
super.initState();
_plController.callTimeSlotAPI();
}
Another method is to create two lists using the future list:
List<PLTimeSlotModel> temp1 = await _plController.futureTimeSlot_PL_C_D.value;
temp1.forEach((element) {
listA.add(element);
listB.add(element);
});
onclick:
for(int i =0;i<listA.length;i++){
listA[i].isselect = false;
print(listA[i].isselect);
print(listB[i].isselect);
}
Now the issue is I have changed/updated the only "listA" value, So why automatically set the same value to "listB"? The two list is based on the one list.
A List in Dart contains references objects, not the objects themselves. So what you are doing is copying references to objects into two lists. But since they are pointing at the same objects, you will see any modification in one list also happen in the other list. You need to copy each PLTimeSlotModel object and put the copy into your new list.
One way to copy objects is to create an constructor which takes an object of the same type and creates a new object based on this first object. So something like this:
class Person {
String name;
Person(this.name);
Person.fromPerson(Person other) : this(other.name);
#override
String toString() => 'Person($name)';
}
void main() {
final persons = [
Person('Adam'),
Person('Bob'),
];
// Make new list based on persons
final otherPersonList = [
...persons.map((person) => Person.fromPerson(person))
];
otherPersonList[0].name = 'Carl';
print(persons); // [Person(Adam), Person(Bob)]
print(otherPersonList); // [Person(Carl), Person(Bob)]
}

Flutter : create new instance of a class which no have default constructor and change some properties

I have a class with name "RecognisedText" in one of my packages which is required in my Flutter application. This class is:
class RecognisedText {
RecognisedText._(this.text, this.blocks);
factory RecognisedText.fromMap(Map<dynamic, dynamic> map) {
var resText = map["text"];
var textBlocks = <TextBlock>[];
for (var block in map["blocks"]) {
var textBlock = TextBlock.fromMap(block);
textBlocks.add(textBlock);
}
return RecognisedText._(resText, textBlocks);
}
///String containing all the text identified in a image.
final String text;
///All the blocks of text present in image.
final List<TextBlock> blocks;
}
I want to define a variable from this class:
RecognisedText myobject = RecognisedText(mytext,myblocks);
but it raise this error:
The class 'RecognisedText' doesn't have a default constructor
I tried to define myobject in different way:
RecognisedText myobject;
myobject.text = mytext;
myobject.blocks = myblocks;
but it raise this error:
'text' can't be used as a setter because it's final.
How i can define my new variable from RecognisedText class and set properties? I can't change any part of class RecognisedText because it is a remote class (added from pubspec.yaml)
Edit:
I finally solved my problem with this code:
RecognisedText myobject = RecognisedText.fromMap({"text": mytext, "blocks": myblocks});
Your Class can't create its instance so try using YourClassName.fromMap constructor.
Class RecognisedText is designed in the way that you can not create its instance other than using its fromMap constructor, which accepts map.
So the only way to create it is to create map with values you need and pass it to RecognisedText.fromMap constructor.
If you already have your block and your text as variables, you can modify you class like this to accept a default constructor :
class RecognisedText {
//----Replace this line ----
//RecognisedText._(this.text, this.blocks);
//----By this line ----
RecognisedText.(this.text, this.blocks);
factory RecognisedText.fromMap(Map<dynamic, dynamic> map) {
var resText = map["text"];
var textBlocks = <TextBlock>[];
for (var block in map["blocks"]) {
var textBlock = TextBlock.fromMap(block);
textBlocks.add(textBlock);
}
return RecognisedText._(resText, textBlocks);
}
///String containing all the text identified in a image.
final String text;
///All the blocks of text present in image.
final List<TextBlock> blocks;
}
To complete Alex's answer, the constructor fromMap takes a map as a parameter. It should look like :
RecogniserdText.fromMap({'text': myText, 'blocks': myblock1, 'blocks': myblock2, 'blocks': myblock3});

flutter add method was called on null using provider

Hello I want to add some value to my list. I have already googled for solutions but I can't see any other solutions besides initializing the list which I did.
When I try to add an item to my AutomaticDateList class I get the error:
The method 'add' was called on null.
Receiver: null
Tried calling: add(Instance of 'AutomaticDate')
Here is the class with the list in it.
class AutomaticDateList with ChangeNotifier {
List<AutomaticDate> items = []; // here I inialize
AutomaticDateList({this.items});
void addToList(AutomaticDate automaticDate) {
items.add(automaticDate);
notifyListeners();
}
List<AutomaticDate> get getItems => items;
}
This is the item I want to add to the list.
class AutomaticDate with ChangeNotifier {
String date;
String enterDate;
String leaveDate;
String place;
AutomaticDate({this.date, this.enterDate, this.leaveDate, this.place});
Here I call the method using the provider inside a page widget
void onGeofenceStatusChanged(Geofence geofence, GeofenceRadius geofenceRadius,
GeofenceStatus geofenceStatus) {
geofenceController.sink.add(geofence);
AutomaticDate automaticDateData = AutomaticDate();
automaticDateData.place = geofence.id;
automaticDateData.date = DateFormat("dd-mm-yyyy").format(DateTime.now());
if (geofenceStatus == GeofenceStatus.ENTER) {
widget.enterDate = DateFormat("HH:mm:ss").format(DateTime.now());
} else {
automaticDateData.leaveDate =
DateFormat("HH:mm:ss").format(DateTime.now());
automaticDateData.enterDate = widget.enterDate;
widget.list.add(automaticDateData);
WidgetsBinding.instance.addPostFrameCallback((timeStamp) {
AutomaticDateList automaticDateList =
Provider.of<AutomaticDateList>(context, listen: false);
automaticDateList.items.add(automaticDateData); // Here I add the data and get error "add was called on null"
print(automaticDateList.getItems);
});
}
}
The problem is in the initialization:
List<AutomaticDate> items = []; // here I inialize
AutomaticDateList({this.items});
You set a default value, but you are using the "auto-assign" sintax in the constructor, saying that items passing in the parameters are going to be assigned in the items property of the class.
You are instantiating the class using this code:
AutomaticDate automaticDateData = AutomaticDate();
So, you are passing "null" implicitly as parameter, then items [] got replaced with null value.
Just change the code to:
List<AutomaticDate> item;
AutomaticDateList({this.items = []}); // Default value

How to concatenate a class with a variable to get a static variable from this class?

I am making a pokemon app and I have a question that I already had in other projects and I would like to know if anyone can help me with a solution.
I receive a variable called pokemonName from other screen, I want to pass the variable and concatenate with the class "Strings", it will be like Strings.+pokemonName.toLowerCase(), converting to lowercase to get the map from the class Strings, but I don't know how to achieve this to remove the switch and don't need to use a lot of cases for each pokemon.
class PokemonDetailScreen extends StatelessWidget {
final String pokemonName;
final String image;
Map<String, dynamic> pokemonMap = {};
PokemonDetailScreen(this.pokemonName, this.image, this.index){
getPokemonMap();
}
#override
Widget build(BuildContext context) {
return Container();
}
void getPokemonMap(){
switch(pokemonName){
case "Bulbasaur":
pokemonMap = Strings.bulbasaur;
break;
case "Charmander":
pokemonMap = Strings.charmander;
break;
}
}
}
**Class in another dart file:**
class Strings {
static Map bulbasaur = {};
}
What I needed is something like this:
void getPokemonMap(){
pokemonMap = Strings.$pokemonMap.toLowerCase();
}
What you could do is have a static map indexed by the name of your Pokemons and whose values are maps.
class Strings {
static Map<String, dynamic> map = {
'Bulbasor': {},
'Charmander': {},
// ...
};
}
And you’ll use it like this: pokemonMap = Strings.map[pokemonName].
~You can use JSON file to do all this things instead use a class.~
I recommend not use a static class to do that thing, instead you can just make a normal class and instantiate on another file, so when the class that you call your another class will be dispose when the parent was.
class PokemonStrings {
Map bulbasaur = {your map here};
}
To call that in another file you need just do
PokemonString _pokemonString = PokemonString();
And call whatever you need in the class that you instantiate
var bulbasaurMap = _pokemonString.bulbasaur;
But even so you need walk with static class. Just call the name of class followed by dot to access all the static attributes
var bulbasaurMap = PokemonString.bulbasaur;

AS3 - How do you Ignore a class (Error #1009)?

I have created a class for a MovieClip creating coins for the player (char) to pick up. All the class is suppose to do is add to the score and coinscollected variables, and then remove the one coin from the stage. But when I change the frame using gotoAndStop(#);, the console spams
ErrorType: Error #1009: Cannot access a property or method of a null object reference."
Coin class:
public class coin extends MovieClip{
var char:MovieClip;
var MainTimeLine = MovieClip(root);
public function coin() {
// constructor code
this.addEventListener(Event.ENTER_FRAME,update);
}
function update(event:Event):void{
if(MainTimeLine.currentFrame!=5){
char=MovieClip(root).char;
if(this.hitTestObject(char)){
this.removeEventListener(Event.ENTER_FRAME,update);
parent.removeChild(this);
MainTimeLine.score++;
MainTimeLine.coinscollected++;
}
}
}
}
Root isn't populated until your display object has been added to the display list. You need to listen for that event before setting the variable.
var char:MovieClip;
var MainTimeLine; //do not initialize here, root is null at this point
public function coin() {
// constructor code
//root is still null here sometimes too, so see if it's populated yet
if(root){
init(); //root is populated, skip to initialization
}else{
this.addEventListener(Event.ADDED_TO_STAGE,addedToStage); //root isn't populated yet, listen for added to stage and then initialize
}
}
private function addedToStage(e:Event = null):void {
this.removeEventListener(Event.ADDED_TO_STAGE,addedToStage);
init();
}
private function init():void {
MainTimeLine = MovieClip(root)
this.addEventListener(Event.ENTER_FRAME,update);
}