Flutter iterate through Stream<List<DocumentSnapshot<Object?>>> - flutter

I have an object of type
Stream<List<DocumentSnapshot<Object?>>>
That is returned from my database. I'm using it in a method that sends data and such so I don't believe I can use a stream builder with it to iterate over it.
I want to be able to loop through each one and use an if statement so I can check data on each document snapshot in the list

I worked it out I sumply just had to do
users.listen((List<DocumentSnapshot> documentList) {
// doSomething()
documentList.forEach((DocumentSnapshot document) {
//do code in here
}
}

Related

flutter list contains check model not working

// ----- a list to store the favourites courses list
List<FavouriteModel> _favCourses = [];
void initAddToFav(FavouriteModel model, BuildContext context) {
if (_favCourses.contains(model)) {
_courseController.removeFromFavourite(model);
AlertHelper.showSanckBar(
context, 'Remove from favourites !', AnimatedSnackBarType.error);
notifyListeners();
} else {
_courseController.addToFavourite(model);
AlertHelper.showSanckBar(
context, 'Added to favourites !', AnimatedSnackBarType.success);
notifyListeners();
}
}
When try check _favCourses.contains favourite model then if condition not working even data exsist else part working
You are using .contains on a list of FavouriteModel objects. Dart doesn't automatically know how to test if one object is equal to another in the same way that it compares numbers or strings. So it will compare the item by memory address. That is unless you tell it how to test if the two objects are equal using a key.
Take a look at this answer here which uses a different way of checking if the list contains the item.
Check whether a list contain an attribute of an object in dart
you are check wrong condition because you applied the condition on _favCourses list and perform the task in _courseController.
Correct your if condition
If(_courseController.contains(model))
{
_courseController.removeFromFavourite(model);
AlertHelper.showSanckBar(context, 'Remove from favourites !', AnimatedSnackBarType.error);
notifyListeners();
}

Is it possible to feed a model name into a Future as a variable or use a callback in a Future in Flutter?

Background
I understand the concept of callbacks from JS. Being on day #5 of flutter I don't really understand the interplay with callbacks at all in dart/flutter.
So please bear with me
What I'm trying to accomplish
I'm trying to build a single set of reusable code that can communicate from my app to a JSON site to make various different JSON requests via the same exact code base
What I have right now
I have a Future call which successfully polls a site for JSON data and sends it off for parsing by using a specific model.
Future<Result> getJSONfromTheSite(String thecall) async {
try {
//2
final response = await client.request(requestType: RequestType.GET,
path: thecall).timeout(const Duration(seconds: 8));
if (response.statusCode == 200) {
//3
return Result<MyModel>.success(MyModel.fromRawJson(response.body));
} else {
return Result.error(title:"Error",msg:"Status code not 200", errorcode:1);
}
} catch (error) {
(...)
}
}
I'm making the request via my UI page like this:
FutureBuilder(
future: _apiResponse.getJSONfromTheSite('latestnews'),
builder: (BuildContext context, AsyncSnapshot<Result> snapshot) {
if (snapshot.data is SuccessState) { ...
Using the variable thecall which I feed in from the FutureBuilder on my various UI pages I can successfully change which http JSON request is being made to poll for different data.
What I'm stuck on
Where I'm stuck is that while I can successfully vary the request to change what data I'm polling for, I can't do anything with the result because my current code always wants to use MyModel to parse the JSON.
return Result<MyModel>.success(MyModel.fromRawJson(response.body));
The question
I essentially need to be able to switch the Model being used against this JSON data depending on what UI page is making the request, rather then hardcoding 10 versions of the same code.
I was thinking of feeding in the name of the model I want to use for that specific call via the FutureBuilder call. For example something like future: _apiResponse.getJSONfromTheSite('latestnews', MyModel2), but that didn't work at all.
Alternatively I was thinking of having the entire return Result<MyModel>.success(MyModel2.fromRawJson(response.body)); sent in as a callback.
The concept of callback makes sense from my JS days, but I'm not sure if I'm correctly applying the concept here. So if I'm going about this the wrong way I'm all ears to a more elegant solution.
Thank you!
You could simply pass as a callback the constructor you want to use and make your method getJSONfromTheSite dynamically typed. The only issue is that you won't be able to define fromRawJson as a factory constructor but instead as a static method returning an instance of your object.
Code Sample
// Your method fromRawJson should be implemented like this
class MyModel {
// ...
static MyModel fromRawJson(Map<String, dynamic> json) =>
MyModel(/* your parameters */);
}
/// T is the dynamic type which you will use to define if it is
/// MyModel or any other class.
Future<Result<T>> getJSONfromTheSite<T>(
String thecall,
T Function(Map<String, dynamic>) jsonFactory,
) async {
try {
// ...
return Result<T>.success(jsonFactory(response));
} catch (error) {
// ...
}
}
// Then you can call your method like this
await getJSONfromTheSite<MyModel>('latestnews', MyModel.fromRawJson);
// For another class such as MyModel2 it would be like this
await getJSONfromTheSite<MyModel2>('', MyModel2.fromRawJson);
Try the full code on DartPad

convert Stream<List<String>> to List<String> in flutter

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

When and where is the best to initialize reliable collection?

Scenario: statefull SF service will store its state in several reliable collections. Statefull SF is available via remoting.
Do I need to "initialize" the collections before the first use (by calling StateManager.GetOrAddAsync)? Will it help lower the first access to reliable collection or it is not necessary to do this step?
If it is advised to do this init, when is right time and place to do it?
The most reasonable place is right before endless loop in RunAsync but what if method called via remoting will be called before the collections are initialized? Is there going to be any deterioration in performance in that first remoting call (when the collection is going to be initialized)?
Last thing -> when working with reliable collections it is OK to hold reference to collection in class (e.g. during some instance initiation I will get the reference by using StateManager.GetOrAddAsync) and working just with this reference or is better to call StateManager.GetOrAddAsync before every call to collection?
Thanks for answers!
Do I need to "initialize" the collections before the first use (by calling StateManager.GetOrAddAsync)?
Yes, but you don't have to do that to “warm up” collection. Call that method if you really need retrieve some data or want to store something.
what if method called via remoting will be called before the collections are initialized?
That's why you need to do StateManager.GetOrAddAsync on every call to the service.
Is there going to be any deterioration in performance in that first remoting call
Yes. But it will be unnoticeable.
when working with reliable collections it is OK to hold reference to collection in class
You can hold a reference to the collection in a variable within a method call. Here is an example:
public async Task AddPost(Guid userId, PostId postId)
{
try
{
var state = await StateManager.GetOrAddAsync<IReliableDictionary<Guid, List<PostId>>>(StateName);
using (var tx = StateManager.CreateTransaction())
{
await state.AddOrUpdateAsync(
tx,
userId,
addValue: new List<PostId> {postId},
updateValueFactory: (usrId, oldPostsList) =>
{
oldPostsList.Insert(0, postId);
return oldPostsList;
}
);
await tx.CommitAsync();
}
}
catch (TimeoutException)
{
PostsLogger.Singleton.LogWarning("Add post timeout");
throw;
}
catch (Exception ex)
{
PostsLogger.Singleton.LogException(sb.ToString(), ex);
throw;
}
}

Spring Batch - Invoke read() method in Reader multiple times

I am trying to implement calling read() method in the itemReader multiple times.
For Eg:
I have a list of POJO in which I will have one string variable with values either A or B or C.
I have to sort this list based on alphabetical order and segment it into three list for each value. i.e., list for value A and list for value B
and list for value C.
I need to send each list to the read() method in the itemReader one by one.
Once List for A is processed and write, then I need to send List for B and so on..
Is this doable? Any help is appreciated.
Although I am not very clear on what you are trying to achieve, I don't see any reason it cannot be done.
I assume you mean either of this:
1. You want the "item" to be process to be a whole list of POJO with same ABC Type, or
2. You want the item to be the POJO itself, and you want them to be processed in order of ABC Type
2 is straight-forward. At the first read, prepare all the POJOs, sort it. I assume they are in some kind of
In psuedo code, it looks like this
class MyReader implements ItemReader<MyPojo> {
private List<MyPojo> values;
MyPojo read() {
if (values == null) {
values = getPojos();
sort values;
}
if (values.isEmpty()){
return null;
} else {
return values.popFront();
}
}
}
1 is nothing more complicated. You will need to group POJOs with same ABC type in same list, and return the lists one by one. It can be easily done by using a TreeMap<String, List<MyPojo>>
In psuedo code, it looks like this
class MyReader implements ItemReader<List<MyPojo>> { // note the item is List<MyPojo>
private NavigableMap<String, List<MyPojo>> values;
List<MyPojo> read() {
if (values == null) {
values = new TreeMap<>();
pojos = getPojos();
for (pojo : pojos) {
if (values do not contain pojo.abcType() ) {
values.put(pojo.abcType(), new ArrayList(pojo));
} else {
values.get(pojo.abcType()).add(pojo);
}
}
}
if (values.isEmpty()){
return null;
} else {
return values.popFirstEntry().value();
}
}
}
If your list of items is fully available (you have a List<Pojo> loaded with all items) you can:
use a ListItemReader and inject into the ordered list
use a custom ItemReader and sort items after first ItemReader.read()
About break the best way is to use a custom CompletionPolicy based on pojo 'string variable'; in this manner your writer will receive a list where POJO's 'string variable' has the same values for all list items (check How to read csv lines chunked by id-column with Spring-Batch? for sample code).