Skip to content

Instantly share code, notes, and snippets.

@evaisse
Last active August 14, 2025 17:31
Show Gist options
  • Select an option

  • Save evaisse/82b8bf8ad0280868e2bcd55d1065a735 to your computer and use it in GitHub Desktop.

Select an option

Save evaisse/82b8bf8ad0280868e2bcd55d1065a735 to your computer and use it in GitHub Desktop.
using provider to lazy load service disregarding the widget tree order.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class ServiceBuilder<T extends Service> {
final T Function(BuildContext context) create;
ServiceBuilder(this.create);
Provider<T> asProvider(ValueNotifier<BuildContext> scope) =>
Provider<T>(create: (_) => create(scope.value));
@override
bool operator ==(Object other) => other is ServiceBuilder<T>;
@override
int get hashCode => T.hashCode;
}
class ServicesFactory extends StatelessWidget {
final Set<ServiceBuilder> services;
final WidgetBuilder builder;
const ServicesFactory({
super.key,
required this.services,
required this.builder,
});
@override
Widget build(BuildContext context) {
final scope = ValueNotifier(context);
final providers = services.map((s) => s.asProvider(scope)).toSet().toList();
return MultiProvider(
providers: providers,
builder: (context, child) {
scope.value = context;
return builder(context);
},
);
}
}
class ServiceApp extends StatelessWidget {
const ServiceApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Service Management',
theme: ThemeData(),
home: ServicesFactory(
services: {
ServiceBuilder<LolaService>(MockedLolaService.fromContext),
ServiceBuilder<LolaService>(LolaService.fromContext),
ServiceBuilder<JohnService>(JohnService.fromContext),
ServiceBuilder<LaraService>(LaraService.fromContext),
},
builder: (context) => const ServiceDashboard(),
),
);
}
}
/// A dashboard widget to display and interact with the services.
class ServiceDashboard extends StatelessWidget {
const ServiceDashboard({super.key});
@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(title: const Text('Service Management')),
body: SingleChildScrollView(
padding: const EdgeInsets.all(16.0),
child: Center(
child: Column(
children: [
Text(context.read<LolaService>().status),
Text(context.read<JohnService>().status),
Text(context.read<LaraService>().status),
],
),
),
),
);
}
}
abstract class Service {
String get status;
Service.fromContext(BuildContext context);
}
class LolaService extends Service {
@override
String get status => 'Lola is observing quietly.';
LolaService.fromContext(super.context) : super.fromContext();
}
class MockedLolaService extends LolaService {
@override
String get status => 'I\'m mocked Lola.';
MockedLolaService.fromContext(super.context) : super.fromContext();
}
class JohnService extends Service {
@override
String get status => 'John is pondering, while lara ${lara.status}.';
final LaraService lara;
JohnService.fromContext(super.context)
: lara = context.read(),
super.fromContext();
}
class LaraService extends Service {
@override
String status = 'Lara is thoughtful.';
final JohnService Function() johnProvider;
LaraService.fromContext(super.context)
: johnProvider = (() => context.read<JohnService>()),
super.fromContext();
}
void main() {
runApp(const ServiceApp());
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment