StreamBuilder triggers a method twice while the same operation as a variable triggered only once - flutter

I have a StreamBuilder that accepts a stream from my service. It looks like this:
StreamBuilder(
stream: MyService.getStream$()
builder (...)
);
Plus, I have my service with the following method:
getStream$() {
print('being printed twice');
return Observable.just('text')
.doOnData(() => print('being printed twice too'));
}
When I run the app, I get the following prints being printed twice (each).
But, when I change the following implementation as a variable, it runs just once:
Observable getStream = Observable
.just('text')
.doOnData((data) => print('being printed once');
Of course, in the example above, I would use variables, but in my original code, I'm unable to do so because I'm depended on the instance properties.
What I can do, is to declare an Observable variable and in the constructor to set it to my desired observable. Although, this solution sounds like a workaround, and I'm not sure why would the the method would be triggered twice.
Any ideas?

StreamBuilder is rebuild every time build method is invoked. It means that MyService.getStream$() is evaluated with each invocation and creates new Observable. If you assign Observable to variable it will be created once and reused between build calls.
Take a look at this question Future running twice because it's in build method, how to fix it?
it's about future but the mechanism is same.

Related

What does the query method do in Flutter Flame game and what type is it supposed to be?

I'm trying to get the update function in Flame game to work. I have a global variable called newInstructions that's a list that gets updated by a separate function. I want the update function to check when there's a new addition to the list and call a function (populateInfo) with that list as input. After looking at some of the documentation, I've come up with what I think would be the correct code, but it keeps returning this error:
The method 'query' isn't defined by the type 'List'
I think that part of this might come from my not fully understanding what the update/query methods do. With that, what does the query method do and what type should it be? How would I go about changing my code to fix that error?
Here is the update function that I wrote:
#override
void update(double dt){
final instructions = newInstructions.query<List>();
populateInfo(instructions);
}
With that, what does the query method do and what type should it be?
query is a Flame specific method that is used on the OrderedSet in each component where the children are stored, it is used to get children of a specific type. For example to get all Player components:
children.query<Player>();
How would I go about changing my code to fix that error?
Since you want to react to when something is added the newInstructions list you shouldn't do this check in update since this method runs at least 60 times per seconds, it's better to just react once when there is a new instruction added.
This can be done in a few different ways, you could for example put the newInstructions list in a class that you then have an add method on that both adds the instruction to a list contained within the class, and also calls populateInfo. You could also wrap the list in a ChangeNotifier like this.

how do I use this OnCompleted function?

This library I found that handles music playing has the following variable public.
void Function() onCompleted;
I want to change the icon of a button when the track is finished, so that it returns to a play icon.
I tried using musicPlayer.OnCompleted(() { **stuff** }); but that gives me a syntax error Too many positional arguments: 0 expected, but 1 found.
How do I subscribe on that event, or how do I check if OnCompleted has been called?
I am still pretty new to dart but can't wrap my head around this one. I tried subscribing like in Angular or looking up if there's a different syntax for it, but I am at a loss.
Presumably you have to set onCompleted to something, specifically a function taking no parameters and returning void.
It would be normal to provide something like this in the constructor. Is there a named, optional parameter for this? Alternatively, there may be a setter.
Let's assume there's a setter. You could write:
musicPlayer.onCompleted = (){/* do stuff*/};

Observable - don't return results until successful completion

I have an IObservable<T> that comes from parsing a CSV, spitting out a parsed result for each row.
There's an issue right now with corruption in the source data that I cannot detect until I've already reached the end of the file: with the current Reactive setup, that means I've already emitted bad results.
Until the source data issue is resolved, is there a way I can "buffer" (hold back) an entire IObservable result stream such that no results are emitted until it has completed successfully? No method signatures should change (the source should still return IObservable<T>).
It's easy, just do this:
var query = source.ToArray();
IDisposable subscription =
source.Subscribe(allRows =>
{
/* do something with `allRows` */
});
The .ToArray() operator turns an IObservable<T> that returns zero or more values into an IObservable<T[]> that returns one array of T that contains zero or more elements.
You must make sure that your source observable ends with an OnCompleted for the array to be produced.
You can also use .ToList() which returns an IList<T> rather than an T[].
If you want to return a IObservable<T> rather than a IObservable<T[]> simply put a .SelectMany(t => t) after the .ToArray(). Keep in mind that this means that all the values will come at once as soon as the source observable completes.
I'm sure there's a nicer way, but this should work:
// csvObservable is your existing observable
var waitTillEndObservable = csvObservable.ToList().Wait().ToObservable();
This converts to a list, waits until it's done, and then converts back to an observable so that it can be used interchangeably with your existing csvObservable.

What is this ScalaRX code doing?

So I'm pretty new to both Scala and RX. The guy who knew the most, and who actually wrote this code, just left, and I'm not sure what's going on. This construct is all over his code and I'm not really clear what its doing:
def foo(List[Long]) : Observable[Unit] =
Observable {
subscriber => {
do some stuff
subscriber.onNext()
subscriber.onCompleted()
}
I mostly get do some stuff, and the calls to subscriber. What I don't get is, where does subscriber come from? Does subscriber => { instantiate the subscriber? What does Observable { subscriber => { ... } } do/mean?
If you take a look at the Observable companion object documentation, you will see an apply method that takes a function of type (Subscriber[T]) ⇒ Unit. So, when you call Observable{withSomeLambda}, then this is the same as calling Observable.apply{withSomeLambda}
And, if you go all the way to the source code you will see that this is really returning
toScalaObservable(rx.Observable.create(f))
where f is the lambda that you passed in.
So, subscriber is just the parameter of the lambda. It is passed in by the caller of that function.
This code is creating a new Observable as described here.
Basically when a downstream component subscribes to this stream, this callback is called. In the callback we determine when we, as a data source, will call onNext(v: T) which is how we pass each element we are generating to them, and when we will call onCompleted() which is how we tell the subscriber that we are done sending data.
Once you have created an Observable you can start calling Observable operators, which will either result in another, compound Observable, or will result in a terminating condition which will end the process, and generally result in a final result for the flow (often a collection or aggregate value).
You don't use the List in your question, but normally if you wanted to make a reactive stream out of a list you would call Observable.from().
PS: I think this is RxJava code.

dart js-interop FunctionProxy callback relationship to js.context

I have a Dart js-interop callback that in turn takes a javascript callback as an argument. The dart callback implementation looks like this:
void callBackToDartCode(String query, js.FunctionProxy completionCallback) {
js.context.completionCallback = completionCallback;
doSomethingAscyn(query).then(
(result) {
// hand the query result back to the javascript code
js.context.completionCallback(js.map(result));
});
This works. The key to making this work is to save the FunctionProxy in the js.context so that it is available when it comes time to execute it in the async "then" method. This line of code is important:
js.context.completionCallback = completionCallback;
If that's not done then the completeCallback is not retained and hence cannot be called when the async operation completes.
I have not seen examples like this and I am not sure I have really done this properly.
It raises questions:
How do I disassociate "completeCallback" from js.context after I've called it? Does it remain associated with js.context forever?
It appears there will be conflicting use of the name "completionCallback" within js.context if multiple async operations are in progress at the same time. That strikes me as a common problem. Does js-interop have a way to deal with that or is it my job to manage that?
With js-interop all proxies are scoped to prevent memory leaks. This means that Proxy will lost its JS object reference at the end of its associated scope. If scoped((){}) function is not use explicitely a lazy scope is initialized the first time an interop operation is done and the scope is automatically closed at the end of the current event loop. If you want to make a Proxy to live longer than its associated scope, you have to retain it. This can be done with js.retain(proxy). Once your proxy is no longer needed, you can release it with js.release(proxy).
Thus your code should be :
void callBackToDartCode(String query, js.FunctionProxy completionCallback) {
js.retain(completionCallback);
doSomethingAscyn(query).then(
(result) {
// hand the query result back to the javascript code
completionCallback(js.map(result));
// completionCallback is no longer used
js.release(completionCallback);
});
}
About your question about disassociate "completeCallback" from js.context you could have done it with js.deleteProperty(js.context, "completeCallback")