Flutter: why ever use a Future over a Stream? - flutter

If a Future displays a once off piece of data while a Stream offers the additional advantage of updating information in real-time when data is modified at the source (ie, Firestore database), then why would one ever use a Future? What disadvantages would using a Stream over a Future have?

Why would one ever use a Future?
A Future handles a single event when an asynchronous operation completes or fails. It can be used for simple HTTP requests (GET, POST, ...).
You can have a look to the boring flutter development show where Google engineers build a simple Hacker News app, with Futures.
EDIT
New video from Flutter team about dart Futures
What disadvantages would using a Stream over a Future have?
They are made for different needs : real time updates or asynchronous calls, so they cannot really be compared in terms of advantages of one over the other.

Related

What are the best practices when working with data from multiple sources in Flutter/Bloc?

The Bloc manual describes the example of a simple Todos app. It works as an example, but I get stuck when trying to make it into a more realistic app. Clearly, a more realistic Todos app needs to keep working when the user temporarily loses network connection, and also needs to occasionally check the server for updates that the user might have added from another device.
So as a basic data model I have:
dataFromServer, which is refreshed every five minutes, and
localData, that describes what changes have been made locally but haven't been synchronized to the server yet.
My current idea is to have three kinds of events:
on<GetTodosFromServer>() which runs every few minutes to check the server for updates and only changes the dataFromServer,
on<TodoAdded>() (and its friends TodoDeleted, TodoChecked, and so on) which get triggered when the user changes the data, and only change the localData, and
on<SyncTodoToServer>() which runs whenever the user changes the todo list, or when network connectivity is restored, and tries to send the changes to the server, retrieves the new value from the server, and then sets the new dataFromServer and localData.
So obviously there's a lot of interaction between these three methods. When a new todo is added after the synchronization to the server starts, but before synchronization is finished, it needs to stay in the local changes object. When GetTodosFromServer and SyncTodoToServer both return server data, they need to find out who has the latest data and keep that. And so on.
Coming from a Redux background, I'm used to having two reducers (one for local data, one for server data) that would only respond to simple actions. E.g. an action { "type": "TodoSuccessfullySyncedToServer", uploadedData: [...], serverResponse: [...] } would be straightforward to parse for both the localData and the dataFromServer reducer. The reducer doesn't contain any of the business logic, it receives actions one by one and all you need to think about inside the reducer is the state before the action, the action itself, and the state after the action. Anything you rely on to handle the action will be in the action itself, not in the context. So different pieces of code that generate those actions can just fire these actions without thinking, knowing that the reducer will handle them correctly.
Bloc on the other hand seems to mix business logic and updating the state. API calls are made within the event handlers, which will emit a value possibly many seconds later. So every time you return from an asynchronous call in an event handler, you need to think about how the state might have changed while that call was happening and the consequences this has on what you're currently doing. Also, an object in the state can be updated by different events that need to coordinate among themselves how to avoid conflicts while doing so.
Is there a best practice on how to avoid the complexity that brings? Is it best practice to split large events into "StartSyncToServer" and "SuccessfullySyncedToServer" events where the second behaves a lot like a Redux reducer? I don't see any of that in the examples, so is there another way this complexity is typically avoided in Bloc? Or is Bloc entirely unopinionated on these things?
I'm not looking for personal opinions here, only if there's something I missed in the Bloc manual (or other authoritative source) about how this was intended to work.

ObjectBox Dart/Flutter multi-isolate access

Creating a separate thread for a question stated in a comment...
How does ObjectBox handle concurrent(by different threads/isolates) write requests? example of my use case: FCM "onBackgroundmessage" call runs in a different isolate, the same time multiple write requests might happen. "Hive" is failing in this case completely. Is there any inbuild solution in ObjectBox?
ObjectBox for dart is based on a native ObjectBox core library that handles concurrency using Transactions. Let me pick out few points relevant to the question:
Transactions manage multi-threading; e.g. a transaction is tied to a thread and vice versa.
Read(-only) transactions never get blocked or block a write transaction.
There can only be a single write transaction at any time; they run strictly one after the other (sequential).
As for the isolates in Dart/Flutter - yes, they can safely access the same store, you just need to make sure it really is the same native store instance. To do so, you do the following steps:
Create a Store() instance in your main isolate, as you normally would.
Get ByteData store.reference which contains the information about the native store.
Send this reference to another isolate, via a SendPort.
In another isolate, receive the reference and open a local Store instance, using Store.fromReference(getObjectBoxModel(), msg as ByteData).
Now both isolates have their own Dart Store instances which internally use the same underlying native store. Therefore, their transactions are synchronized, they both see the same data and get notifications on data changes. 🎉
You can see the code I've just described this test case: https://github.com/objectbox/objectbox-dart/blob/461a948439dcc42f3956b7d21b232eb9c2bc26e1/objectbox/test/isolates_test.dart#L50
Make sure you don't close the store while another isolate is still using it. Better not close it at all - that's best practice in normal applications without huge amounts of background work.

Does setting listen to false on StreamProvider prevent cloud firestore read charge?

So I am using the provider architecture, more specifically, the StreamProvider, to get a list of documents
in a collection called 'Timeline Posts'. One of my goals is to minimize firestore reads and hence costs, so my question is:
If I set listen=false, I know this prevents my UI from updating when there's an update in the documents but does it also prevent firestore from reading that update and charging it as one read. Because I know everytime a document is updated and you're using stream, it counts as a read.
So does listen=false affect both my UI in flutter and the firestore read
From reading the documentation it will still read the changes in the stream. You could switch to a FutureProvider in order to prevent this from happening. If you share your code I would be happy to help you make that switch. A future is something you only would like to read one time and a stream is used for tracking real-time changes.
Why not use Futures instead? I generally use Futures instead of Stream for the situation you are describing.

How do you introduce reactive programming in an existing projet?

Potentially "subjective" question : what is a sweet spot for introducing reactive programming (rxjs, bacon, etc...) into an existing, "old-school- MVC-jquery" client side application ?
For example, Promises shine the most if you introduce it in the "API calls" layer of an application (and you can do it one function at a time, returning a Promise instead of accepting a callback - they, it tends to disseminate once everyone in the team gets a few benefits.)
From most of the tutorials I could read, I do not really see where rxjs would shine most. In the widgets (returning stream of events instead of having a 'listener-based' API ?)
Any experience welcome.
It is hard to say where it will shine the most…
For me, the key feature, is that it allows to describe code in more declarative way instead of writing complicated state machines(as it often happens when working with async logic).
In general, it can be quite useful for anything async for example in UI, or for API calls layer implementation as you mentioned about Promises, but better(promise is just a limited version of observable, except the fact that observable is lazy).
In case of implementing API calls layer, in comparison to promises it will have at least following benefits:
subscription to observable is cancellable(disposable) - for example, you can switch between subscriptions for api results without worrying about race conditions with previous api requests... it is as simple as results = queries.switchMap(q=>doApiCall(q))
it can return multiple values using the same interface - you can easily replace ajax call with subscription to web-socket, and you will not need to change code that is using this.
better error handing - it is quite easy with rx to do things like retrying operation n-times before throwing an error, or handling timeout.
I suggest you to watch Netflix JavaScript Talks - Async JavaScript with Reactive Extensions by Jafar Husain, there is great examples about where RxJS can be helpful. And likely it would be mostly an answer to your question.

Can Dart have sync APIs?

I am thinking about using Dart for server side programming. Because are no full frameworks similar to Ruby on Rails, I am reviewing lower level libraries. The most needed library is Posgresql driver. I found few and most mature seems to be https://pub.dartlang.org/packages/postgresql
And here is my problem. The Postgresql driver has async API. I know that async APIs are required for client side, simply to not block UI thread. However on server side threads are available so why Postgresql driver has async API?
I known about Promises APIs but for me this is just unneeded complexity when doing things on server side. Code readability is most important.
I just wonder if there is something in Dart language design that forces people to build async APIs. So the question is: can Dart have sync APIs for database and file IO operations?
Dart libraries/packages can offer sync APIs. DB ones don't tend to, because you usually don't want to block the entire server waiting for a potentially long DB operation to finish. For example, say you're creating a web server, with a request handler that fetches data from the DB and serves it. If you're only using sync operations, and you get 10 requests, 9 of those will be waiting for the first one to finish before being processed.
If your only concern is readability, you can wait for the await keyword to be implemented, which will help your code feel like sync code, while actually working async:
var conn = await connect(uri);
var results = await conn.query('select * from users').toList();
for(result in results) {
print("${result.username} has email address ${result.emailAddress}.");
}
Dart does have synchronous file io operations. For example see File.readAsStringSync().
Dart does not have a built in way to perform blocking io on a socket, which means that the postgresql library must be asynchronous.
Dart, even on the server, doesn't really have "threads". It has isolates which can run in parallel, but can only communicate by message passing, and do not have synchronisation primitives like mutexes.
Here is a list of server frameworks.
When writing asynchronous code in Dart, the Future.then() syntax, especially with multiple levels of nesting, can become tedious. Luckily the async/await feature is being implemented which means you can write code that is asynchronous but reads similar to code written with blocking io. For example:
main() async {
var conn = await connect('postgresql://foo');
try {
var sql = "select 'foo'";
var result = await conn.query(sql).toList();
return result[0];
} on Exception catch (ex) {
print('Query error: $ex');
} finally {
conn.close();
}
}
As of Nov14, to use async await you need to run dart with the --enable_async flag, and be prepared for crashes, and missing stack trace information - this feature is under active development and not yet stable. Another more stable option is to use the async_await package to translate your async/await code to use Futures.
If you have any specific questions about the postgresql driver (I am the author), feel free to open an issue against it in github, or to send me an email. My email address is on the postgresql pub page.
You need concurrent programming on the server too, not only on the client. It would be highly inefficient for the server to process requests from clients one after another - waiting until one request is totally completed before starting to process the next request while the Dart server process itself is waiting for the operating system, the database or the network to complete calls made to it.
When an I/O operation which are usually async is called, Dart can start processing other requests while it waits for invoked I/O operations to complete.
You can improve concurrent programming by using isolates but you can't create a Dart application that does some kind of I/O calls with sync calls only.
Dart doesn't support multithreading, if not in the form of Dart isolates (but those are not production ready). Only asynchronous processing is well supported, and the "await" keyword (the best syntax for coroutines) is being added to Dart in the next few months. If you need to build a small web site it will work great.
But if you need a really scalable solution for a big web site or a demanding web app, I suggest you to use the combination of Dart+Go. Make Dart to manage the client/UI side, and Golang to manage the data providers on server side. Go is the most performant language server side thanks to his innovative "Goroutines". Goroutines are a form or coroutines that runs automatically in multiple threads, combining the flexibility of asynchronous processing with the efficiency of synchronous multithreading. Goroutines are automatically multiplexed onto multiple OS threads so if one should block, such as while waiting for I/O, others continue to run.
Go+Dart makes a really powerful combination.