Fetching Data from an API in a Flutter Splash Screen and Inserting it into a Database
Flutter is a popular framework for developing cross-platform mobile applications. In the following article, we'll look at a simple Flutter app featuring a splash screen. We'll read via the given code to understand its structure and purpose.
Imports: The code begins by importing two packages:
flutter/material.dart
and a customsplash_screen.dart
file. These imports are essential for building the user interface and managing navigation within the app.main()
Function: Themain()
function is the entry point of a Flutter app. Here, it ensures that Flutter is initialized and then runs theMyApp
widget.MyApp
Widget:MyApp
is a custom Flutter widget that extendsStatelessWidget
. In Flutter, everything is a widget, and widgets are the building blocks of your app's UI.build()
Method: Thebuild()
method is where you define the structure of your app. Here's what's happening within this method:MaterialApp
: It's a Flutter widget that provides a Material Design-themed app. ThedebugShowCheckedModeBanner
property is set tofalse
to hide the debug banner when running the app in debug mode.title
: This sets the title of the app to 'REST API'.home
: Thehome
property specifies the initial screen of the app, and it's set toSplashScreenPage()
. This suggests that your app starts with a splash screen, andSplashScreenPage
likely resides in thesplash_screen.dart
file you've imported.
import 'package:flutter/material.dart';
import 'package:rest_api/splash_screen.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return const MaterialApp(
debugShowCheckedModeBanner: false,
title: 'REST API',
home: SplashScreenPage(),
);
}
}
Splash Screen and Beyond
In this code, you've set up the foundation for your Flutter app. It begins with a splash screen, and from there, you can expand and create additional screens and functionality.
To implement the splash screen, you can customize the
SplashScreenPage
in thesplash_screen.dart
file. A splash screen is often used to display a logo or branding while the app loads resources.As your app evolves, you can navigate to other screens, fetch data from REST APIs, and provide a rich user experience. Flutter offers various packages and tools for making HTTP requests, handling responses, and managing state.
Creating a Flutter Model Class: PhotoModel
In Flutter, model classes are crucial for representing data structures that your application uses. In this article, we'll explore the PhotoModel
class you've provided. This class is designed to represent photo data fetched from an API and serves as a blueprint for how this data is structured in this Flutter app.
Understanding the PhotoModel
Class
class PhotoModel {
int? albumId;
int? id;
String? title;
String? url;
String? thumbnailUrl;
PhotoModel({this.albumId, this.id, this.title, this.url, this.thumbnailUrl});
PhotoModel.fromJson(Map<String, dynamic> json) {
albumId = json['albumId'];
id = json['id'];
title = json['title'];
url = json['url'];
thumbnailUrl = json['thumbnailUrl'];
}
Map<String, dynamic> toJson() {
final Map<String, dynamic> data = <String, dynamic>{};
data['albumId'] = albumId;
data['id'] = id;
data['title'] = title;
data['url'] = url;
data['thumbnailUrl'] = thumbnailUrl;
return data;
}
}
Properties: The PhotoModel
class defines several properties that represent attributes of a photo object:
albumId
: An integer representing the album to which the photo belongs.id
: An integer uniquely identifying the photo.title
: A string describing the title or caption of the photo.url
: A string containing the URL where the full-sized photo can be accessed.thumbnailUrl
: A string with the URL of a thumbnail version of the photo.
Constructor: This is a constructor method for the PhotoModel
class. It allows you to create instances of PhotoModel
with optional named parameters. This means you can create a PhotoModel
object with any combination of properties.
fromJson
Factory Method: This method is used to create a PhotoModel
object from a JSON map (a key-value pair structure commonly used for data interchange). It takes a Map<String, dynamic>
as input, extracts the values for each property from the map, and assigns them to the corresponding class properties.
toJson
Method: This method converts a PhotoModel
object back into a JSON map. It creates a new map, assigns each property's value to the corresponding key, and returns the map as a JSON representation of the object.
Managing Local Database in a Flutter App: DatabaseHelper
Class
In this page, we'll explore the DatabaseHelper
class you've provided. This class is a critical component of your Flutter app as it handles the initialization and management of a local SQLite database. This database is used to store and retrieve instances of the PhotoModel
class, which represents photo data fetched from a remote API.
import 'package:rest_api/model/photomodel.dart';
import 'package:sqflite/sqflite.dart';
import 'package:path/path.dart';
class DatabaseHelper {
Future<Database> initializedDB() async {
String path = await getDatabasesPath();
return openDatabase(
join(path,'photos.db'),
version: 1,
onCreate: (Database db, int version) async{
await db.execute(
"CREATE TABLE photos("
"albumId INTEGER,"
" id INTEGER PRIMARY KEY,"
" title TEXT NOT NULL,"
" url TEXT NOT NULL,"
" thumbnailUrl TEXT NOT NULL)"
);
}
);
}
Future<int> insertData (PhotoModel data) async {
final db = await initializedDB();
return await db.insert('photos', data.toJson(),
conflictAlgorithm: ConflictAlgorithm.replace); }
Future<List<PhotoModel>> getAllData() async{
final db = await initializedDB();
final List<Map<String,dynamic>> maps = await db.query('photos');
return List.generate(maps.length, (i){
return PhotoModel.fromJson(maps[i]);
});
}
}
Imports: The class imports necessary packages like photomodel.dart
for working with PhotoModel
objects, sqflite
for SQLite database operations, and path
for managing file paths.
initializedDB
Method: This method is responsible for initializing the SQLite database. It returns a Future<Database>
, which represents the database instance. Here's what this method does:
It determines the path where the database file should be stored using
getDatabasesPath()
.It opens or creates a new SQLite database named
photos.db
at the specified path.If the database doesn't exist, the
onCreate
callback is executed. In this callback, it defines the structure of thephotos
table with columns foralbumId
,id
,title
,url
, andthumbnailUrl
.
insertData
Method: This method inserts a PhotoModel
object (data
) into the photos
table. It returns the ID of the newly inserted row as a Future<int>
. Key points:
It retrieves a reference to the initialized database.
It uses the
insert
method to add the data to thephotos
table. TheconflictAlgorithm: ConflictAlgorithm.replace
parameter specifies that if there is a conflict (i.e., a row with the same primary key exists), it should replace the existing row.
getAllData
Method: This method retrieves all data from the photos
table and returns it as a list of PhotoModel
objects. Here's how it works:
It retrieves a reference to the initialized database.
It uses the
query
method to fetch all rows from thephotos
table, resulting in a list ofMap<String, dynamic>
objects.It uses
List.generate
to convert each map into aPhotoModel
object by calling thePhotoModel.fromJson
constructor.
Creating a Splash Screen in Flutter with Data Fetching and Local Database
In this page, we'll explore a Flutter SplashScreenPage
class that serves as an introductory screen for this app. This splash screen is designed to fetch data from a remote API, store it in a local database, and then navigate to another page while displaying an image. Let's dive into the code :
import 'dart:async';
import 'package:flutter/material.dart';
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:rest_api/photo.dart';
import 'datahelper.dart';
import 'model/photomodel.dart';
class SplashScreenPage extends StatefulWidget {
const SplashScreenPage({super.key});
@override
State<SplashScreenPage> createState() => _SplashScreenPageState();
}
class _SplashScreenPageState extends State<SplashScreenPage> {
final dbHelper = DatabaseHelper();
late final List<PhotoModel> data = [];
@override
void initState() {
databaseInitialized();
fetchAndSavePhotos();
super.initState();
}
Future<void> databaseInitialized() async {
await dbHelper.initializedDB();
}
Future fetchAndSavePhotos() async {
final response = await http
.get(Uri.parse('https://jsonplaceholder.typicode.com/albums/1/photos'));
if (response.statusCode == 200) {
var jsonData = json.decode(response.body);
final dbHelper = DatabaseHelper();
for (final item in jsonData) {
PhotoModel yourData = PhotoModel.fromJson(item);
await dbHelper.insertData(yourData);
}
data.clear();
data.addAll(await dbHelper.getAllData());
Navigator.pushReplacement(
context,
MaterialPageRoute(builder: (context) => MyHomePage(data : data )),
);
} else {
throw Exception('Failed to local data from the API');
}
return data;
}
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.black,
body: SafeArea(
top: true,
child: Container(
width: MediaQuery.of(context).size.width,
height: MediaQuery.of(context).size.height * 1,
color: Colors.black,
child: Center(
child: ClipRRect(
borderRadius: BorderRadius.circular(8),
child: Image.network(
'https://wallpapercave.com/wp/wp5443115.jpg',
fit: BoxFit.scaleDown,
),
),
),
),
),
);
}
}
Imports: The code imports essential packages, including flutter/material.dart
for Flutter UI, http
for making HTTP requests, and custom files like datahelper.dart
and model/photomodel.dart
, which contain database and data model logic.
State Class: _SplashScreenPageState
is the state class for your SplashScreenPage
. It contains the logic for fetching and managing data, as well as a list to store photo data.
initState
Method: In the initState
method, you perform the following actions:
Call
databaseInitialized
to initialize the local database usingDatabaseHelper
.Call
fetchAndSavePhotos
to fetch data from a remote API and save it to the local database.
databaseInitialized
Method: This method initializes the local database using theDatabaseHelper
class. It awaits the completion of the database initialization.fetchAndSavePhotos
Method: This asynchronous method fetches data from a remote API and saves it to the local database:It makes an HTTP GET request to the API using the
http
package.If the response status code is 200 (indicating success), it decodes the JSON response and saves each item to the database using
dbHelper.insertData
.After saving the data, it clears and populates the
data
list with the data from the database.Finally, it navigates to another page (
MyHomePage
) while passing the fetched data.
build
Method: Thebuild
method defines the UI structure of your splash screen. In this case, it displays a black background with a centered image fetched from a URL. This screen will be shown while data is fetched and processed.
Building a Flutter Photo List Page
In this page, we'll explore a Flutter MyHomePage
class, which represents a photo list page that displays a list of photos fetched from a local database. Users can tap on a photo to view its details. Let's dissect the code :
import 'package:flutter/material.dart';
import 'package:rest_api/datahelper.dart';
import 'package:rest_api/details.dart';
import 'package:rest_api/model/photomodel.dart';
class MyHomePage extends StatefulWidget {
final List<PhotoModel> data;
const MyHomePage({Key? key, required this.data}) : super(key: key);
@override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
final dbHelper = DatabaseHelper();
bool isLoading = true;
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('REST API'),
),
body: ListView.builder(
itemCount: widget.data.length,
itemBuilder: (context, index) {
return SizedBox(
height: 100,
child: GestureDetector(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) =>
DetailsPage( photoModel: widget.data[index],),
),
);
},
child: Card(
elevation: 4,
child: Row(
children: [
Image.network(widget.data[index].url.toString(),
width: 80, fit: BoxFit.cover),
Expanded(
child: Container(
padding: const EdgeInsets.all(10),
child: Column(
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
widget.data[index].id.toString(),
style: const TextStyle(
fontSize: 15,
fontWeight: FontWeight.bold),
),
Text(
widget.data[index].title.toString(),
maxLines: 2,
style: const TextStyle(
fontSize: 13,
fontWeight: FontWeight.bold),
),
Text(
widget.data[index].thumbnailUrl.toString(),
style: const TextStyle(
fontSize: 11,
fontWeight: FontWeight.w400),
),
],
),
))
],
),
),
),
);
},
),
);
}
}
Imports: The code includes necessary imports for Flutter (flutter/material.dart
) and custom classes like datahelper.dart
, details.dart
, and model/photomodel.dart
. MyHomePage
receives a list of PhotoModel
objects as its data source.
State Class: _MyHomePageState
is the state class for your MyHomePage
. It manages the state of the widget.
build
Method: The build
method defines the UI structure of your MyHomePage
widget. Here's how it works:
It creates a
Scaffold
with anAppBar
at the top, displaying the title "REST API."The body of the
Scaffold
is aListView.builder
widget that generates a list of photo items using the data received from the constructor.For each photo item, it creates a
Card
with anImage
and additional details.The
GestureDetector
allows users to tap on a photo, triggering navigation to theDetailsPage
while passing the selectedPhotoModel
.
Creating a Flutter Details Page for Photo Display
In this page, we'll explore a Flutter DetailsPage
class that is responsible for displaying detailed information about a specific photo. This page will show the photo, its ID, title, and thumbnail URL. Let's break down the code :
import 'package:flutter/material.dart';
import 'package:rest_api/model/photomodel.dart';
class DetailsPage extends StatelessWidget {
final PhotoModel photoModel;
const DetailsPage({Key? key, required this.photoModel}) : super(key: key);
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: const Text('Details'),
),
body: Padding(
padding: const EdgeInsets.all(8.0),
child: Card(
elevation: 10,
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Center(
child: Card(
margin: EdgeInsets.only(top: 30),
elevation: 10,
child: Image.network(
photoModel.url.toString(),
width: 300,
height: 200,
fit: BoxFit.cover,
),
),
),
SizedBox(height: 16),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
photoModel.id.toString(),
style: TextStyle(fontSize: 21, fontWeight: FontWeight.bold),
),
),
SizedBox(height: 10),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
photoModel.title.toString(),
style: TextStyle(fontSize: 18,fontWeight: FontWeight.bold),
),
),
SizedBox(height: 10),
Padding(
padding: const EdgeInsets.all(8.0),
child: Text(
photoModel.thumbnailUrl.toString(),
style: TextStyle(fontSize: 16,fontWeight: FontWeight.w400),
),
),
],
),
),
),
);
}
}
Here's a breakdown of the DetailsPage
code:
Imports: The code includes necessary imports for Flutter (
flutter/material.dart
) andPhotoModel
for displaying the details of the selected photo.Constructor: The
DetailsPage
class has a constructor that takes aPhotoModel
object as a parameter. This allows you to pass the specific photo's data to the details page when navigating to it.build
Method: This method defines the UI structure of theDetailsPage
widget. Here's how it works:It creates a
Scaffold
with anAppBar
that displays the title "Details."Inside the
Scaffold
, there's aCard
widget with elevated content for displaying the photo details.The photo is displayed in the center using an
Image.network
widget. The image URL is obtained from thephotoModel
.Below the photo, there are three pieces of information displayed: ID, title, and thumbnail URL. Each piece of information is placed in a
Text
widget with different text styles.The
SizedBox
widgets add vertical spacing between the elements for better readability.
Setting up a Flutter Project with REST API Integration
In this article, we will guide you through setting up a Flutter project named "rest_api" for integrating REST API data fetching and displaying it in your app. We'll also include dependencies for HTTP requests, local database storage, and splash screen functionality.
Here's your
pubspec.yaml
file with the necessary configurations and dependencies:name: rest_api description: A new Flutter project. publish_to: 'none' version: 1.0.0+1 environment: sdk: '>=3.0.5 <4.0.0' dependencies: flutter: sdk: flutter cupertino_icons: ^1.0.2 http: ^1.1.0 # For making HTTP requests to your API sqflite: ^2.3.0 # For local database storage path: ^1.8.3 # For handling file paths splash_screen_view: ^3.0.0 # For implementing a splash screen dev_dependencies: flutter_test: sdk: flutter flutter_lints: ^2.0.0 # Optional linting rules for your Flutter project flutter: uses-material-design: true