组件封装
封装 flutter 组件
当出现两个 变量 同时决定页面展示时,使用同一个函数封装
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39
| var taskLs = [fakeTask, fakeSonTask, fakeSonSonTask, fakeSonTask2, fakeTask2]; TaskManifest? selectedManifest;
class TaskManager with ChangeNotifier { List<Task> getTaskLs() { return taskLs; }
bool createTaskOrUpdateManifest({Task? task, TaskManifest? manifest}) { if (manifest != null) { selectedManifest = manifest; notifyListeners(); } else if (task != null) { taskLs.add(task); notifyListeners(); } else { print("unknown"); return false; } return true; }
List<Task> getRootTaskLs() { print("---: $selectedManifest ${selectedManifest?.name}"); var ls = <Task>[];
for (final task in getTaskLs()) { if (task.manifestId == selectedManifest?.id) { if (task.isRoot == true) { ls.add(task); } } } getTaskLs().forEach((element) { print("el: $element");} ); return ls; } }
|
类型转换
cast
在Dart中,cast
函数是一个非常有用的工具,它允许将一个集合的元素类型转换为另一个类型。这在处理dynamic
类型或不同类型之间的转换时尤其有用,但需要谨慎使用以避免运行时错误。下面是使用cast
函数的一些最佳实践:
1. 明确知道元素类型时使用
只有当确定集合中的所有元素都可以安全地被转换为目标类型时,才使用cast
。这通常适用于从动态类型(如从数据库、外部数据源或第三方库中获取的数据)转换到具体类型时。
2. 避免不必要的类型转换
如果能通过设计来确保数据的类型安全,那么尽量避免使用cast
。比如,使用泛型集合来存储和传递具体类型的数据,这样可以让Dart的静态类型检查帮助捕获类型错误。
3. 处理cast
可能失败的情况
使用cast
时,如果集合中有任何元素不能被转换为目标类型,都会抛出运行时异常。因此,使用cast
时应该尽量确保转换的安全性,或者使用try-catch结构来处理可能的异常。
4. 优先使用类型安全的替代方案
在某些情况下,可以通过映射(.map()
)集合并手动转换每个元素来避免使用cast
。这样做的好处是可以在转换每个元素时提供一个回退方案,比如:
1 2
| var list = <dynamic>[1, 2, 3]; var intList = list.map((e) => e as int).toList();
|
这种方法比cast
更加类型安全,因为可以控制转换的过程,并且在转换失败时捕获异常。
5. 谨慎使用cast
改变集合的可变性
当对集合使用cast
时,返回的是原始集合的一个视图,这意味着原始集合和转换后的集合在底层是相同的数据。对任一集合的修改都会影响另一个,但如果集合的类型不兼容,这种修改可能会引起问题。
6. 在混合类型数据流中使用
在处理混合类型的数据流时(比如一个列表包含了不同类型的对象),cast
可以用来过滤出特定类型的对象集合,以便进行进一步处理。
1 2 3 4 5 6 7 8
| List<Task> getTaskLs() { if (taskBox != null) { return taskBox!.values.cast<Task>().toList(); } else { return []; } }
|
as 类型转换
在Dart语言中,as
关键字用于类型转换,将一个对象显式地转换为另一个类型。尽管这是一个强大的功能,但如果不当使用,可能会导致运行时错误。以下是使用as
进行类型转换的一些最佳实践:
1. 当确定转换是安全的时使用
只在确信对象可以被安全地转换为目标类型时使用as
。这通常是在通过某些方式(例如通过类型检查)已经验证了对象的类型后。
1 2 3
| if (object is TargetType) { final targetTypeObject = object as TargetType; }
|
2. 优先使用类型测试运算符is
在尝试将一个对象转换为特定类型之前,先使用is
运算符检查对象是否为目标类型。这可以避免在转换失败时抛出异常。
1 2 3
| if (object is TargetType) { }
|
3. 避免不必要的as
使用
如果Dart的类型推断能够正确识别对象的类型,就没有必要使用as
进行显式转换。过度使用as
可能会降低代码的可读性和维护性。
4. 在处理泛型时谨慎使用
当与泛型类型打交道时,特别是当类型参数在运行时可能变化时,使用as
进行类型转换需要格外小心。在这种情况下,确保转换是安全的,或者考虑使用更安全的替代方案。
5. 处理as
转换可能失败的情况
尽管通过is
检查类型可以避免大多数问题,但在某些情况下,转换可能仍然失败。使用as
时,考虑包含异常处理逻辑,特别是当处理外部数据或在对数据源不完全确定时。
1 2 3 4 5
| try { final targetTypeObject = object as TargetType; } catch (e) { }
|
6. 使用类型安全的集合操作
当从集合中获取元素时,如果确信集合中的所有元素都属于一个特定类型,使用as
进行转换可以使代码更简洁。但是,仍然推荐使用is
进行检查,或者使用泛型来保证类型安全。
7. 避免将as
用作隐藏逻辑错误的手段
错误地使用as
可能会隐藏潜在的逻辑错误,导致难以调试的运行时异常。在使用as
之前,仔细考虑是否有其他方式(如改进程序逻辑或使用更合适的类型)来解决问题。
结论
as
关键字是Dart中强大的类型转换工具,但应谨慎使用。始终确保转换的安全性,优先使用类型检查运算符is
,并在适当的地方处理可能的异常,以编写更安全、更健壯的Dart代码。
_TaskContainerState 状态延迟刷新问题
背景描述
TaskContainer
组件下的 _TaskContainerState build
定义为
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| Widget build(BuildContext context) { List<Widget> loadSonTaskContainerLs(Set set) { if (_isFolded || !_haveSon) { return [const SizedBox()]; } else { List<TaskContainer> ls = <TaskContainer>[]; for (final id in set) { ls.add(TaskContainer(indentTime: increaseIndentTime(widget.indentTime), task: taskDBRead.getTaskById(id))); } return ls; } }
return Consumer<TaskUpdateModel>( builder: (context, taskUpdateModel, child) { final set = taskUpdateModel.getSonTaskIdLsFromParentId(widget.task!.id);
_haveSon = set.isEmpty ? false : true; print("set: ${set.length} , haveson: $_haveSon, isFold: $_isFolded"); return Row( crossAxisAlignment: CrossAxisAlignment.start, children: [ Container( width: 48, child: _haveSon ? Container( margin: const EdgeInsets.all(12), child: IconButton( onPressed: () { setState(() { _isFolded = !_isFolded; }); }, icon: Icon( _isFolded ? Icons.arrow_drop_down_rounded : Icons.arrow_right_rounded, size: 24, ), )) : Container(), ), Expanded( child: Column( children: [ SingleTaskP(widget.indentTime, widget.task), if (!_isFolded && _haveSon) ...loadSonTaskContainerLs(set), ], ), ), ], ); } ); }
|