difference between ref.watch(myProvider.state) and ref.watch(myProvider).state - flutter

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

Stream Listening For List Updates

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));
});

Stream created using StreamController and await for

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");
}

List with sorting function stopped working since i add lazy loader. Flutter/Dart

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();
});
}
}

How can I get variable data into a Class with ChangeNotifier in Flutter?

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

compute() in flutter has no effect

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).