I have a Map<String, Stream<dynamic>> and I want to convert it into a Stream<Map<String, dynamic>> which should yield the latest snapshot of values from the former. I need something like Rx.combineLatest( mapOfStreams.values, (list) => list ) but somehow keeping map keys.
I've found this solution, which seems to work (supposing keys and values of Map are always aligned), but I feel there must be something better:
final keys = mapOfStreams.keys.toList();
Rx.combineLatest( mapOfStreams.values, (list) => list.asMap().map( (i, value) => MapEntry(keys[i], value) ) );
This is my way
void main() async {
final streams = <String, Stream<dynamic>>{
'a': Stream<int>.periodic(const Duration(milliseconds: 200), (i) => i),
'b': Stream<int>.periodic(const Duration(milliseconds: 500), (i) => i),
'c': Stream<String>.value('Hello'),
};
final final$ = Rx.combineLatest(
streams.entries
.map((entry) => entry.value.map((v) => MapEntry(entry.key, v))),
(List<MapEntry<String, dynamic>> values) => Map.fromEntries(values),
);
final$.listen(print);
await Future.delayed(const Duration(seconds: 10));
}
Related
We are able to define an async inline method in different ways, Is there any difference in the result or under the hood?
1.
Future<void> counter() async => await Future<void>.delayed(
const Duration(seconds: 5),
() => print('Result'),
);
2.
Future<void> counter() async => Future<void>.delayed(
const Duration(seconds: 5),
() => print('Result'),
);
3.
Future<void> counter() => Future<void>.delayed(
const Duration(seconds: 5),
() => print('Result'),
);
Timing, if anything.
The async => await version waits for the delayed future created by Future.delayed to complete before returning, then it completes the returned future.
The async => version should do precisely the same, since the await is implicit in the return.
The => version returns the future created by Future.delayed directly.
In either case, the returned future will be completed after the 5 second duration has passed. It may or may not go through an extra intermediate microtask.
I'm trying to get my state to persist using hydrated bloc but it is not working. When i restart the app the state is not persisting
This is the code i have to start the app:
void bootstrap() async {
WidgetsFlutterBinding.ensureInitialized();
final storage = await HydratedStorage.build(
storageDirectory: await getApplicationDocumentsDirectory(),
);
HydratedBlocOverrides.runZoned(
() => runApp(
RepositoryProvider<void>(
create: (context) => DatabaseCubit(),
child: const RunApp(),
),
),
storage: storage,
);
}
this is the relevent code in the cubit:
class DatabaseCubit extends HydratedCubit<DatabaseState>{
DatabaseCubit() : super(databaseInitial);
#override
DatabaseState? fromJson(Map<String, dynamic> json) {
return DatabaseState.fromMap(json);
}
#override
Map<String, dynamic> toJson(DatabaseState state) {
return state.toMap();
}
I have set up unit tests that make sure my toMap and fromMap functions are working. The tests are passing, here is the code for them:
test('Database state should be converted to and from json', () {
final databaseStateAsJson = databaseState.toMap();
final databaseStateBackToNormal =
DatabaseState.fromMap(databaseStateAsJson);
expect(databaseStateBackToNormal, databaseState);
});
Please tell me what i am doing wrong
I've just solved a similar problem.
Try digging a little into hydrated_bloc.dart hydrate() method and you might find out why it refuses to load your state :).
Could be type conversion problem between collections - as it was in my case.
In Flutter/Dart the examples sometimes show fat arrow and sometimes dont. Here are examples:
RaisedButton(
onPressed: () {
setState(() {
_myTxt = "Text Changed";
});
},
Elsewhere you see:
void main() => runApp(MyApp());
The fat arrow syntax is simply a short hand for returning an expression and is similar to (){ return expression; }.
According to the docs.
Note: Only an expression—not a statement—can appear between the arrow (=>) and the semicolon (;). For example, you can’t put an if statement there, but you can use a conditional expression
void main(){
final cls = TestClass();
cls.displayAnInt((){
//you can create statements here and then return a value
int num1 = 55;
int num2 = 1;
int sum = num1 + num2;
return sum;
});
cls.displayAnInt(() => 55 + 1); // simply return an int expression
}
class TestClass{
displayAnInt(makeIntFunc){
int intValue = makeIntFunc();
print('The int value is $intValue');
}
}
From the code above, You can see that multiline statement can be made when the callback function is used and then a value is returned, while the fat arrow simply has an expression with no return keyword.
Considering your answer about fat arrows not supporting multiline statements in dart. This is quite understandable since doing () => {somtheing} would imply you are returning a map and it would expect to see something like () => {'name':'John', 'age':25} and not () => { _myTxt = "Text Changed";_myTxt = "Never Mind"; } .
=> is used to return a value of an anonymous function.
() {} lets you execute multiple statements.
while
() => {myVar} or () => myVar; allows one single statement.
() => myVar; is short and simple when returning one statement.
The same logic goes for creating non anonymous functions too.
Single statement func
func() => y = x + x;
Multiple statement func
func () {
x = x + x;
print(x + ' value of x');
};
I found that the mean the exact same thing. The only difference is that you can use (you don't have to) the fat arrow if there is only one statement. Following is the above RaisedButton declaration with the fat arrow. Notice I had to remove two curly braces and one semi-colon:
RaisedButton(
onPressed: () {
setState(() =>
_myTxt = "Text Changed"
);
},
If you are used to other languages that allow you to put multiple statements after a fat arrow you'll you'll find that you can't in dart and if you try you'll get an error as in the following:
this wont work
RaisedButton(
onPressed: () {
setState(() => {
_myTxt = "Text Changed";
_myTxt = "Never Mind";
});
},
They are both for expressing anonymous functions. The fat arrow is for returning a single line, braces are for returning a code block.
A fat arrow trying to return a code block will not compile.
There seems to be one difference at least in case of Dart version 2.10:
If the expression to be executed is a Future, then the execution order is not the same.
=>
new Future(() => print('future #1 of 2'))
.then((_) => new Future(() => print('future #1a (a new future)')))
.then((_) => print('future #1b'));
new Future(() => print('future #2 of 2'))
.then((_) => new Future(() => print('future #2a (aa new futue)' )))
.then((_) => print('future #2b'));
The result is:
future #1 of 2
future #2 of 2
future #1a (a new future)
future #1b
future #2a (aa new futue)
future #2b`
{} :
new Future(() => print('future #1 of 2'))
.then((_) => new Future(() => print('future #1a (a new future)')))
.then((_) => print('future #1b'));
new Future(() => print('future #2 of 2'))
.then((_) { new Future(() => print('future #2a (aa new futue)' )); })
.then((_) => print('future #2b'));
The result is
future #1 of 2
future #2 of 2
future #2b
future #1a (a new future)
future #1b
future #2a (a new futue)
Fat Aarrow => Single line of code => Expression form, does not use return statement, the expression is automatically returned
void main() => runApp(MyApp()); // you cannot specify return here. This
is the turned value from the function. This is shorthand form
No fat arrow, uses {}, can have multiple statements, have to use return statement if we want to return a value, if not return can be skipped
setState(() {
_myTxt = "Text Changed";
});
I've seen this already: https://stackoverflow.com/a/49146503/1757321
Followed the solution, but it is not working in my case.
Some enlightenment would do for me this afternoon
Future<String> loadInterest() async {
print('Going to load interests');
final whenDone = new Completer();
SharedPreferences prefs = await SharedPreferences.getInstance();
final token = await prefs.getString('token');
print('The token ${token}');
await this.api.interests(token).then((res) {
// print('The response: ${res['interests']}'); <-- this prints response alright. Data is coming.
whenDone.complete(res['interests']);
});
return whenDone.future;
}
Then I'm trying to use the above Future in a future builder like so:
new FutureBuilder(
future: loadInterest(),
builder: (BuildContext context, snapshot) {
return snapshot.connectionState == ConnectionState.done
? new Wrap(
children: InterestChips(snapshot.data),
)
: Center(child: CircularProgressIndicator());
},
),
Where InterestChips(...) is this:
InterestChips(items) {
print('Interest Chips ${items}');
List chipList;
for (Object item in items) {
chipList.add(Text('${item}'));
}
return chipList;
}
But, I always get null as the snapshot, which means the loadInterest() for the Future is not returning anything.
If I understand this answer correctly, then I'm doing mine along the lines of that: https://stackoverflow.com/a/49146503/1757321
You don't need to use a Completer for this. Since your method is already async, you should just do this for your first code block:
Future<String> loadInterest() async {
print('Going to load interests');
final whenDone = new Completer();
SharedPreferences prefs = await SharedPreferences.getInstance();
final token = await prefs.getString('token');
print('The token ${token}');
final res = await this.api.interests(token).then((res) {
// print('The response: ${res['interests']}'); <-- this prints response alright. Data is coming.
return res['interests']);
}
You might also want to check for snapshot.hasError to make sure you're not getting any exceptions in there.
I want to do something after a lot of future functions are done, but I do not know how to write the code in dart?
the code is like this:
for (var d in data) {
d.loadData().then()
}
// when all loaded
// do something here
but I don't want to wait for them one by one:
for (var d in data) {
await d.loadData(); // NOT NEED THIS
}
how to write those code in dart?
You can use Future.wait to wait for a list of futures:
import 'dart:async';
Future main() async {
var data = [];
var futures = <Future>[];
for (var d in data) {
futures.add(d.loadData());
}
await Future.wait(futures);
}
DartPad example
Existing answer gives enough information, but I want to add a note/warning.
As stated in the docs:
The value of the returned future will be a list of all the values that were produced in the order that the futures are provided by iterating futures.
So, that means that the example below will return 4 as the first element (index 0), and 2 as the second element (index 1).
import 'dart:async';
Future main() async {
print('start');
List<int> li = await Future.wait<int>([
fetchLong(), // longer (which gives 4) is first
fetchShort(), // shorter (which gives 2) is second
]);
print('results: ${li[0]} ${li[1]}'); // results: 4 2
}
Future<int> fetchShort() {
return Future.delayed(Duration(seconds: 3), () {
print('Short!');
return 2;
});
}
Future<int> fetchLong() {
return Future.delayed(Duration(seconds: 5), () {
print('Long!');
return 4;
});
}
If you want to wait for multiple futures of different types and also support null-safety then you can add a helper function similar to the following.
import 'package:tuple/tuple.dart';
Future<Tuple2<T1, T2>> waitConcurrently<T1, T2>(
Future<T1> future1, Future<T2> future2) async {
late T1 result1;
late T2 result2;
await Future.wait([
future1.then((value) => result1 = value),
future2.then((value) => result2 = value)
]);
return Future.value(Tuple2(result1, result2));
}
In order for this to work you need tuples.
At the moment Dart does not provide tuples natively, but there is a package from Google which does: https://pub.dev/packages/tuple
In addition, I'd like to supplement Günter Zöchbauer's answer with FutureOr variant. You'll need to convert your FutureOr<T> variable to Future<T> first and then call wait:
Future.wait(list.map((x) async => x))