Skip to content

Instantly share code, notes, and snippets.

@slightfoot
Last active July 19, 2023 12:51
Show Gist options
  • Star 12 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save slightfoot/85d39f7c235119b724b6b1fa4afa0b41 to your computer and use it in GitHub Desktop.
Save slightfoot/85d39f7c235119b724b6b1fa4afa0b41 to your computer and use it in GitHub Desktop.
Defer initialization of your UI based on a background service - by Simon Lightfoot - 29/12/2020 - Null Safe!
import 'dart:math' show Random;
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart' show RendererBinding;
void main() {
runApp(MaterialApp(
home: Home(),
));
}
class MyService {
MyService._();
static MyService? _instance;
static MyService get instance => _instance!;
static Future<MyService> init() async {
if (_instance == null) {
await Future.delayed(const Duration(seconds: 1));
_instance = MyService._();
}
return _instance!;
}
bool isLoggedIn() {
return Random(DateTime.now().millisecondsSinceEpoch).nextBool();
}
}
@immutable
class Home extends StatelessWidget {
const Home({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return Material(
child: DeferInit(
create: () async {
await MyService.init();
if (MyService.instance.isLoggedIn()) {
return Center(child: Text('Not logged in'));
} else {
return Center(child: Text('Logged In'));
}
},
emptyWidget: Center(child: Text('No Data')),
),
);
}
}
typedef DeferInitCreate<T extends Widget?> = Future<T> Function();
@immutable
class DeferInit<T extends Widget?> extends StatefulWidget {
const DeferInit({
Key? key,
required this.create,
this.emptyWidget = const SizedBox.shrink(),
}) : super(key: key);
final DeferInitCreate<T> create;
final Widget emptyWidget;
@override
_DeferInitState<T> createState() => _DeferInitState<T>();
}
class _DeferInitState<T extends Widget?> extends State<DeferInit<T>> {
late Future<T> _future;
@override
void initState() {
super.initState();
RendererBinding.instance!.deferFirstFrame();
_future = widget.create().whenComplete(() {
RendererBinding.instance!.allowFirstFrame();
});
}
@override
Widget build(BuildContext context) {
return FutureBuilder(
future: _future,
builder: (BuildContext context, AsyncSnapshot<T> snapshot) {
if (snapshot.connectionState != ConnectionState.done) {
return const SizedBox.shrink();
} else if (snapshot.hasError) {
return ErrorWidget(snapshot.error!);
} else {
Widget? data = snapshot.data;
return data ?? widget.emptyWidget;
}
},
);
}
}
@godilite
Copy link

Really cool

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment