当前位置: 首页 > article >正文

flutter getx路由管理、状态管理、路由守卫中间件、永久储存get_storage

一个简单的路由跳转、状态管理

目录

lib/
├── main.dart
├── routes/index.dart         // 路由表
├── middlewares/auth_middleware.dart  // 登录守卫
├── pages/
│   ├── home_page.dart
│   ├── login_page.dart
│   └── profile_page.dart
└── controllers/auth_controller.dart  // 登录状态管理

✅ 1. 登录状态控制器(AuthController)

// controllers/auth_controller.dart
import 'package:get/get.dart';class AuthController extends GetxController {var isLoggedIn = false.obs;void login() => isLoggedIn.value = true;void logout() => isLoggedIn.value = false;
}

✅ 2. 路由守卫中间件(AuthMiddleware)

// middlewares/auth_middleware.dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../controllers/auth_controller.dart';class AuthMiddleware extends GetMiddleware {@overrideRouteSettings? redirect(String? route) {final auth = Get.find<AuthController>();if (!auth.isLoggedIn.value) {return const RouteSettings(name: '/login');}return null; // 正常访问}@overrideint? priority = 0; // 优先级
}

✅ 3. 页面:Home、Login、Profile

// pages/home_page.dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../controllers/auth_controller.dart';class HomePage extends StatelessWidget {@overrideWidget build(BuildContext context) {final auth = Get.find<AuthController>();return Scaffold(appBar: AppBar(title: const Text("首页")),body: Center(child: Column(mainAxisAlignment: MainAxisAlignment.center,children: [const Text("欢迎来到首页"),ElevatedButton(onPressed: () => Get.toNamed("/profile"),child: const Text("进入个人中心"),),ElevatedButton(onPressed: auth.logout,child: const Text("退出登录"),)],),),);}
}
// pages/login_page.dart
import 'package:flutter/material.dart';
import 'package:get/get.dart';
import '../controllers/auth_controller.dart';class LoginPage extends StatelessWidget {@overrideWidget build(BuildContext context) {final auth = Get.find<AuthController>();return Scaffold(appBar: AppBar(title: const Text("登录页")),body: Center(child: ElevatedButton(onPressed: () {auth.login();Get.offAllNamed('/home');},child: const Text("点击登录"),),),);}
}
// pages/profile_page.dart
import 'package:flutter/material.dart';class ProfilePage extends StatelessWidget {@overrideWidget build(BuildContext context) {return const Scaffold(body: Center(child: Text("这是个人中心")),);}
}

✅ 4. 路由定义(routes.dart)

// routes.dart
import 'package:get/get.dart';
import 'middlewares/auth_middleware.dart';
import 'pages/home_page.dart';
import 'pages/login_page.dart';
import 'pages/profile_page.dart';final List<GetPage> appRoutes = [GetPage(name: '/login', page: () => LoginPage()),// 添加守卫的页面GetPage(name: '/home',page: () => HomePage(),middlewares: [AuthMiddleware()],),GetPage(name: '/profile',page: () => ProfilePage(),middlewares: [AuthMiddleware()],),
];

✅ 5. 启动文件(main.dart)

import 'package:flutter/material.dart';
import 'package:get/get.dart';
import 'controllers/auth_controller.dart';
import 'routes.dart';void main() {Get.put(AuthController()); // 注册控制器runApp(MyApp());
}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return GetMaterialApp(debugShowCheckedModeBanner: false,initialRoute: '/home',getPages: appRoutes,);}
}

重点

  • Get.find(); 在 main() 中全局注册
  • 路由配置中需要添加 中间件

Getx 路由套转配置方式

方法功能示例
Get.to()普通跳转Get.to(DetailPage())
Get.toNamed()跳转到命名路由Get.toNamed('/home')
Get.back()返回上一页Get.back()
Get.off()替换当前页面Get.off(DetailPage())
Get.offNamed()替换并跳转命名路由Get.offNamed('/home')
Get.offAll()清除所有页面,跳转Get.offAll(MainPage())
Get.offAllNamed()清除所有页面并跳转命名路由Get.offAllNamed('/login')
Get.toNamed('/page', arguments: data)传递数据接收:Get.arguments
Get.toNamed('/page/123')传递路径参数Get.parameters['id']

✅ 二、路由配置:GetMaterialApp + getPages

void main() {runApp(MyApp());
}class MyApp extends StatelessWidget {@overrideWidget build(BuildContext context) {return GetMaterialApp(title: 'GetX Demo',initialRoute: '/',getPages: [GetPage(name: '/', page: () => HomePage()),GetPage(name: '/login', page: () => LoginPage()),GetPage(name: '/detail/:id', page: () => DetailPage()),],);}
}

✅ 三、参数传递方式

传递 arguments(类似 Vue 的 query)
// 跳转时传
Get.toNamed('/detail', arguments: {'title': 'GetX 超棒!'});// 接收
final args = Get.arguments;
2️⃣ 传递 path 参数(像 /user/123)
// 定义路由
GetPage(name: '/user/:id', page: () => UserPage());// 跳转
Get.toNamed('/user/123');// 接收参数
final id = Get.parameters['id']; // 获取的是 '123'

✅ 四、嵌套路由(子路由)

GetPage(name: '/parent',page: () => ParentPage(),children: [GetPage(name: '/child', page: () => ChildPage()),],
);

跳转方式:

Get.toNamed('/parent/child');

✅ 五、使用中间件(路由守卫)

GetPage(name: '/home',page: () => HomePage(),middlewares: [AuthMiddleware()],
);
  • 中间件例子:
class AuthMiddleware extends GetMiddleware {@overrideRouteSettings? redirect(String? route) {final auth = Get.find<AuthController>();if (!auth.isLoggedIn.value) {return const RouteSettings(name: '/login');}return null;}
}

✅ 六、转场动画

GetPage(name: '/about',page: () => AboutPage(),transition: Transition.rightToLeft,transitionDuration: const Duration(milliseconds: 300),
);

七、导航栏方式(bottomNavigation + 路由)

  • 你也可以结合 GetX + IndexedStack 做底部导航 + 路由组合(需要时我可以提供完整例子)。

✅ 跳转方法速查表:

方法作用
Get.to(Widget)Push 一个页面
Get.off(Widget)替换当前页面
Get.offAll(Widget)清除所有页面
Get.toNamed('/path')跳转命名路由
Get.offNamed('/path')替换当前为命名路由
Get.offAllNamed('/path')全部清除并跳转命名
Get.back()返回上一级
Get.arguments获取传递的对象
Get.parameters获取 path 中的参数(如 /user/:id)

Getx 状态管理

  1. 响应式变量基础(Rx 类型)
  2. GetX 控制器结构与绑定
  3. UI 自动刷新更新机制
  4. GetStorage 实现永久存储
  5. 增删改查完整示例
  6. 完整状态管理架构建议

响应式变量基础(Rx 类型)

类型示例使用说明
RxIntRxInt count = 0.obs;obs 创建响应式变量
RxStringvar name = ''.obs;自动追踪变化
RxListRxList items = [].obs;响应式数组
RxMapRxMap map = {}.obs;响应式字典
Rx<T>Rx<User> user = User().obs;自定义类型
改变值方式:
count.value++;
name.value = '新名称';
items.add('新项');
map['key'] = 'value';

2️⃣ GetX 控制器结构与绑定

class CounterController extends GetxController {var count = 0.obs;void increment() {count.value++;}
}
  • 注册控制器:
// main.dart
Get.put(CounterController());
// 页面中局部绑定
final counter = Get.put(CounterController());

3️⃣ UI 自动刷新更新机制

  1. 方法 1:Obx(最推荐)
Obx(() => Text('计数:${counter.count}'));
  1. 方法 2:GetX Widget
GetX<CounterController>(builder: (controller) => Text('${controller.count}'),
);
  1. 方法 3:GetBuilder(非响应式,只手动更新)
GetBuilder<CounterController>(builder: (_) => Text('${_.count}'),
);

GetBuilder 适用于不频繁更新的组件,需要手动调用 update()。

4️⃣ GetStorage 实现永久存储(本地缓存)

步骤 1:引入依赖
dependencies:get_storage: ^2.1.1
步骤 2:初始化
void main() async {await GetStorage.init(); // 必须 await 初始化runApp(MyApp());
}
步骤 3:使用
final box = GetStorage();// 存
box.write('isLoggedIn', true);// 取
bool isLoggedIn = box.read('isLoggedIn') ?? false;// 删
box.remove('isLoggedIn');

5️⃣ 增删改查完整示例(以 RxList 为例)

class TodoController extends GetxController {var todos = <String>[].obs;void add(String task) => todos.add(task);void updateAt(int index, String newValue) => todos[index] = newValue;void delete(int index) => todos.removeAt(index);void clear() => todos.clear();
}
  • 使用:
final todoController = Get.find<TodoController>();Obx(() => ListView.builder(itemCount: todoController.todos.length,itemBuilder: (_, i) => ListTile(title: Text(todoController.todos[i]),trailing: IconButton(icon: Icon(Icons.delete),onPressed: () => todoController.delete(i),),),
));

6️⃣ 完整状态管理架构建议

功能推荐方式
页面数据共享使用 Get.put() 全局注册控制器
子页面控制器Get.lazyPut() 按需注册
多状态切换用多个 RxBool / RxEnum 控制
页面重构控制器 + Obx 封装成组件
状态持久化GetStorage 存取数据
中间件判断状态Get.find<Controller>().xxx.value

✅ 示例:登录状态持久化控制器(完整)

class AuthController extends GetxController {final storage = GetStorage();var isLoggedIn = false.obs;@overridevoid onInit() {super.onInit();isLoggedIn.value = storage.read('isLoggedIn') ?? false;}void login() {isLoggedIn.value = true;storage.write('isLoggedIn', true);}void logout() {isLoggedIn.value = false;storage.remove('isLoggedIn');}
}

状态管理,永久存储 get_storage

  1. 在pubspec.yaml文件中添加库的依赖:
dependencies:get_storage: ^2.1.1
  1. 然后运行:
flutter pub get

✅ 2. 初始化(必须)

  • 在 main.dart 的入口函数中初始化:
import 'package:get_storage/get_storage.dart';void main() async {await GetStorage.init(); // 初始化存储runApp(MyApp());
}

注意:await GetStorage.init() 是异步方法,必须在 runApp() 前执行。

✅ 3. 基本用法

final box = GetStorage(); // 实例化,默认使用 'GetStorage' 区域// 写入数据
box.write('username', '张三');// 读取数据
String name = box.read('username') ?? '游客';// 删除某个值
box.remove('username');// 清空所有数据
box.erase();// 判断是否存在
bool exists = box.hasData('username');

✅ 4. 支持的类型

支持所有基本类型和 Map、List:

类型示例
String'张三'
int100
double3.14
booltrue
List<String>['a', 'b']
Map<String, dynamic>{'id': 1, 'name': 'Tom'}

✅ 5. 多区域存储(类似命名空间)

  • 你可以为不同模块使用不同的存储文件(如用户模块/缓存模块)
await GetStorage.init('user');
final userBox = GetStorage('user');userBox.write('token', '123456');
print(userBox.read('token'));

✅ 6. 实时监听值变化(响应式)

box.listen(() {print('本地数据发生变化');
});
  • 你也可以监听某个 key:
box.listenKey('isDark', (value) {print('主题设置变为:$value');
});

✅ 7. 搭配 GetX Controller 使用(推荐)

  • 例如保存登录状态:
class AuthController extends GetxController {final storage = GetStorage();var isLoggedIn = false.obs;@overridevoid onInit() {super.onInit();isLoggedIn.value = storage.read('isLoggedIn') ?? false;}void login() {isLoggedIn.value = true;storage.write('isLoggedIn', true);}void logout() {isLoggedIn.value = false;storage.remove('isLoggedIn');}
}

✅ 8. 存储对象(推荐使用 JSON)

final user = {'id': 1,'name': 'Alice','roles': ['admin', 'editor'],
};box.write('user', user);// 读取
Map userData = box.read('user');

如需存储自定义对象,请使用 toJson / fromJson 显式转换。

✅ 9. 总结速查表

操作方法示例
初始化await GetStorage.init()在 main() 中
实例化GetStorage()可传命名空间
写入.write('key', value)
读取.read('key')
删除.remove('key')
清空.erase()
判断.hasData('key')
监听所有.listen((){})
监听某项.listenKey('key', callback)

使用场景推荐

场景建议用法
登录状态bool 持久化 + 控制器绑定
用户信息Map 存储 JSON
主题模式bool 监听并更新 UI
App 首次启动设置 isFirstRun 标志位
临时缓存数据write + remove 清理机制

相关文章:

flutter getx路由管理、状态管理、路由守卫中间件、永久储存get_storage

一个简单的路由跳转、状态管理 目录 lib/ ├── main.dart ├── routes/index.dart // 路由表 ├── middlewares/auth_middleware.dart // 登录守卫 ├── pages/ │ ├── home_page.dart │ ├── login_page.dart │ └── profile_page.dart └─…...

贪心算法之跳跃游戏问题

问题背景 本文背景是leetcode的一道经典题目&#xff1a;跳跃游戏&#xff0c;描述如下&#xff1a; 给定一个非负整数数组 nums&#xff0c;初始位于数组的第一个位置&#xff08;下标0&#xff09;。数组中的每个元素表示在该位置可以跳跃的最大长度。判断是否能够到达最后…...

Dockers Compose常用指令介绍

Dockers Compose常用指令 1、常用指令介绍 1.1、version 指令 顶级一级指令&#xff0c;指定 compose 指定文件格式版本 version: "3.8" services: 不同版本支持的功能不同。常用版本有 ‘2’, ‘3’, ‘3.8’ 等。 1.2、services 指令 顶级一级指令&#xff0…...

YOLOv11 性能评估与横向对比

在第二章中&#xff0c;我们深入剖析了 YOLOv11 的核心技术&#xff0c;从骨干网络、颈部网络到头部&#xff0c;再到损失函数、数据增强和训练策略的创新&#xff0c;揭示了其高性能背后的奥秘。然而&#xff0c;理论的强大最终需要通过严谨的实验数据来验证。本章将详细阐述 …...

kafka在线增加分区副本数

1、问题来源 线上有一个物联网项目依赖kafka集群中指定主题消费&#xff0c;前些天kafka集群中的某一台机器出现了故障&#xff0c;导致kafka这个主题的数据一直无法消费&#xff0c;经查发现为了保证消息的顺序性此主题仅设置了一个分区&#xff0c;但是副本也仅有一个&#…...

Unity 如何使用Timeline预览、播放特效

在使用unity制作和拟合动画时&#xff0c;我们常用到Timeline&#xff0c;前后拖动滑轨&#xff0c;预览动画正放倒放非常方便。如果我们想对特效也进行这个操作&#xff0c;可以使用下文的步骤。 至此&#xff0c;恭喜你又解锁了一个新的技巧。如果我的分享对你有帮助&#xf…...

GIM发布新版本了 (附rust CLI制作brew bottle流程)

GIM 发布新版本了&#xff01;现在1.3.0版本可用了 可以通过brew upgrade git-intelligence-message升级。 初次安装需要先执行 brew tap davelet/gim GIM 是一个根据git仓库内文件变更自动生成git提交消息的命令行工具&#xff0c;参考前文《GIM: 根据代码变更自动生成git提交…...

GitHub 趋势日报 (2025年05月21日)

本日报由 TrendForge 系统生成 https://trendforge.devlive.org/ &#x1f310; 本日报中的项目描述已自动翻译为中文 &#x1f4c8; 今日整体趋势 Top 10 排名项目名称项目描述今日获星总星数语言1microsoft/WSLLinux的Windows子系统⭐ 1731⭐ 25184C2virattt/ai-hedge-fundA…...

MySQL篇-其他面试题

MySQL事务 问题&#xff1a;事务是什么&#xff1f;ACID问题 事务是一组操作的集合&#xff0c;它是一个不可分割的工作单位&#xff0c;事务会把所有的操作作为一个整体一起向系统提交或撤销操作请求&#xff0c;即这些操作要么同时成功&#xff0c;要么同时失败。 1、事务…...

iOS 蓝牙开发中的 BT 与 BLE

在 iOS 开发者的语境里&#xff0c;大家把 BT 和 BLE 当成两种不同的蓝牙技术在谈——它们来自同一个 Bluetooth 规范&#xff0c;但面向的场景、协议栈乃至 Apple 提供的 API 都截然不同。 缩写全称 / 技术名称规范层叫法iOS 支持现状典型用途BTBluetooth Classic&#xff08…...

Git的工作区,暂存区,本地仓库

Git 核心概念解析 1. 工作区&#xff08;Working Directory&#xff09; - 日常操作代码的目录&#xff0c;包含项目所有文件和子目录 - 开发者直接编辑和修改文件的位置 - 实际可见的项目文件结构 2. 暂存区&#xff08;Staging Area&#xff09; - 临时保存修改记录的缓冲区…...

鸿蒙Flutter实战:21-混合开发详解-1-概述

引言 在前面的系列文章中&#xff0c;我们从搭建开发环境开始&#xff0c;讲到如何使用、集成第三方插件&#xff0c;如何将现有项目进行鸿蒙化改造&#xff0c;以及上架审核等内容&#xff1b;还以高德地图的 HarmonyOS SDK 的使用为例&#xff0c; 讲解了如何将高德地图集成…...

MySQL错误1419(HY000)解决方案:SUPER权限缺失与二进制日志启用冲突的3种处理方式

一、错误背景与原因分析 错误描述 在执行存储过程、函数或触发器时,MySQL可能抛出以下错误: ERROR 1419 (HY000): You do not have the SUPER privilege and binary logging is enabled (you *might* want to use the less safe log_bin_trust_function_creators variable)…...

[架构之美]从PDMan一键生成数据库设计文档:Word导出全流程详解(二十)

[架构之美]从PDMan一键生成数据库设计文档&#xff1a;Word导出全流程详解&#xff08;二十&#xff09; 一、痛点 你是否经历过这些场景&#xff1f; 数据库字段频繁变更&#xff0c;维护文档耗时费力用Excel维护表结构&#xff0c;版本混乱难以追溯手动编写Word文档&#…...

大量程粗糙度轮廓仪适用于哪些材质和表面?

大量程粗糙度轮廓仪是一种能够在广泛的测量范围内对工件表面进行粗糙度分析的精密仪器。它通常采用接触式或非接触式传感器&#xff0c;通过对工件表面的扫描&#xff0c;捕捉表面微观的起伏和波动&#xff0c;从而获取粗糙度数据。该仪器不仅能测量微小的表面细节&#xff0c;…...

linux 查看java的安装路径

一、验证Java安装状态 java -version正常安装会显示版本信息&#xff1a; openjdk version "1.8.0_65" OpenJDK Runtime Environment (build 1.8.0_65-b17) OpenJDK 64-Bit Server VM (build 25.65-b01, mixed mode)二、检查环境变量配置 若已配置JAVA_HOME&#…...

C 语言程序终止的艺术:理解 return main 与 exit() 函数

各类资料学习合集下载地址: ​​​​https://pan.quark.cn/s/472bbdfcd014​​ 每个 C 语言程序都有其起点——​​main​​ 函数。同样,每个程序也都有其终点,即程序执行完毕并退出。在 C 语言中,主要有两种方式可以优雅或立即地终止整个程序的执行,并将一个状态码传递给…...

数据实时同步:inotify + rsync 实现数据实时同步

1 数据实时同步 在生产环境中&#xff0c;某些场景下&#xff0c;要将数据或文件进行实时同步&#xff0c;保证数据更新后其它节点能立即获得最新的数据。 数据同步的两种方式 PULL&#xff1a;拉&#xff0c;使用定时任务的方式配合同步命令或脚本等&#xff0c;从指定服务…...

LeetCode 404.左叶子之和的迭代求解:栈结构与父节点定位的深度解析

一、题目解析&#xff1a;左叶子的定义与问题本质 题目描述 LeetCode 404. 左叶子之和要求计算二叉树中所有左叶子节点的值之和。左叶子的定义是&#xff1a;如果一个节点是其父节点的左子节点&#xff0c;并且它本身没有左右子节点&#xff0c;则称为左叶子。 关键要点 左…...

Unity-编辑器扩展

之前我们关于Unity的讨论都是针对于Unity底层的内容或者是代码层面的东西&#xff0c;这一次我们来专门研究Unity可视化的编辑器&#xff0c;在已有的基础上做一些扩展。 基本功能 首先我们来认识三个文件夹&#xff1a; Editor&#xff0c;Gizmos&#xff0c;Editor Defaul…...

【自用-python】生成准心居中exe程序,防止云电脑操作时候鼠标偏移

封装exe&#xff1a;&#xff1a; altf12是终端---我理解的就是最初始python的运行台 看where python&#xff08;Windows的&#xff09;看是在那个路径 再确保之前pip安装了pyinstaller 然后pyinstaller --onefile --noconsole --name 输出exe的文件名称 你的py文件名称.py…...

Lucide:一款精美的开源矢量图标库,前端图标新选择

名人说&#xff1a;博观而约取&#xff0c;厚积而薄发。——苏轼《稼说送张琥》 创作者&#xff1a;Code_流苏(CSDN)&#xff08;一个喜欢古诗词和编程的Coder&#x1f60a;&#xff09; 目录 一、前言&#xff1a;为何选择 Lucide&#xff1f;二、Lucide 是什么&#xff1f;1.…...

在Rocky Linux 8.10上安装Nginx

如果没有配置操作系统安装源&#xff0c;并且不连接网络&#xff0c;先配置安装源。 sudo dnf install nginx sudo systemctl enable nginx sudo systemctl start nginx systemctl status nginx curl http://ip [rootrocky810 work]# sudo dnf install nginx Last metadata …...

Mac如何允许安装任何来源软件?

打开系统偏好设置-安全性与隐私&#xff0c;点击右下角的解锁按钮&#xff0c;选择允许从任何来源。 如果没有这一选项&#xff0c;请到打开终端&#xff0c;输入命令行&#xff1a;sudo spctl --master-disable, 输入命令后回车&#xff0c;输入电脑的开机密码后回车。 返回“…...

YOLO学习笔记 | YOLO11对象检测,实例分割,姿态评估的TensorRT部署c++

以下是YOLOv11在TensorRT上部署的步骤指南,涵盖对象检测、实例分割和姿态评估: 1. 模型导出与转换 1.1 导出ONNX模型 import torch from models.experimental import attempt_loadmodel = attempt_load(yolov11s.pt, fuse=True) model.eval...

2025最新版Visual Studio Code for Mac安装使用指南

2025最新版Visual Studio Code for Mac安装使用指南 Installation and Application Guide to The Latest Version of Visual Studio Code in 2025 By JacksonML 1. 什么是Visual Studio Code&#xff1f; Visual Studio Code&#xff0c;通常被称为 VS Code&#xff0c;是由…...

机器学习第二十三讲:CNN → 用放大镜局部观察图片特征层层传递

机器学习第二十三讲&#xff1a;CNN → 用放大镜局部观察图片特征层层传递 资料取自《零基础学机器学习》。 查看总目录&#xff1a;学习大纲 关于DeepSeek本地部署指南可以看下我之前写的文章&#xff1a;DeepSeek R1本地与线上满血版部署&#xff1a;超详细手把手指南 CNN详…...

【嵙大o】C++作业合集

​ 参考&#xff1a; C swap&#xff08;交换&#xff09;函数 指针/引用/C自带-CSDN博客 Problem IDTitleCPP指针CPP引用1107 Problem A编写函数&#xff1a;Swap (I) (Append Code)1158 Problem B整型数据的输出格式1163 Problem C时间&#xff1a;24小时制转12小时制1205…...

《算法笔记》11.8小节——动态规划专题->总结 问题 B: 拦截导弹

题目描述 某国为了防御敌国的导弹袭击&#xff0c;开发出一种导弹拦截系统。但是这种导弹拦截系统有一个缺陷&#xff1a;虽然它的第一发炮弹能够到达任意的高度&#xff0c;但是以后每一发炮弹都不能高于前一发的高度。某天&#xff0c;雷达捕捉到敌国的导弹来袭&#xff0c;…...

Flink 核心概念解析:流数据、并行处理与状态

一、流数据&#xff08;Stream Data&#xff09; 1. 有界流&#xff08;Bounded Stream&#xff09; 定义&#xff1a;有明确起始和结束时间的数据集合&#xff0c;数据量固定&#xff0c;处理逻辑通常是一次性计算所有数据。 典型场景&#xff1a; 历史交易数据统计&#xf…...