1. Introduction
Flutter is a powerful and cross-platform mobile app development framework, it’s easy to learn and build a nice user interface. But, if you are an experienced c#/Java programmer (it’s me~ ha ha), maybe you will be a little uncomfortable, because Flutter is a reactive programming framework, reactive programming is a declarative programming paradigm that is based on the idea of asynchronous event processing and data streams.
So, if you want to update the UI in Flutter, you need to update the state to refresh the layout, the programming logic will be different with C# or Java, so luckily there are many state management frameworks to help do that, but these frameworks are not easy to understand and use except GetX
.
GetX
is a fast, stable, and light state management library in Flutter. There are so many State Management libraries in Flutter like MobX, BLoC, Redux, Provider, etc. GetX is also a powerful micro framework and using this, we can manage states, make routing, and can perform dependency injection.
2. Why Getx
GetX
is focused on performance and minimum consumption of resources. One of the key performance advantages of GetX
lies in its minimal overhead. By minimizing unnecessary re-renders and widget rebuilds, GetX
significantly reduces the computational burden on your application, resulting in faster rendering and improved overall performance.
In addition, GetX
leverages the power of efficient dependency injection. Its lightweight dependency injection mechanism enables the creation and management of dependencies without compromising performance. By efficiently managing dependencies, GetX
helps eliminate unnecessary object instantiations and ensures efficient memory utilization.
3. Base Usages
3.1 Installing
Add Get to your pubspec.yaml
:
dependencies:
get: 4.6.6
and import the lib in your dart file
import 'package:get/get.dart';
3.2 State Management
GetX is easy to use, for example, you can define a variable with .obs
to make it observable
var isEnabled = false.obs;
...
//change to enable
isEnabled.value = true;
and use Obx(() => )
in UI to monitor the changes
return Scaffold(
appBar: AppBar(
title: const Text('Test'),
centerTitle: true,
),
body: Stack(
children: [
Obx(
() => controller.isEnabled.value
? ListView(
children: <Widget>[
...
],
)
: const SizedBox.shrink(),
),
],
),
);
}
for the above example, if the isEnabled
value changed to true
, then will show the ListView
data, just so easy, right?
3.3 Route Management
Navigation is very important in an App, GetX can help you easy to manage it. For example:
//navigate to a next page
Get.to(NextPage());
//navigate to next page by name
Get.tonamed('/next');
//beck to previous page or close snackbar,dialogs...
Get.back();
//to go to the next page and no option to go back to the previous page (for use in SplashPage, login Page, etc.)
Get.off(NextPage());
//to go to the next screen and cancel all previous routes (useful in shopping carts, polls, and tests)
Get.offAll(NextPage());
Ok, you can find more detailed usages in the official project website, and I will show another tip what I am using 🙂
4. Other Usages
Most of the time, we just need to bind the dependencies in main.dart
when starting the app, but if you are using the bottomNavigationBar
, you also need to bind the dependence in the bottom navigation main page, for example the below structure
dashboard (bottomNavigationBar main page)
-- home
-- product1
-- product1_detail
-- product2
-- product1_detail
-- settings
so the bindings in dashboard
should be like below
class DashboardBinding extends Bindings {
@override
void dependencies() {
Get.lazyPut<DashboardController>(
() => DashboardController(),
);
Get.lazyPut<HomeController>(
() => HomeController(),
);
Get.lazyPut<Product1Controller>(
() => Product1Controller(),
);
Get.lazyPut<Product2Controller>(
() => Product2Controller(),
);
}
}
and when you want to navigate to the product1 detail
page from product1
, you need to add the binding before go
return InkWell(
onTap: () {
Get.lazyPut<Product1DetailController>(
() => Product1DetailController(),
);
Get.to(() => const Product1DetailPage());
},
4.2 Using service for the common functions
GetX Service useful to let you make some common functions, you can handle the same lifecycle (onInit()
, onReady()
, onClose()
) as controller, and you can get the service anywhere with Get.find()
. For example, create a local storage service for handle the SharedPreferences
functions
class LocalStorageService extends GetxService {
Future<T?> getValue<T>(
LocalStorageKeys key, [
T Function(Map<String, dynamic>)? fromJson,
]) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
switch (T) {
case int:
return prefs.getInt(key.name) as T?;
case double:
return prefs.getDouble(key.name) as T?;
case String:
return prefs.getString(key.name) as T?;
case bool:
return prefs.getBool(key.name) as T?;
default:
assert(fromJson != null, 'fromJson must be provided for Object values');
if (fromJson != null) {
final stringObject = prefs.getString(key.name);
if (stringObject == null) return null;
final jsonObject = jsonDecode(stringObject) as Map<String, dynamic>;
return fromJson(jsonObject);
}
}
return null;
}
void setValue<T>(LocalStorageKeys key, T value) async {
SharedPreferences prefs = await SharedPreferences.getInstance();
switch (T) {
case int:
prefs.setInt(key.name, value as int);
break;
case double:
prefs.setDouble(key.name, value as double);
break;
case String:
prefs.setString(key.name, value as String);
break;
case bool:
prefs.setBool(key.name, value as bool);
break;
default:
assert(
value is Map<String, dynamic>,
'value must be int, double, String, bool or Map<String, dynamic>',
);
final stringObject = jsonEncode(value);
prefs.setString(key.name, stringObject);
}
}
}
and init the service in main.dart
Get.put(LocalStorageService());
then you can use it anywhere (including in other services)
//get the service
var localStorage = Get.find<LocalStorageService>();
...
//save the value
localStorage.setValue<String>('currentLanguage', 'en');
//get the value
var currentLanguage =
await localStorage.getValue<String>('currentLanguage');
4.3 Using the dialog
GetX support to use the popup dialog, you can easily use the default dialog below
Get.defaultDialog(
title: 'Title',
titleStyle: const TextStyle(color: Colors.red),
middleText: 'Messages');
This is only the normal alert dialog, if you want to use a custom style, you can use the below
Get.dialog(
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 40),
child: Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(
Radius.circular(20),
),
),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Material(
child:
//your layout widgets
),
),
),
),
],
),
);
as you can see, you can put any widgets in Get.dialog()
, so this is not only a dialog but also a popup page 🙂
and you can create the dialog as a service, there is a complete custom dialog service below:
enum DialogType {
info,
success,
error,
warning,
}
class DialogService extends GetxService {
showAlert(
String title,
String message, {
DialogType dialogType = DialogType.info,
Function? callback,
}) {
IconData iconData = Icons.info;
Color iconColor = Colors.blueGrey;
if (dialogType == DialogType.error) {
iconData = Icons.error;
iconColor = Colors.red;
} else if (dialogType == DialogType.warning) {
iconData = Icons.warning;
iconColor = Colors.yellow;
} else if (dialogType == DialogType.success) {
iconData = Icons.done_rounded;
iconColor = Colors.green;
}
Get.dialog(
Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Padding(
padding: const EdgeInsets.symmetric(horizontal: 40),
child: Container(
decoration: const BoxDecoration(
color: Colors.white,
borderRadius: BorderRadius.all(
Radius.circular(20),
),
),
child: Padding(
padding: const EdgeInsets.all(20.0),
child: Material(
child: Column(
children: [
const SizedBox(height: 10),
Icon(
iconData,
color: iconColor,
size: 50,
),
const SizedBox(height: 10),
Text(
title,
style: const TextStyle(
fontSize: 24, fontWeight: FontWeight.bold),
textAlign: TextAlign.center,
),
const SizedBox(height: 20),
Text(
message,
style: const TextStyle(fontSize: 18),
textAlign: TextAlign.center,
),
const SizedBox(height: 50),
//Buttons
Row(
children: [
Expanded(
child: ElevatedButton(
style: ElevatedButton.styleFrom(
foregroundColor: const Color(0xFFFFFFFF),
backgroundColor: Colors.blue,
minimumSize: const Size(0, 45),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
),
onPressed: () {
callback != null ? callback() : null;
},
child: Text(
style: const TextStyle(fontSize: 18),
LabelKeys.ok.tr,
),
),
),
],
),
],
),
),
),
),
),
],
),
);
}
}
you can use it anywhere
final dialog = Get.find<DialogService>();
//show the normal alert
dialog.showAlert(
'Title',
'This is a normal info alert'
);
//show the error alert
dialog.showAlert(
'Error',
'This is an error alert',
dialogType: DialogType.error
);
5. Advanced Apis
There are also many advanced APIs that can be use, such like
// give the current args from currentScreen
Get.arguments
// give name of previous route
Get.previousRoute
// give the raw route to access for example, rawRoute.isFirst()
Get.rawRoute
// give access to Routing API from GetObserver
Get.routing
// check if snackbar is open
Get.isSnackbarOpen
// check if dialog is open
Get.isDialogOpen
// check if bottomsheet is open
Get.isBottomSheetOpen
//Check in what platform the app is running
GetPlatform.isAndroid
GetPlatform.isIOS
GetPlatform.isMacOS
GetPlatform.isWindows
GetPlatform.isLinux
GetPlatform.isFuchsia
//Check the device type
GetPlatform.isMobile
GetPlatform.isDesktop
//All platforms are supported independently in web!
//You can tell if you are running inside a browser
//on Windows, iOS, OSX, Android, etc.
GetPlatform.isWeb
// Equivalent to : MediaQuery.of(context).size.height,
// but immutable.
Get.height
Get.width
// Gives the current context of the Navigator.
Get.context
// Gives the context of the snackbar/dialog/bottomsheet in the foreground, anywhere in your code.
Get.contextOverlay
...
you can find more in here
6. Conclusion
GetX is powerful, it’s saved my many times, and it’s easy to understand, it also has a highly active and helpful community, you can find the solutions in their community if there are any problems, and you also can install the vs-code extension to help to build the GetX project. Please let me know if you have another opinion of GetX 🙂