Skip to main content

Flutter Introduction

FLUTTER

First App in Flutter
import "package:flutter/material.io";
void main()                                                                   <---------------- Entry point  of application
{
 runApp(                                                                       <---------------  Inflates widget and shows it on app screen
    Center(                                                                     <---------------    Center and  
        Text(                                                                     <---------------     Text are widgets
            "Hello FLutter",
            textDirection : TextDirection.ltr;
        )
    )
);
}

In flutter, almost everything is just a widget,
Whatever we see on screen is  a widget

Some common widgets : 
Center
Text
Material App
Material 
Scaffold
AppBar

import "package:flutter/material.dart";
void main()
{
runApp(
    MaterialApp(
    title: "MyFirstFlutterApp",
    home : Scaffold(
            appBar: AppBar(title: Text("Hi Hello Slawalekum!"),),
            body: Material(
                    color: Colors.blueAccent,
                    child :
                    Center(
                        child:
                        Text(
                            "Hello Flutter",
                            textDirection: TextDirection.ltr,
                            style: TextStyle(
                            color : Colors.white,
                            fontSize: 40.2,
                            ),
                        ),
                    )
                )
             )
         )
    );
}

Asynchronus Programming:
Flutter is written using Dart and Dart is a single-threaded language then Flutter apps are single-threaded. This means that a Flutter app can only do one thing at a time.

But Dart/Flutter is Single-Threaded:

So in Flutter Main UI thread has to perform these tasks also,
and that is done using asynchronous programming

Flutter apps use an event loop

This should come as no surprise since Android has a main looper and iOS has a run loop (aka. main loop). Heck, even JavaScript devs are unimpressed since JavaScript itself has a … wait for it … event loop. Yes, all the cool kids are using an event loop these days.
An event loop is a background infinite loop which periodically wakes up and looks in the event queue for any tasks that need to run. If any exist, the event loops put them onto the run stack if and only if the CPU is idle.
As your app is running instructions, they run serially — one after another. If an instruction is encountered that may potentially block the main thread waiting on some resource, it is started and the ‘wait’ part is put on a separate queue.

Why would it wait?

Certain things are slow compared to the CPU. Reading from a file is slow. Writing to a file is even slower. Communicating via Ajax? Forget about it. If we kept the waiting activity on the main thread it would block all other commands. What a waste!
The way this is handled in JavaScript, iOS, Android, and now Dart is this:
An activity that is well-known to be slow is started up as normal.
The moment it begins waiting for something — the disk, HTTP request, whatever — it is moved away from the CPU.
A listener of sorts is created. It monitors the activity and raises an alert when it is finished waiting.
The reference to that listener is returned to the main thread. This reference object is known as a Future.
The main thread continues chugging along its merry way.
When the waiting activity is finally resolved, the event loop sees it and runs an associated method on the main thread to handle finishing up the slow event.
All you do is write the code to create the future and to handle futures that are returned from other methods.
In Dart you have the ability to specify the type of thing that Future will give you eventually:
When we have that Future object, you may not have the data, but you definitely have a promise to get that data in the Future. (See what they did there?)

How do we get the data from a Future?

You tell the Future what to do once the data is ready. Basically, you’re responding to a “Yo, the data is ready” event and telling the Future what to do by registering a function which we refer to as a callback.
myFuture.then(myCallback);
The .then() function is how you register that callback function. The callback should be written to handle the promised data. For example, if we have a Future<Foo> then our callback should have this signature:
So if the Future will return a Person, your callback should receive a Person. If the Future promises a String, your callback should receive a String. And so forth.
Your callbacks should always return void because there’s no way that the .then function can receive a returned value. This makes a ton of sense when you think about it because remember that it is no longer running within the main thread of your app so it has no way of merging back in. So how do you get a value from the callback? Several methods, but the most understandable is that you use a variable that is defined outside the callback:
To get a value out of an async callback, you set an external variable
Tacking a .then() onto your Future object can occasionally muddy up your code. If you prefer, you can clean it up a bit with await.

await

There’s another way to get the data which is more straightforward to read. Instead of using .then(), you can await the data.
Foo theIncomingData = await somethingThatReturnsAFuture();
Awaiting pauses the running code… well … wait for the Future to resolve before it moves on to the next line. In the example above, the “Foo” that you’re awaiting is returned and put into the incoming data. Simple.
Or maybe it isn’t that simple…

async

Like it or not, when you use await inside a function, that function is now in danger of blocking the main thread, so it must be marked as async. For example, this function …
… becomes this when we await:
Note that when we added an await on line 2, we must mark the function itself with async. The subtle thing is that when it is marked as async, anything returned from that function is immediately wrapped in the Future unless it is already one.
Are you sitting down? Check this out: whenever you choose to await a future the function must be marked as async and therefore all who call it must be awaited and they must be marked as async and so on and so on. Eventually you get to a high enough spot in the call chain that you’re not in a function so you don’t have to mark it as async.
Maybe I spoke too soon when I said this is simpler.
Hint: The Flutter build() method cannot be async but events like onPress can. So try to steer your async activities into events to solve this recursive async-await-async-await thing.

Here are your takeaways:
Futures allow your Dart code to be asynchronous — it can handle slow-running processes in a separate thread (kind of).
You can handle the callbacks of those things with either a .then(callback) or by awaiting them.
If you await in a function, that function must be marked as async.



USING SQLITE in FLutter
Persisting data is very important for users since it would be inconvenient for them to type their information every time or wait for the network to load the same data again. In situations like this, it would be better to save their data locally.
In this article, I will demonstrate this using SQLite in Flutter.

If you speak Portuguese you can find the translated version here

Why SQLite?

SQLite is one of the most popular ways to store data locally. For this article, we will be using the package sqflite to connect with SQLite. Sqflite is one of the most used and up to date packages for connecting to SQLite databases in Flutter.

1. Add dependencies to your project

In your project go to pubspec.yaml and look for dependencies. Under dependencies, add the latest version of sqflite and path_provider (use the right numbers from Pub).
NOTE:
We use the path_provider package to get the commonly used location such as TemporaryDirectory and ApplicationDocumentsDirectory.

2. Create a DB Client

Now in your project create a new file Database.dart. In the newly created file, we need to create a singleton.
Why we need singleton: We use the singleton pattern to ensure that we have only one class instance and provide a global point access to it
1.Create a private constructor that can be used only inside the class :
2.Setup the database
Next we will create the database object and provide it with a getter where we will instantiate the database if it’s not (lazy initialization).
If there is no object assigned to the database, we use the initDB function to create the database. In this function, we will get the path for storing the database and create the desired tables:
NOTE: The database name is TestDB and the only table we have is called Client. If you don't know what's going on you really need to go and learn some SQL it's more important than water.

3. Create the Model Class

The data inside your database will be converted into Dart Maps so first, we need to create the model classes with toMap and fromMap methods. I am not going to cover how to do this manually. If you don’t know how to do this, you should consider reading this article by Poojã Bhaumik.
To create our model classes, I am going to use this website. If you don’t already have it bookmarked, you really should :)
Our Model:

4. CRUD operations

Create

The SQFlite package provides two ways to handle these operations using RawSQL queries or by using the table name and a map which contains the data :
Using rawInsert :
Using insert :
Another example using the biggest ID as a new ID:

Read

Get Client by id

In the above code, we provide the query with id as the argument using whereArgs. We then return the first result if the list is not empty else we return null.

Get all Clients with a condition

In this example I used rawQuery and I mapped the result list to a list of Client objects:
Example: Only get the Blocked Clients

Update

Update an existing Client

Example: Block or unblock a Client:

Delete

Delete one Client

Delete All Clients


Demo

For our demo, we will create a simple Flutter app to interact with our database.
We will first start with the app’s layout:
Notes :
1. The FutureBuilder is used to get the data from the database.
2. The FAB adds a random client to the database when it’s clicked.
3. A CircularProgressIndicator is shown if there is no data.
4. When the user clicks the checkbox the client will be blocked or unblocked according to the current state.
Now it’s very easy to add new features, for example, if you want to delete a client when the item is swiped, just wrap ListTile with a Dismissible Widget like this:
For our OnDismissed function, we are using the Database provider to call the deleteClient method. For the argument, we are passing the item’s id.

Refactoring to use BLoC Pattern

We have done a lot in this article but in a real-world applications, making state part of the UI isn’t really a good thing. Instead, we should always keep them separated.
There are a lot of patterns for managing state in Flutter but I will use BLoC in this article because it’s very flexible.

Create the BLoC :

Notes :
getClients will get the data from the Database (Client table) asynchronously. We will call this method whenever we update the table hence the reason for placing it into the constructor’s body
We StreamController<T>.broadcast constructor so that we are able to listen to the stream more than once. In our example, it doesn't make much of a difference since we are only listening to the stream once but it is good to consider cases where you want to listen to the stream more than once.
Don't forget to close your stream. This prevents us from getting memory leaks. In our example, we will close it using the dispose method of our StatefulWidget.
Now let’s add some methods to our block to interact with the database :
And that’s all for our BLoC!
Our next step would be finding a way to provide our bloc to our widgets. We need a way to make the bloc accessible from different parts of the tree while also being able to free itself from memory when not in use.
For this can take a look at this library by Remi Rousselet.
In our case, the bloc is only going to be used by one widget so we can declare it and dispose of it from our stateful widget.
Next, we need to use StreamBuilder instead of FutureBuilder. This is because we are now listening to a stream (clients stream) instead of a future.
The final step would be to refactor our code so that we are calling the methods from our bloc and not the database directly:
Here is the final result
Finally, you can find the code source for this example in this repo (check the sqlite_demo_bloc branch to see the new version after refactoring ). I hope you enjoyed this article.

Comments