There is a broad trend in Programming to approach the flow of the code with Lazy manner and the Flutter Framework is no exception. On one hand there are functional and reactive programming. The modern frameworks enforce wrapping logic in callbacks, listeners, events, messages or self-contained requests. The other side is a better User Experience that could be archived by loading and displaying the information to the user – gradually. Do not load more than what could be presented on the screen and always show the user what an app is doing.
Deferred Flutter Widgets
It seems that the modern frameworks do not care about the users’ Internet Bandwidth and Internet Applications are getting fatter and fatter. From one aspect – the whole industry is moving to 5G speeds and it will not be a problem. But, all the already sold devices will not be replaced and upgraded with a magic wand. Until then – having JavaScript Applications bigger than 2MB will be mind-blowing. It is bad from all perspectives to take more than 3s and on slower connections more than 10s to load a Web Page.
The solution applied in Flutter, also used in several other frameworks is code splitting:
The Flutter code that does the job is:
import 'package:online_platform/ui/PublicFigureOrOrganizationList.dart' deferred as PublicFigureOrOrganizationList;
….
FutureBuilder( future: PublicFigureOrOrganizationList.loadLibrary(), builder: (BuildContext context, snapshot) { return PublicFigureOrOrganizationList.PublicFigureOrOrganizationList(); })
The output of flutter build web will hopefully several, smaller JavaScript files, instead of one big.
Endless Scrolls
To load more items in the end of a list, you must wrap it in scroll-detecting widget. It is already implemented right here: https://pub.dev/packages/lazy_load_scrollview. The Code snippet I’m using:
LazyLoadScrollView( onEndOfPage: () => load(_items.length), child: ListView.builder( itemCount: _items.length, itemBuilder: (context, position) { return EpisodeListItem(episode: _items[position]); }, ))
Lazy Images
To lazy load images with Flutter, use the following package: https://pub.dev/packages/extended_image, and code:
import 'package:extended_image/extended_image.dart'; import 'package:flutter/cupertino.dart'; import 'package:flutter/material.dart'; class MyExtendedImageNetwork extends StatelessWidget { final String url; final double width; final double height; MyExtendedImageNetwork(this.url, {this.width=200, this.height=200}); @override Widget build(BuildContext context) { return ExtendedImage.network(url, width: width,height: height, cache: true, fit: BoxFit.scaleDown, loadStateChanged: (state) { switch (state.extendedImageLoadState) { case LoadState.loading: return CircularProgressIndicator(); case LoadState.failed: return Expanded(child: Image.asset("res/img/failed.png", fit: BoxFit.scaleDown)); case LoadState.completed: return ExtendedRawImage( image: state.extendedImageInfo?.image, width: width,height: height, ); } return Container(); } ); } }
The building process failed for me at the time of writing this article and it required change in Line 785:
_invertColors = MediaQuery.of(context, nullOk: true)?.invertColors ??
=>
_invertColors = MediaQuery.maybeOf(context)?.invertColors ??
You can see a Live Demo of all the points described in this article on the following address: https://programtom.com/Online_Platform/app/. The episodes get downloaded endlessly until the total amount is reached and all images on all screens are wrapped in the lazy loader. The code splitting is not optimal, but, for now – there are 3 more separate files. I may try to optimize it more in the future.