Bound variable in ViewModel is not updating the displayed value - mvvm

I was trying to create an countdown timer in ViewModel but i didnt found any method to do that so i ve tried to do this with task delay and while loop but it ends after first task delay. Do u know any other way how to do that or how to repair that one.
public PageViewModel()
{
MethodName();
}
public async void MethodName()
{
CountSeconds = 10;
while (CountSeconds > 0)
{
await Task.Delay(1000);
CountSeconds--;
}
}

The reason why you can`t see others is related to context. You trying to run async code in non-async context.
To solve this problem you can do several ways, which way to choose is your choice and depends on your needs:
await MethodName();
async Task MethodName()
{
CountSeconds = 10;
while (CountSeconds > 0)
{
await Task.Delay(1000);
CountSeconds--;
}
}
Another way is to create various of tasks and execute them, here you can see methods, which can help you.
And as Rand Random metioned it's not about MAUI, it`s about understanding of async programming itself, so for you will be usefull read more about it.

You can use Dispatacher.StartTimer() (available in the DispatcherExtensions class) to create a function that will execute every x seconds/minutes/hours (depending of what you're setting) using the device's clock.
To access the Application's Dispatcher from any class, use the following line:
var dispatcher = Application.Current.Dispatcher;
Since there is no documentation available yet for MAUI, you can read the Device.StartTimer() documentation from Xamarin, which acts exactly the same.

Related

Isolates in Flutter - Where can I place the isolates inside my Flutter code

I have some confusion regarding how Isolates can be used inside a Flutter application.
If we go through the documentation, It is said that functions that you pass inside the isolates should only be declared as top-level functions. Does that mean we cannot declare them inside a class ?
I created a class TestIsolate inside my lib/business_logic/bloc folder.
class TestIsolate {
Future<void> handle(int _m) async {
final response = ReceivePort();
await Isolate.spawn(_isolate, response.sendPort);
final sendPort = await response.first as SendPort;
final answer = ReceivePort();
sendPort.send([_m, answer.sendPort]);
await answer.first.then((p) {
log(p);
});
}
static void _isolate(SendPort _initialReplyTo) {
final port = ReceivePort();
_initialReplyTo.send(port.sendPort);
port.listen((message) {
final data = message[0] as int;
final send = message[1] as SendPort;
send.send(_syncHandle(data));
});
}
}
Future<String> _syncHandle(int data) async {
return 'done - $data';
}
I then called await TestIsolate.handle(15) upon an onTap event from my presentation layer which worked like a charm.
Am I doing this correctly ? If yes, can we call handle() placed inside TestIsolate class as a top-level function?
Any help would be really appreciated!
What you are doing is correct. The source you reference (which I will point out is an article, not documentation) says:
The function passed to the isolate spawn() must be a top-level function *(a function that is not within the boundary of a class) or a static method.
You are spawning an isolate with an entry point of _isolate(), which is a static method. So, according to your source, that is ok.
However, it may be the case that your source is outdated. According to the changelog for Dart 2.15:
Allow closures both in inter-isolate messages as well as as entrypoints in Isolate.spawn(<entrypoint>, ...) calls. Closures and their enclosing context may need to be copied in this process. The enclosing context is - as with normal messages - verified to only contain objects that are sendable.
Note of caution: The Dart VM's current representation of enclosing variables in closures can make closures hang on to more variables than strictly needed. Using such closures in inter-isolate communication can therefore lead to copying of larger transitive object graphs. If the extended transitive closure includes objects that are illegal to send, the sending will fail.
It would appear that closure (and non-static method) arguments to Isolate.spawn() were introduced after your source article was written.
As the changelog cautions though, you do want to be cognizant of the memory copying that will occur.
Further references:
Is DartDocs about the entry of Isolate.spawn wrong or something?

Dynamic tab view with multiple API calls using Flutter

I want to create a Flutter tab view, tab count and content must be based on the multiple API calls.
There is 3 section in each tab and each section get data from a separate API.
What is the best method to create a solution? Bloc is the best way to manage the state.
I tried to implement a CustomTabView and set tab data but I'm facing various issues and wired tab combinations. Please help me to solve this problem.
Thank you
This is a general question and doesn't have debug details, so the answer can seem a bit dumb.
Anyway,
The best case is to have a separate block for each section.
But you can also have all requests in one block. It is not recommended at all, but I will explain the method.
For call Multi api in one bloC:
when you use the state manager bloC , you have a method named mapEventToState that calls a second method of Stream type according to your request.
It is in this method that you return the State. In order to call several APIs, you need to define a dynamic variable here for each one. Then connect to each API here and fill these variables with the corresponding response.
To return the result, it is better if all variables containing the response containing statusCode were successful, then the state of this bloC should be succeeded.
...
#override
Stream<MyBlocState> mapEventToState(MyBlocEvent event) async* {
if (event is CallTheAPIsEvent) {
yield ApisHaveNeedCalles();
}
// second method of Stream
Stream<MyBlocState> ApisHaveNeedCalles() {
var resultApi1;
var resultApi2;
var resultApi3;
try {
resultApi1 = _repository.getAPI1();
resultApi2 = _repository.getAPI2();
resultApi3 = _repository.getAPI3();
} catch (e) {
yield ErrorState();
}
if (resultApi1 != null && resultApi2 != null && resultApi13 != null) {
yield SuccessState(resultList: [resultApi1, resultApi2, resultApi3 ]);
}
// more event handling
}
...

kotlin coroutine - what is default scope?

How does coroutines default scope work if i do not specify anything. lets take a look at this example:
class MyAppCompatActivity:AppCompatActivity{
fun getContact() {
GlobalScope.launch {
val contact = contacts.getContact() // suspended function
withContext(Dispatchers.Default) {
phoneContact.value = contact }
}
}
}
which simply updates the UI when a contact is retrieved. this is added to the global scope of so the coroutine life span can be that of the entire application.
but lets do the same thing again without a globalScope:
class MyAppCompatActivity:AppCompatActivity{
fun getContact() {
launch {
val contact = contacts.getContact() // suspended function
withContext(Dispatchers.Default) {
phoneContact.value = contact }
}
}
}
what is the lifespan of getContact now that i have removed the globalScope ? is it tied to the MyAppCompatActivity scope ?
Your code will fail to compile because launch must be called on a CoroutineScope object. This object specifies the lifespan of the coroutine. Since your activity does not implement a scope it will fail to compile or call a completely unrelated launch function.
I don't think this is a good idea anymore, as it looks like they're just functions for testing (doesn't launch coroutines). Maybe this was an API available previously, but now you should be using lifecycleScope to scope a coroutine to a fragment or activity, and viewModelScope to scope them to a View Model's life cycle. These are properties available in those classes by already.
Here's what I see when I try to use launch:

When and where is the best to initialize reliable collection?

Scenario: statefull SF service will store its state in several reliable collections. Statefull SF is available via remoting.
Do I need to "initialize" the collections before the first use (by calling StateManager.GetOrAddAsync)? Will it help lower the first access to reliable collection or it is not necessary to do this step?
If it is advised to do this init, when is right time and place to do it?
The most reasonable place is right before endless loop in RunAsync but what if method called via remoting will be called before the collections are initialized? Is there going to be any deterioration in performance in that first remoting call (when the collection is going to be initialized)?
Last thing -> when working with reliable collections it is OK to hold reference to collection in class (e.g. during some instance initiation I will get the reference by using StateManager.GetOrAddAsync) and working just with this reference or is better to call StateManager.GetOrAddAsync before every call to collection?
Thanks for answers!
Do I need to "initialize" the collections before the first use (by calling StateManager.GetOrAddAsync)?
Yes, but you don't have to do that to “warm up” collection. Call that method if you really need retrieve some data or want to store something.
what if method called via remoting will be called before the collections are initialized?
That's why you need to do StateManager.GetOrAddAsync on every call to the service.
Is there going to be any deterioration in performance in that first remoting call
Yes. But it will be unnoticeable.
when working with reliable collections it is OK to hold reference to collection in class
You can hold a reference to the collection in a variable within a method call. Here is an example:
public async Task AddPost(Guid userId, PostId postId)
{
try
{
var state = await StateManager.GetOrAddAsync<IReliableDictionary<Guid, List<PostId>>>(StateName);
using (var tx = StateManager.CreateTransaction())
{
await state.AddOrUpdateAsync(
tx,
userId,
addValue: new List<PostId> {postId},
updateValueFactory: (usrId, oldPostsList) =>
{
oldPostsList.Insert(0, postId);
return oldPostsList;
}
);
await tx.CommitAsync();
}
}
catch (TimeoutException)
{
PostsLogger.Singleton.LogWarning("Add post timeout");
throw;
}
catch (Exception ex)
{
PostsLogger.Singleton.LogException(sb.ToString(), ex);
throw;
}
}

.NET Rx - ReplaySubject buffer size not working

I've been using .NET Reactive Extensions to observe log events as they come in. I'm currently using a class that derives from IObservable and uses a ReplaySubject to store the logs, that way I can filter and replay the logs (for example: Show me all the Error logs, or show me all the Verbose logs) without losing the logs I've buffered.
The problem is, even though I've set a buffer size on the subject:
this.subject = new ReplaySubject<LogEvent>(10);
The memory usage of my program goes through the roof when I use OnNext to add to the observable collection on an infinite loop:
internal void WatchForNewEvents()
{
Task.Factory.StartNew(() =>
{
while (true)
{
dynamic parameters = new ExpandoObject();
// TODO: Add parameters for getting specific log events
if (this.logEventRepository.GetManyHasNewResults(parameters))
{
foreach (var recentEvent in this.logEventRepository.GetMany(parameters))
{
this.subject.OnNext(recentEvent);
}
}
// Commented this out for now to really see the memory go up
// Thread.Sleep(1000);
}
});
}
Does the buffer size on ReplaySubject not work? It doesn't seem to be clearing the buffer when the buffer size is reached. Any help much appreciated!
UPDATE:
I add subscribers like this (Is this wrong?):
public IDisposable Subscribe(IObserver<LogEvent> observer)
{
return this.subject.Subscribe(observer);
}
...which is called like:
// Inserts into UI ListView
this.logEventObservable.Subscribe(evt => this.InsertNewLogEvent(evt));
I'm not sure if this is the definitive answer, but I suspect that you're hitting an issue because of concurrency around the scheduler you're using. The constructor you're calling on ReplaySubject looks like this:
public ReplaySubject(int bufferSize)
: this(bufferSize, TimeSpan.MaxValue, Scheduler.CurrentThread)
{ }
The Scheduler.CurrentThread worries me. Try changing it to Scheduler.ThreadPool and see if that helps.
Also, as a side note, you seem to be mixing Rx with TPL and old fashioned thread sleeping. It's usually best to avoid doing that. You could change your WatchForNewEvents code to look like this:
dynamic parameters = new ExpandoObject();
var newEvents =
from n in Observable.Interval(TimeSpan.FromSeconds(1.0))
where this.logEventRepository.GetManyHasNewResults(parameters)
from recentEvent in
this.logEventRepository.GetMany(parameters).ToObservable()
select recentEvent;
newEvents.Subscribe(this.subject);
That's a nice compact Rx-y way of doing things.