Real-time data delivery is one of the most important elements of mobile application development. This is primarily because users want to see up-to-date data in the UI without any additional actions/gestures to update the information. This capability is available for Flutter frontends (including Flutter Web) out of the box in Backendless and we call it Real-Time Database.
Applications using Backendless SDK for Flutter can subscribe to changes happening in a data table in the database. This quick guide will help you to get an understanding of how Backendless real-time database works. You will build a basic Flutter app displaying a list of movies from Backendless Database. The movie list will be dynamically updated anytime the data changes in the database. The changes in the database which will be displayed in the application in real-time include: new movies saved in the database and existing movies modified or deleted.
The sample Flutter database application developed as a part of this quick start guide requires some data to be stored in the database. This section of the guide contains instructions for populating the database with sample data. There are several ways to get data into Backendless Database, however, in this guide, we will consider only two methods, both of which use Backendless Console. The first one imports data from a CSV file, and the second one uses REST Console:
Create a file called Movies.csv with the following content:
"description(STRING(100))","rating(STRING(36))","release_year(STRING(36))","title(STRING(36))","objectId(STRING_ID)","ownerId(STRING(36))","created(DATETIME)","updated(DATETIME)" "A Intrepid Documentary of a Sumo Wrestler And a Astronaut who must Battle a Composer in The Outback","G","2006","CROSSROADS CASUALTIES","2AF53B19-6A91-0F28-FF05-85980DFEE500",null,"Tue Jul 02 08:26:30 UTC 2019",null "A Thoughtful Tale of a Woman And a A Shark who must Conquer a Dog in A Monastery","NC-17","2006","JASON TRAP","56B0EBD9-3C2B-68D6-FFFB-7EE98388A000",null,"Tue Jul 02 08:26:30 UTC 2019",null "A Touching Drama of a Crocodile And a Crocodile who must Conquer a Explorer in Soviet Georgia","G","2006","DESTINY SATURDAY","81F71483-A809-4662-FF43-951511680000",null,"Tue Jul 02 08:26:30 UTC 2019",null "A Epic Drama of a Mad Scientist And a Explorer who must Succumb a Waitress in An Abandoned Fun House","PG","2006","SKY MIRACLE","D1040D67-A9E8-72C0-FF4B-88E219616A00",null,"Tue Jul 02 08:26:30 UTC 2019",null "A Action-Packed Reflection of a Car And a Moose who must Outgun a Car in A Shark Tank","R","2006","PLUTO OLEANDER","D9B7498B-CF23-6D70-FFB8-0AA56859C000",null,"Tue Jul 02 08:26:30 UTC 2019",null
Open Backendless Console and navigate to Manage -> Import section and import the file as described in the screenshot below:
Click the IMPORT button. This will add the data to the Movies data table. The name of the table in the database is the same as the name of the CSV file.
Open Backendless Console and click the Data icon. Create a new data table with the name “Movies”:
You will be prompted to create columns in the new data table. Cancel out as the columns will be created dynamically with the following instructions. Click the REST Console tab. You will make a single API call which will create a data table schema and save some sample data for the app:
[ { "title": "JASON TRAP", "release_year": "2006", "rating": "NC-17", "description": "A Thoughtful Tale of a Woman And a A Shark who must Conquer a Dog in A Monastery" }, { "title": "SKY MIRACLE", "release_year": "2006", "rating": "PG", "description": "A Epic Drama of a Mad Scientist And a Explorer who must Succumb a Waitress in An Abandoned Fun House" }, { "title": "CROSSROADS CASUALTIES", "release_year": "2006", "rating": "G", "description": "A Intrepid Documentary of a Sumo Wrestler And a Astronaut who must Battle a Composer in The Outback" }, { "title": "PLUTO OLEANDER", "release_year": "2006", "rating": "R", "description": "A Action-Packed Reflection of a Car And a Moose who must Outgun a Car in A Shark Tank" }, { "title": "DESTINY SATURDAY", "release_year": "2006", "rating": "G", "description": "A Touching Drama of a Crocodile And a Crocodile who must Conquer a Explorer in Soviet Georgia" } ]
You can verify that the data has been stored in the database by clicking the DATA BROWSER tab:
Create a Flutter project and add the Backendless plugin dependency to your pubspec.yaml
. Make sure to replace VERSION FROM PUB
with a specific version number which you can find here: https://pub.dev/packages/backendless_sdk ):
dependencies: flutter: sdk: flutter backendless_sdk: ^VERSION FROM PUB
Save the changes and make sure that packages are installed. The installation should be automatically handled by IDE when the changes are detected. Otherwise you can install packages from the command line:
flutter packages get
Create the movies.dart
file and implement the Movies
stateless widget that will display a list of movies from the database:
import 'package:flutter/material.dart'; class Movies extends StatelessWidget { final List<Map> moviesList; Movies(this.moviesList); Widget _buildMovieItem(BuildContext context, int index) { return Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text(moviesList[index]['title'], style: TextStyle( color: Colors.black, fontSize: 16, fontWeight: FontWeight.bold, ), ), Text(moviesList[index]['description'], style: TextStyle( color: Colors.black, fontSize: 15, ), ), Row( children: [ Text(moviesList[index]['rating'], style: TextStyle( color: Colors.black, fontSize: 15, fontWeight: FontWeight.bold, ), ), Container( margin: EdgeInsets.fromLTRB(10, 0, 0, 0), child: Text(moviesList[index]['release_year'], style: TextStyle( color: Colors.black, fontSize: 15, fontWeight: FontWeight.bold, ), ), ), ], ), Divider( color: Colors.black, ), ], ); } @override Widget build(BuildContext context) { return ListView.builder( padding: EdgeInsets.all(10), itemBuilder: _buildMovieItem, itemCount: moviesList.length, ); } }
Open your main.dart
file and add the following code:
import 'package:flutter/material.dart'; import 'package:backendless_sdk/backendless_sdk.dart'; import 'movies.dart'; void main() => runApp(MyApp()); class MyApp extends StatelessWidget { @override Widget build(BuildContext context) { return MaterialApp( title: 'RT Database Demo', theme: ThemeData( primarySwatch: Colors.blue, ), home: MyHomePage( title: 'Watched Movies' ), ); } } class MyHomePage extends StatefulWidget { MyHomePage({Key key, this.title}) : super(key: key); final String title; @override _MyHomePageState createState() => _MyHomePageState(); } class _MyHomePageState extends State { static const String API_HOST = "https://api.backendless.com"; static const String APP_ID = "YOUR_APP_ID"; static const String ANDROID_APP_KEY = "YOUR_ANDROID_API_KEY"; static const String IOS_APP_KEY = "YOUR_IOS_API_KEY"; IDataStore<Map> moviesStore = Backendless.data.of('Movies'); List<Map> moviesList = []; @override void initState() { super.initState(); _initBackendless(); _enableRealTime(); getMovies(); } void _initBackendless() { Backendless.setUrl(API_HOST); Backendless.initApp(APP_ID, ANDROID_APP_KEY, IOS_APP_KEY); } void _enableRealTime() { // we will add code for Real Time Database here } void getMovies() { DataQueryBuilder queryBuilder = DataQueryBuilder() ..pageSize = 100 ..sortBy = ['created']; moviesStore.find(queryBuilder).then((response) => setState(() => moviesList = response)); } @override Widget build(BuildContext context) { return Scaffold( appBar: AppBar( title: Text(widget.title), ), body: Movies(moviesList), ); } }
The following import allows you to use Backendless SDK in your Dart code:
static const String API_HOST = "https://api.backendless.com"; static const String APP_ID = "YOUR_APP_ID"; static const String ANDROID_APP_KEY = "YOUR_ANDROID_API_KEY"; static const String IOS_APP_KEY = "YOUR_IOS_API_KEY"; void _initBackendless() { Backendless.setUrl(API_HOST); Backendless.initApp(APP_ID, ANDROID_APP_KEY, IOS_APP_KEY); }
Make sure to put your application ID and API Keys into the code. You can find them in Backendless Console on the Manage -> App Settings screen:
The Movies
class is StatelessWidget
. It is responsible for rendering a list of movies in the UI:
class Movies extends StatelessWidget
The following line of code obtains a reference to the Movies data table:
IDataStore<Map> moviesStore = Backendless.data.of('Movies');
Then the code retrieves database records with the paging and sorting options:
void getMovies() { DataQueryBuilder queryBuilder = DataQueryBuilder() ..pageSize = 100 ..sortBy = ['created']; moviesStore.find(queryBuilder).then((response) => setState(() => moviesList = response)); }
Once the data is loaded, the result is a collection of movie objects. The collection is assigned to the moviesList
variable. The moviesList
variable is important for the real-time integration, we will come to it a little bit later. And also when data is loaded, it is rendered. The enableRealTime
function is left empty for now.
With the code we have added by now you can already experience the app. To do this, run your Flutter application in IDE. You should see the following screen:
Before we continue, let’s review what Backendless Real-Time Database is. In most cases, you want your application to display up-to-date data without any additional user actions (such as pull to refresh for instance) or any additional requests to the server. In Backendless Real-Time Database there are three main events, which, once occurred, get your client app synchronized with the server data:
All our SDKs (Flutter, JS, Android, iOS and .NET) include necessary logic responsible for establishing and maintaining a connection to our real-time servers. The SDKs also provide the API to subscribe to the events listed above.
Now we got to the final part of the guide – adding real-time subscriptions to the code. When a new database record in the Movies
table is created, or an existing one is updated or deleted, we want the app to be notified about it and re-render the UI. Additionally, we need to maintain an up-to-date list in the app. For this purpose, the code uses the moviesList
variable. The list of the Movie cards in the UI will correspond to the objects in the moviesList
variable.
To add the real-time integration, you should add socket.io
library dependency to the Android part of your Flutter project:
implementation ('io.socket:socket.io-client:1.0.0') { exclude group: 'org.json', module: 'json' }
Then modify the enableRealTime
function as shown below:
void _enableRealTime() { EventHandler<Map> rtHandlers = moviesStore.rt(); rtHandlers.addCreateListener((movie) { setState(() { moviesList = List.from(moviesList); moviesList.add(movie); }); }); rtHandlers.addUpdateListener((movie) { setState(() { moviesList = List.from(moviesList.map((m) => m['objectId'] == movie['objectId'] ? movie : m)); }); }); rtHandlers.addDeleteListener((movie) { setState(() { moviesList = List.from(moviesList); moviesList.removeWhere((m) => m['objectId'] == movie['objectId']); }); }); }
As you can see, the code is very straightforward. There are three subscriptions for each event (a new movie is created, a movie is updated and a movie is deleted):
Let’s check what we’ve got:
To experience real-time database integration:
That’s all folks, happy coding!