I'm watching a provider's state in another provider.
This is my StateProvider.
final counterProvider = StateProvider<int>((ref) => 0);
Now there are two ways to watch this.
final isEvenProvider = Provider<bool>((ref) {
final counter = ref.watch(counterProvider); // First
return (counter.state % 2 == 0);
});
final isEvenProvider = Provider<bool>((ref) {
final counter = ref.watch(counterProvider.state); // Second
return (counter % 2 == 0);
});
What is the difference between the two?
When should we use which?
Related
I'm trying to understand how to use streams to notify listeners when there is a new addition to a list, below I wrote an example program that sums up what I'm trying to accomplish. Everytime there is a NEW string added to the existing 'names' list, I would like the stream to notify its listeners.
import 'dart:async';
import 'dart:io';
import 'dart:math';
List<String> names = ['matt', 'luke', 'sam'];
// pushes random string onto 'names' list every 3 seconds
void addNamesToNameList() async {
Random random = Random();
int len = 4;
while(true) {
String new_name = String.fromCharCodes(List.generate(len, (index) => random.nextInt(33) + 89));
names.add(new_name);
print("Added $new_name to names list");
sleep(Duration(seconds: 3));
}
}
void main() {
addNamesToNameList();
/*
Insert stream that is notified every time there is a NEW addition to the 'names' list
*/
}
You can use Stream.periodic to accomplish this.
late final List<String> names = [];
late final Stream<String> stream = randomStream().asBroadcastStream();
//use [asBroadcastStream] if you have multiple listeners.
String generateNewName(int i) {
Random random = Random();
int len = 4;
return String.fromCharCodes(
List.generate(len, (index) => random.nextInt(33) + 89));
}
Stream<String> randomStream() async* {
yield* Stream.periodic(
const Duration(seconds: 3),
generateNewName,
).asyncMap((event) => event);
}
and then listen to changes:
stream.listen((event) {
setState(() => names.add(event));
});
I am learning stream in dart.
The following code shows a generator method(countStream) and a method that uses the stream(sumStream), they are from sample code from dart.dev. It works, meaning that
I can see the following output at the end.
end of for
total = 15
However, when I try to create a stream using makeCounter where I use StreamController to create a stream instead of generator (async* and yield), I can see the following output.
add
add
add
add
add
I suppose that makeCounter works because I see five "add".
How to fix this problem? Or It may impossible to create a stream with StreamController with await for.
Future<int> sumStream(Stream<int> stream) async {
var sum = 0;
await for (final value in stream) {
sum += value;
}
print("end of for");
return sum;
}
Stream<int> makeCounter(int to) {
var controller = StreamController<int>();
int counter = 0;
void tick(Timer timer) {
counter++;
print("add");
controller.add(counter);
if (counter >= to) {
timer.cancel();
}
}
Timer.periodic(Duration(seconds: 1), tick);
return controller.stream;
}
Stream<int> countStream(int to) async* {
for (int i = 1; i <= to; i++) {
await Future.delayed(Duration(seconds: 1));
yield i;
}
}
void test() async {
var stream = countStream(5);
//var stream = makeCounter(5); // this does not work correctly
var sum = await sumStream(stream);
print("total = $sum");
}
I had this list but since i add lazy loading function,my sorting fuction stoped working.
here is some of the code and sort function is on top:
I had this list but since i add lazy loading function,my sorting fuction stoped working.
here is some of the code and sort function is on top:
I had this list but since i add lazy loading function,my sorting fuction stoped working.
here is some of the code and sort function is on top:
void showEvsePanels() async{
tempEvses.sort((a, b) {
int nameComp = a.sort_availability.compareTo(b.sort_availability);
if (nameComp == stationAvailability.available.index) {
return a.distance.compareTo(b.distance); // '-' for descending
}
return nameComp;
});
setState(() {
if (evseSearchField.isEmpty){
int i = 0;
if (tempEvses.length != 0){
evsePanels.clear();
while (i < tempEvses.length){
evsePanels.add(new EvsePanel(tempEvses[i], widget.appController, false));
i++;
}
}
}
else{
int i = 0;
if (tempEvses.length != 0){
evsePanels.clear();
while (i < tempEvses.length){
if (containsIgnoreCase(tempEvses[i].friendlyName, evseSearchField))
evsePanels.add(new EvsePanel(
tempEvses[i], widget.appController, false));
i++;
}
}
}
});
}
List<Evse> tempEvses = [];
Future fetch() async {
if (isLoading) return;
isLoading = true;
const limit = 10;
final url = Uri.parse('https://everywhere-dev.iccs.gr:18083/evse/getEvsesPaged?page=$page&pageLimit=$limit');
final response = await http.get(url);
if (response.statusCode == 200) {
final List newItems = json.decode(response.body)["results"];
setState(() {
page++;
isLoading = false;
if (newItems.length <limit) {
hasMore = false;
}
tempEvses.addAll(newItems.map<Evse>((items) {
final evseID = items['evseID'];
final friendlyName = items['friendlyName'];
final street = items['street'];
final streetNumber = items['streetNumber'];
final region = items['region'];
final lat = items['lat'] ?? 0.0;
final lng = items['lng'] ?? 0.0;
final connectorList = items['connectorList'];
final cpSerial = items['cpSerial'];
final img = items['img'];
return new Evse(evseID: evseID, friendlyName: friendlyName, street: street, streetNumber: streetNumber, region: region, lat: lat, lng: lng, connectorList: [connectorList], cpSerial: cpSerial, img: img);
}).toList());
for(int i=0 ; i<tempEvses.length; i++ ){
this.tempEvses[i].calculateDistance(widget.appController.currentLocation);
// this.tempEvses[i].calculateAvailability();
this.tempEvses[i].isEvseFavorite(widget.appController.favoritesList);
this.tempEvses[i].storePlugCounters();
}
showEvsePanels();
});
}
}
I have the following class which pulls in data from a remote JSON source, if I hardcode the URL into the class (daUrl) then it works just great.
But I am planning to use a variable URL which I want to feed into this class when I call it. But declaring the variable at the top just doesn't work.
Any ideas?
class ThreadData with ChangeNotifier
{
Map<String,dynamic> _map = {};
bool _error = false;
String _errorMessage = '';
int _isLoggedIn = 0;
int tid = 1836392;
Map<String,dynamic> get map => _map;
bool get error => _error;
String get errorMessage => _errorMessage;
int get isLoggedIn => _isLoggedIn;
//var daUrl = 'https://jsonplaceholder.typicode.com/todos/';
Future<void> get fetchData async {
final response = await post(Uri.parse(daUrl));
if ((response.statusCode == 200) && (response.body.length >0))
{
try
{
debugPrint('\Thread => Make Call => Success\n');
_map = json.decode(response.body);
_error = false;
}
catch(e)
{
_error = true;
_errorMessage = e.toString();
_map = {};
_isLoggedIn = 0;
}
}
else
{
_error = true;
_errorMessage = 'Error: It could be your internet connection';
_map = {};
_isLoggedIn = 0;
}
notifyListeners(); // if good or bad we will notify the listeners either way
}
void initialValues()
{
_map = {};
_error = false;
_errorMessage = '';
_isLoggedIn = 0;
notifyListeners();
}
}
You can pass it to its constructor:
class ThreadData with ChangeNotifier {
final String url;
// Defaults to some URL if not passed as parameter
ThreadData({this.url = 'https://jsonplaceholder.typicode.com/todos/'});
Map<String,dynamic> _map = {};
bool _error = false;
String _errorMessage = '';
int _isLoggedIn = 0;
int tid = 1836392;
Map<String,dynamic> get map => _map;
bool get error => _error;
String get errorMessage => _errorMessage;
int get isLoggedIn => _isLoggedIn;
Future<void> get fetchData async {
// Access the URL field here
final response = await post(Uri.parse(this.url));
if ((response.statusCode == 200) && (response.body.length >0))
{
try
{
debugPrint('\Thread => Make Call => Success\n');
_map = json.decode(response.body);
_error = false;
}
catch(e)
{
_error = true;
_errorMessage = e.toString();
_map = {};
_isLoggedIn = 0;
}
}
else
{
_error = true;
_errorMessage = 'Error: It could be your internet connection';
_map = {};
_isLoggedIn = 0;
}
notifyListeners(); // if good or bad we will notify the listeners either way
}
void initialValues()
{
_map = {};
_error = false;
_errorMessage = '';
_isLoggedIn = 0;
notifyListeners();
}
}
Then you can call it like that:
ThreadData(); // the URL will be https://jsonplaceholder.typicode.com/todos/
ThreadData(url: 'https://example.com'); // the URL will be https://example.com
I try to use compute in Flutter. Here I try to pass multiple parameters inside a Map. But the code in my function myFunction does not work. I get no errors or something else. My code seems to be ignored. Do you find an error here?
Compute function:
Map map = Map();
map['resultList'] = resultList;
map['_getImageFileFromAssets'] = _getImageFileFromAssets;
map["picturesData"] = picturesData;
map["albumID"] = albumID;
await compute(myFunction, map);
Calls the following function:
Future<bool> myFunction(map) async {
var resultList = map["resultList"];
var _getImageFileFromAssets = map["_getImageFileFromAssets"];
var picturesData = map["picturesData"];
var albumID = map["albumID"];
print("Starten");
for (var i = 0; i < resultList.length; i++) {
print(i);
File imageFile = await _getImageFileFromAssets(resultList[i]);
final appDir = await syspath.getApplicationDocumentsDirectory();
final fileName = path.basename(imageFile.path);
final savedImage =
await File(imageFile.path).copy('${appDir.path}/$fileName');
// Creating thumbnails
final thumb = image.decodeImage(await File(savedImage.path).readAsBytes());
final thumbImage = image.copyResize(thumb, width: 500);
new File('${appDir.path}/$fileName-thumb-500.jpg')
.writeAsBytes(image.encodeJpg(thumbImage));
final finalThumbImage = File('${appDir.path}/$fileName-thumb-500.jpg');
picturesData.add(Picture(
album: albumID,
path: savedImage.path,
thumbPath: finalThumbImage.path,
timestamp: Timestamp.now()));
}
return true;
}
Ok, some code - I put this in dartpad.dev:
import 'package:flutter/foundation.dart';
void main() {
Map map = Map();
compute(myFunction, map).then((result) => print(result));
}
Future<bool> myFunction(Map map) async {
print("Starten");
// fake long process
await Future.delayed(Duration(seconds: 5));
return true;
}
and get this as a console result:
Starten
true
Also: is there a reason you need the "map" parameter in your function to be dynamic? If not, I'd declare it as type Map (like I did now).