dart 重构/实现的最佳方法是从StatefulWidget内部加载到一个单独的类中

dzhpxtsq  于 2023-09-28  发布在  其他
关注(0)|答案(1)|浏览(107)

我有一个工作的“TestScreen”小部件,它可以获取并显示用户的位置坐标。当_isLoading为true时,它显示了一个加载轮,并且该状态变量在此StatefulWidget中声明的函数内控制。

  1. class TestScreen extends StatefulWidget {
  2. @override
  3. _TestScreenState createState() => _TestScreenState();
  4. }
  5. class _TestScreenState extends State<TestScreen> {
  6. bool _isLocationPermissionGranted = false;
  7. Position _currentPosition = const Position(
  8. latitude: 0,
  9. longitude: 0,
  10. accuracy: 0,
  11. altitude: 0,
  12. heading: 0,
  13. speed: 0,
  14. speedAccuracy: 0,
  15. timestamp: null);
  16. bool _isLoading = false;
  17. Future<void> _checkLocationPermission() async {
  18. setState(() {
  19. _isLoading = true;
  20. });
  21. final LocationPermission permission = await Geolocator.requestPermission();
  22. if (permission == LocationPermission.denied) {
  23. setState(() {
  24. _isLocationPermissionGranted = false;
  25. _isLoading = false;
  26. });
  27. } else if (permission == LocationPermission.always ||
  28. permission == LocationPermission.whileInUse) {
  29. setState(() {
  30. _isLocationPermissionGranted = true;
  31. });
  32. await _getCurrentLocation();
  33. setState(() {
  34. _isLoading = false;
  35. });
  36. }
  37. }
  38. Future<void> _getCurrentLocation() async {
  39. setState(() {
  40. _isLoading = true;
  41. });
  42. try {
  43. final Position position = await Geolocator.getCurrentPosition(
  44. desiredAccuracy: LocationAccuracy.high,
  45. );
  46. setState(() {
  47. _currentPosition = position;
  48. _isLoading = false;
  49. });
  50. } catch (e) {
  51. print("Error getting location: $e");
  52. setState(() {
  53. _isLoading = false;
  54. });
  55. }
  56. }
  57. @override
  58. Widget build(BuildContext context) {
  59. return Scaffold(
  60. appBar: AppBar(
  61. title: Text('Location Tracking'),
  62. ),
  63. body: Center(
  64. child: Column(
  65. mainAxisAlignment: MainAxisAlignment.center,
  66. crossAxisAlignment: CrossAxisAlignment.center,
  67. children: [
  68. Text(
  69. _isLocationPermissionGranted
  70. ? 'Location Permission Granted'
  71. : 'Location Permission Denied',
  72. ),
  73. SizedBox(height: 20),
  74. Text('Latitude: ${_currentPosition.latitude}'),
  75. Text('Longitude: ${_currentPosition.longitude}'),
  76. SizedBox(height: 20),
  77. ElevatedButton(
  78. onPressed: _isLoading ? null : _checkLocationPermission,
  79. child: Text('Request Location Permission'),
  80. ),
  81. _isLoading
  82. ? Padding(
  83. padding: EdgeInsets.all(20.0),
  84. child: CircularProgressIndicator(),
  85. )
  86. : SizedBox(),
  87. ],
  88. ),
  89. ),
  90. );
  91. }
  92. }

现在这工作得很好,但是我想把与位置相关的变量和函数放在一个单独的LocationService类中。然而,我不能再使用setState简单地更新_isLoading bool了。

TLDR:什么是重构此代码的行业标准方法,以便我可以为与LocationService相关的所有内容提供单独的类文件,并且仍然控制TestScreen小部件中的isLoading变量?

a6b3iqyw

a6b3iqyw1#

我尽了最大的努力来编写最小的代码。我认为最好将UI和服务分开。现在,它看起来更干净,更漂亮。
您可能会注意到,我为您在服务中编写了额外的几行代码。在checkLocationPermission()中,我尝试处理所有可能的结果。在getCurrentLocation()中,我试图增强和调整。
在UI的一部分,你可以看到我是如何管理加载的。我自己改进代码。现在,它完美地工作。
main.dart

  1. import "package:flutter/material.dart";
  2. import "package:myapp/location_service.dart";
  3. void main() {
  4. WidgetsFlutterBinding.ensureInitialized();
  5. runApp(const MyApp());
  6. }
  7. class MyApp extends StatelessWidget {
  8. const MyApp({super.key});
  9. @override
  10. Widget build(BuildContext context) {
  11. return MaterialApp(
  12. title: "Flutter Demo",
  13. theme: ThemeData(
  14. colorScheme: ColorScheme.fromSeed(seedColor: Colors.deepPurple),
  15. useMaterial3: true,
  16. ),
  17. home: const TestScreen(),
  18. debugShowCheckedModeBanner: false,
  19. );
  20. }
  21. }
  22. class TestScreen extends StatefulWidget {
  23. const TestScreen({super.key});
  24. @override
  25. State<TestScreen> createState() => _TestScreenState();
  26. }
  27. class _TestScreenState extends State<TestScreen> {
  28. LocationService instance = LocationService.instance;
  29. bool isLoading = false;
  30. @override
  31. Widget build(BuildContext context) {
  32. return Scaffold(
  33. appBar: AppBar(
  34. title: const Text("Location Tracking"),
  35. ),
  36. body: Center(
  37. child: isLoading
  38. ? const CircularProgressIndicator()
  39. : Column(
  40. mainAxisAlignment: MainAxisAlignment.center,
  41. crossAxisAlignment: CrossAxisAlignment.start,
  42. children: <Widget>[
  43. Text(
  44. instance.isLocationPermissionGranted
  45. ? "Location Permission: Granted"
  46. : "Location Permission: Denied",
  47. ),
  48. const SizedBox(height: 20),
  49. Text("Latitude: ${instance.currentPosition.latitude}"),
  50. const SizedBox(height: 20),
  51. Text("Longitude: ${instance.currentPosition.longitude}"),
  52. const SizedBox(height: 20),
  53. ElevatedButton(
  54. onPressed: isLoading
  55. ? null
  56. : () async {
  57. isLoading = true;
  58. setState(() {});
  59. await instance.checkLocationPermission();
  60. isLoading = false;
  61. setState(() {});
  62. },
  63. child: const Text("Request Location Permission"),
  64. ),
  65. ],
  66. ),
  67. ),
  68. );
  69. }
  70. }

location_service.dart

  1. import "dart:async";
  2. import "dart:developer";
  3. import "package:geolocator/geolocator.dart";
  4. class LocationService {
  5. LocationService._();
  6. static final LocationService instance = LocationService._();
  7. bool isLocationPermissionGranted = false;
  8. Position currentPosition = const Position(
  9. longitude: 0.0,
  10. latitude: 0.0,
  11. timestamp: null,
  12. accuracy: 0.0,
  13. altitude: 0.0,
  14. heading: 0.0,
  15. speed: 0.0,
  16. speedAccuracy: 0.0,
  17. floor: 0,
  18. isMocked: true,
  19. );
  20. Future<void> checkLocationPermission() async {
  21. final LocationPermission permission = await Geolocator.requestPermission();
  22. switch (permission) {
  23. case LocationPermission.denied:
  24. break;
  25. case LocationPermission.deniedForever:
  26. break;
  27. case LocationPermission.whileInUse:
  28. isLocationPermissionGranted = true;
  29. await getCurrentLocation();
  30. break;
  31. case LocationPermission.always:
  32. isLocationPermissionGranted = true;
  33. await getCurrentLocation();
  34. break;
  35. case LocationPermission.unableToDetermine:
  36. break;
  37. }
  38. return Future<void>.value();
  39. }
  40. Future<void> getCurrentLocation() async {
  41. try {
  42. currentPosition = await Geolocator.getCurrentPosition();
  43. log("LocationService : Success : ${currentPosition.toJson()}");
  44. } on TimeoutException catch (e) {
  45. log("LocationService : Failure : ${e.message}");
  46. }
  47. return Future<void>.value();
  48. }
  49. }
展开查看全部

相关问题