Last updated:
0 purchases
lifecycle screen
LifecycleScreen #
LifecycleScreen is a Flutter library that simplifies state management and lifecycle handling in your applications. By providing a structured approach to managing screen lifecycle events, local state, and UI updates, LifecycleScreen allows you to build robust and maintainable Flutter applications with ease.
Features #
🔄 Lifecycle management: Handle screen lifecycle events such as push, pop, and app state changes.
🧠 State management: Manage local state with a clean, provider-based architecture.
⚡ Asynchronous operation handling: Built-in support for managing loading states and errors during async tasks.
🏗️ Separation of concerns: Clear separation between UI and business logic for better maintainability.
🎨 Customizable UI components: Easily override default loading and error UIs.
🔔 Subscription management: Easily manage stream subscriptions with built-in methods.
Installation #
Add LifecycleScreen to your pubspec.yaml file:
dependencies:
lifecycle_screen: latest_version
provider: ^6.0.0
copied to clipboard
Then run:
flutter pub get
copied to clipboard
Usage #
1. Create a Controller #
Create a controller that extends LifecycleScreenController:
import 'package:lifecycle_screen/lifecycle_screen.dart';
class CounterController extends LifecycleScreenController {
int _counter = 0;
int get counter => _counter;
void increment() {
// Use `asyncRun` to handle loading states and errors
asyncRun(() async {
await Future.delayed(const Duration(seconds: 1));
_counter++;
notifyListeners();
});
}
@override
void onInit() {
super.onInit();
print('Counter initialized');
}
@override
void onDidPush() {
super.onDidPush();
print('Counter screen pushed');
}
}
copied to clipboard
2. Create a Screen #
Create a screen that extends LifecycleScreen:
import 'package:flutter/material.dart';
import 'package:lifecycle_screen/lifecycle_screen.dart';
import 'package:provider/provider.dart';
class CounterScreen extends LifecycleScreen<CounterController> {
@override
CounterController createController() => CounterController();
@override
Widget buildView(BuildContext context, CounterController controller) {
final counter = context.select<CounterController, int>((controller) => controller.counter);
return Scaffold(
appBar: AppBar(title: const Text('Counter')),
body: Center(
child: Text(
'Count: $counter',
style: Theme.of(context).textTheme.headline4,
),
),
floatingActionButton: FloatingActionButton(
onPressed: controller.increment,
child: const Icon(Icons.add),
),
);
}
}
copied to clipboard
3. Use the Screen in Your App #
import 'package:flutter/material.dart';
import 'package:lifecycle_screen/lifecycle_screen.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
return MaterialApp(
title: 'LifecycleScreen Demo',
theme: ThemeData(primarySwatch: Colors.blue),
home: const CounterScreen(),
navigatorObservers: [LifecycleScreenController.basePageRouteObserver],
);
}
}
copied to clipboard
State Management with Provider #
LifecycleScreen uses the Provider package for state management. The library automatically sets up the necessary Provider infrastructure, allowing you to access your controller's state easily within your screen.
Accessing Controller State #
You can access your controller's state using context.read, context.watch, or context.select:
// Read a value once (doesn't listen for changes)
final controller = context.read<CounterController>();
// Watch for all changes in the controller
final counter = context.watch<CounterController>().counter;
// Select and listen to specific properties (recommended for optimal performance)
final counter = context.select<CounterController, int>((controller) => controller.counter);
copied to clipboard
Use context.select when you want to listen to specific properties for optimal performance.
Lifecycle Hooks #
LifecycleScreen provides several lifecycle hooks that you can override in your controller:
class MyController extends LifecycleScreenController {
@override
void onInit() {
super.onInit();
// Called when the controller is initialized
}
@override
void onDispose() {
super.onDispose();
// Called when the controller is disposed
}
@override
void onDidPush() {
super.onDidPush();
// Called when the screen is pushed onto the navigation stack
}
@override
void onDidPop() {
super.onDidPop();
// Called when the screen is popped from the navigation stack
}
@override
void onDidPushNext() {
super.onDidPushNext();
// Called when a new screen is pushed on top of this one
}
@override
void onDidPopNext() {
super.onDidPopNext();
// Called when the screen on top of this one is popped
}
@override
void onResumed() {
super.onResumed();
// Called when the app is resumed from the background
}
@override
void onInactive() {
super.onInactive();
// Called when the app becomes inactive
}
@override
void onPaused() {
super.onPaused();
// Called when the app is paused
}
@override
void onDetached() {
super.onDetached();
// Called when the app is detached
}
}
copied to clipboard
Customizing UI Components #
Custom Loading View #
Override the buildLoading method in your screen to provide a custom loading UI:
class MyScreen extends LifecycleScreen<MyController> {
@override
Widget buildLoading(BuildContext context, MyController controller) {
return const Center(
child: CircularProgressIndicator(),
);
}
}
copied to clipboard
Custom Error View #
Similarly, override the buildError method for a custom error UI:
class MyScreen extends LifecycleScreen<MyController> {
@override
Widget buildError(BuildContext context, MyController controller) {
return Center(
child: Text('Error: ${controller.errorMessage}'),
);
}
}
copied to clipboard
Subscription Management #
LifecycleScreen provides built-in methods to manage stream subscriptions, making it easier to handle and dispose of subscriptions properly.
Adding and Removing Subscriptions #
You can use the addSubscription method to add a subscription to be managed by the controller:
class MyController extends LifecycleScreenController {
void listenToSomeStream() {
final subscription = someStream.listen((data) {
// Handle data
});
addSubscription(subscription);
}
}
copied to clipboard
The controller will automatically cancel all added subscriptions when it's disposed, preventing memory leaks.
You can also manually cancel subscriptions using the cancelSubscription or cancelSubscriptionAll methods:
// Cancel a specific subscription
cancelSubscription(subscription);
// Cancel all subscriptions
cancelSubscriptionAll();
copied to clipboard
This feature helps in managing resources efficiently and prevents potential memory leaks from uncancelled subscriptions.
Best Practices #
Keep Controllers Focused: Each controller should manage the state for a single screen or a specific feature.
Use asyncRun for Async Operations: Always use the asyncRun method provided by LifecycleScreen for asynchronous operations to properly handle loading states and errors.
Leverage Lifecycle Hooks: Make use of the various lifecycle hooks to perform initialization, cleanup, and respond to navigation events.
Optimize Rebuilds: Use context.select instead of context.watch when you only need to listen to specific properties of your controller.
Contributing #
Contributions are welcome! Please feel free to submit a Pull Request.
License #
MIT
For personal and professional use. You cannot resell or redistribute these repositories in their original state.
There are no reviews.