how do I use this OnCompleted function? - flutter

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*/};

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.

Why should I only use `setState` in subclasses of `framework.dart`?

I have written and extension on Stream that allows me to call .watch(<some state>) and automatically keep the widget updated. It works really well, however, I call setState on passed states from the extension and because of this I get a warning saying The member 'setState' can only be used within instance members of subclasses of 'package:flutter/src/widgets/framework.dart'. My question is why is this not recommended/allowed?. To clarify, I get why I am getting the warning - I'm calling setState from another class - but why does Flutter "care" if I do this?
I have tried to find information on any reason for this, but I can only find the obvious workaround of adding a helper function, and no reason is given.
There could be two possible reasons why you are getting this error:
You are using a static or final keyword somewhere where you declare a state
You are unable to setState, because the extension is updating the state of the widget already
Let me know if you need any further help or I understood you wrong!

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

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.

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

RX, Loaded event

Attempting to use RX with events, but this one is alluding me. This is the "normal" way to subscribe to an event
this.Loaded += new RoutedEventHandler(SelectPartyPersonDataEntry_Loaded);
The RX Way....
Observable.FromEventPattern<RoutedEventArgs>(this, "Loaded").Subscribe((routedEvent) => this.Searchbutton_Click(routedEvent.Sender, routedEvent.EventArgs));
however, it fails silently and I'm not sure why.
Thanks!
I'm not quite sure how to handle this, as both of these answers helped me understand where I was going wrong with this. The correct syntax (or that one that works is):
Observable.FromEventPattern<RoutedEventHandler, RoutedEventArgs>(h => this.Loaded += h, h => this.Loaded -= h).Subscribe(routedEvents => SelectPartyPersonDataEntry_Loaded(routedEvents.Sender, routedEvents.EventArgs));
Which simply looks more confusing that anything else. I have to provide both the EventHandler type (RoutedEventHandler), as well as the event argument type to (RoutedEventArgs), in order to subscribe to the events. Using this signature of the FromEventPattern means that I have to have use the +=/-= syntax subscribing to the event.
I only see one reason why you would do this over the traditional (and more concise) syntax - the difference between a strong reference, and a weak reference. If this View goes out of scope, you must ensure the strong reference in order for the view to be garbadge collected (GC). The RX syntax is a weak reference, and as such will be GC without the dereferencing the event.
I just tested this in a WPF app:
var loadedEvent = Observable.FromEventPattern(this, "Loaded");
loadedEvent.Subscribe(e => MessageBox.Show("loaded"));
And it works; the message box is shown.
Perhaps you could elaborate what you mean when you say it fails silently -- have you tried this in a debugger? Are you sure there's a Loaded event in there?
I suspect that it has something to do with not providing the type of the event args. The method signature that you're using is:
IObservable<EventPattern<EventArgs>>
FromEventPattern(object target, string eventName)
I suspect you need:
IObservable<EventPattern<TEventArgs>>
FromEventPattern<TEventArgs>(object target, string eventName)
where TEventArgs: EventArgs
Better yet, don't use the "reflection" method (i.e. no magic strings). Use this instead:
IObservable<EventPattern<TEventArgs>>
FromEventPattern<TDelegate, TEventArgs>(
Action<TDelegate> addHandler, Action<TDelegate> removeHandler)
where TEventArgs: EventArgs