Implementing Lazy Loading in Flutter: The Ultimate Performance Hack

Sabin Poudel
3 min readMay 31, 2024

--

Lazy loading in software development refers to the process of deferring the initialization of an object until it is needed.

Have you ever wondered how the infinite scrolling of Facebook or YouTube works? That is thanks to lazy loading. As we continue to scroll, the content keeps loading. We cannot load all the items at once because what if the user never consumes that resource? Loading all items at once might be costly on both the server side and the client side. To avoid such problems, we can implement lazy loading.

Image Credit: blazingcoders.com

Let’s get started with implementing lazy loading by creating a Flutter project.

flutter create lazy_loading

Let’s add a dependency (optional) to get beautiful log message

flutter pub add logger

Start by creating a MaterialApp inside the main.dart file:

import 'package:flutter/material.dart';

void main() {
runApp(const MyApp());
}

class MyApp extends StatelessWidget {
const MyApp({super.key});

@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
theme: ThemeData(),
);
}
}

Now, create a home_page.dart file inside the lib folder.

First, initialize the initial data source like this (the data source can be api call):

 List<int> dataSource = List.generate(20, (index) => index);

Create an instance of ScrollController to keep track of scroll events:

ScrollController scrollController = ScrollController();

Add the listener to that scroll controller inside the initState() method:

@Override
void initState() {
scrollController.addListener(() {
if (scrollController.position.maxScrollExtent == scrollController.offset) {
// this means user has scrolled till the last item
Logger().i("Scrolled till last item");
addMore();
}
});
super.initState();
}

Now, use the ListView.builder() widget to consume that data source:

ListView.builder(
controller: scrollController,
itemCount: dataSource.length + 1,
itemBuilder: (context, index) {
if (index < dataSource.length) {
return ListTile(
title: Text("Item ${index + 1}"),
);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
),

The condition scrollController.position.maxScrollExtent == scrollController.offset is true only if the user has scrolled till the last item. If the user has scrolled till the last, add more data inside the data source. I have done that with a delay of 2 seconds in a method named addMore():

  void addMore() async {
await Future.delayed(const Duration(seconds: 3));
List<int> additionalDataSoure = List.generate(20, (index) => index);
dataSource.addAll(additionalDataSoure);
setState(() {});
}

Here’s the complete home_page.dart file:

import 'package:flutter/material.dart';
import 'package:logger/logger.dart';

class HomePage extends StatefulWidget {
const HomePage({super.key});

@override
State<HomePage> createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
List<int> dataSource = List.generate(20, (index) => index);
ScrollController scrollController = ScrollController();

void addMore() async {
await Future.delayed(const Duration(seconds: 3));
List<int> additionalDataSoure = List.generate(20, (index) => index);
dataSource.addAll(additionalDataSoure);
setState(() {});
}

@override
void initState() {
scrollController.addListener(() {
if (scrollController.position.maxScrollExtent ==
scrollController.offset) {
// this means user has scrolled till last item
Logger().i("Scrolled till last item"); // or can use debugPrint
addMore();
}
});
super.initState();
}

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
centerTitle: true,
title: const Text("Lazy Loading"),
),
body: ListView.builder(
controller: scrollController,
itemCount: dataSource.length + 1,
itemBuilder: (context, index) {
if (index < dataSource.length) {
return ListTile(
title: Text("Item ${index + 1}"),
);
} else {
return const Center(
child: CircularProgressIndicator(),
);
}
},
),
);
}
}

If you found this article helpful or insightful, give it a round of 👏

--

--