概述

错误处理和异常管理是应用开发的重要方面,它直接影响应用的稳定性和用户体验。在视力保护提醒应用中,我们采用了完整的错误处理机制来确保应用的稳定运行。本文将详细讲解如何进行错误处理和异常管理,包括异常捕获、错误提示、日志记录、恢复机制等功能。

错误处理的核心方面

错误处理主要包含以下方面:

  1. 异常捕获 - 捕获和处理异常
  2. 错误提示 - 向用户显示错误信息
  3. 日志记录 - 记录错误日志用于调试
  4. 恢复机制 - 从错误中恢复

这些方面结合在一起,为应用提供了一个完整的错误处理解决方案。

项目依赖配置

在pubspec.yaml中,我们已经配置了所需的依赖:

dependencies:
  flutter:
    sdk: flutter
  get: ^4.6.5

get库提供了snackbar功能用于显示错误提示。这个依赖是为了支持鸿蒙系统的Flutter开发。

基础异常捕获

使用try-catch捕获异常。

Future<void> loadData() async {
  try {
    final data = await _fetchDataFromServer();
    setState(() {
      _data = data;
    });
  } catch (e) {
    print('加载数据失败: $e');
    Get.snackbar(
      '错误',
      '加载数据失败,请重试',
      snackPosition: SnackPosition.BOTTOM,
      backgroundColor: Colors.red,
      colorText: Colors.white,
    );
  }
}

使用try-catch可以捕获异常并进行处理。在catch块中,我们可以记录错误并向用户显示错误提示。

异常分类处理

根据异常类型进行不同的处理。

Future<void> loadData() async {
  try {
    final data = await _fetchDataFromServer();
    setState(() {
      _data = data;
    });
  } on SocketException {
    Get.snackbar(
      '网络错误',
      '网络连接失败,请检查网络设置',
      snackPosition: SnackPosition.BOTTOM,
      backgroundColor: Colors.red,
      colorText: Colors.white,
    );
  } on TimeoutException {
    Get.snackbar(
      '超时错误',
      '请求超时,请重试',
      snackPosition: SnackPosition.BOTTOM,
      backgroundColor: Colors.orange,

根据异常类型进行不同的处理,可以提供更准确的错误提示。这种分类处理方式能够帮助用户更好地理解错误原因。SocketException表示网络连接问题,TimeoutException表示请求超时。通过捕获不同的异常类型,我们可以为用户显示相应的错误信息和建议。这样可以提高应用的用户体验,让用户知道具体发生了什么问题。

      colorText: Colors.white,
    );
  } catch (e) {
    Get.snackbar(
      '未知错误',
      '发生未知错误,请重试',
      snackPosition: SnackPosition.BOTTOM,
      backgroundColor: Colors.red,
      colorText: Colors.white,
    );
  }
}

根据异常类型进行不同的处理,可以提供更准确的错误提示。

自定义异常

创建自定义异常类。

class AppException implements Exception {
  final String message;
  final String? code;

  AppException({
    required this.message,
    this.code,
  });

  
  String toString() => 'AppException: $message (code: $code)';
}

class NetworkException extends AppException {
  NetworkException({String? message})
      : super(
          message: message ?? '网络连接失败',
          code: 'NETWORK_ERROR',
        );
}

自定义异常类提供了更清晰的错误信息和错误代码。通过继承AppException基类,我们可以创建特定的异常类型,如NetworkException、DataException等。每个异常类都有自己的错误代码和默认错误信息。这样可以在应用中统一处理异常,提供一致的错误处理体验。自定义异常还可以包含更多的上下文信息,帮助开发者快速定位问题。

class DataException extends AppException {
  DataException({String? message})
      : super(
          message: message ?? '数据加载失败',
          code: 'DATA_ERROR',
        );
}

// 使用自定义异常
Future<void> loadData() async {
  try {
    if (!await _checkNetworkConnection()) {
      throw NetworkException();
    }
    final data = await _fetchDataFromServer();
    if (data == null) {
      throw DataException();
    }
    setState(() {
      _data = data;
    });
  } on AppException catch (e) {
    Get.snackbar(
      '错误',
      e.message,
      snackPosition: SnackPosition.BOTTOM,
      backgroundColor: Colors.red,
      colorText: Colors.white,
    );
  }
}

自定义异常可以提供更清晰的错误信息和错误代码。

日志记录

记录错误日志用于调试。

class Logger {
  static void log(String message) {
    print('[LOG] $message');
  }

  static void error(String message, [Object? error, StackTrace? stackTrace]) {
    print('[ERROR] $message');
    if (error != null) {
      print('[ERROR] Error: $error');
    }
    if (stackTrace != null) {
      print('[ERROR] StackTrace: $stackTrace');
    }
  }

  static void warning(String message) {
    print('[WARNING] $message');
  }
}

记录详细的错误日志可以帮助开发者快速定位问题。Logger类提供了三个静态方法:log用于记录普通日志,error用于记录错误信息和堆栈跟踪,warning用于记录警告信息。通过在关键位置添加日志记录,我们可以追踪应用的执行流程。当出现问题时,这些日志可以提供宝贵的调试信息。在生产环境中,可以将日志上传到服务器进行分析。

// 使用日志记录
Future<void> loadData() async {
  try {
    Logger.log('开始加载数据');
    final data = await _fetchDataFromServer();
    Logger.log('数据加载成功');
    setState(() {
      _data = data;
    });
  } catch (e, stackTrace) {
    Logger.error('数据加载失败', e, stackTrace);
    Get.snackbar(
      '错误',
      '加载数据失败,请重试',
      snackPosition: SnackPosition.BOTTOM,
      backgroundColor: Colors.red,
      colorText: Colors.white,
    );
  }
}

记录详细的错误日志可以帮助开发者快速定位问题。

错误恢复机制

实现错误恢复机制。

class DataManager {
  static const int maxRetries = 3;

  static Future<T> retryOperation<T>(
    Future<T> Function() operation, {
    int maxRetries = maxRetries,
    Duration delay = const Duration(seconds: 1),
  }) async {
    int retryCount = 0;
    while (retryCount < maxRetries) {
      try {
        return await operation();
      } catch (e) {
        retryCount++;
        if (retryCount >= maxRetries) {
          rethrow;
        }
        Logger.warning('操作失败,${delay.inSeconds}秒后重试 (${retryCount}/${maxRetries})');
        await Future.delayed(delay);
      }

实现重试机制可以在网络不稳定时自动重试操作。retryOperation方法接收一个异步操作函数,并在失败时自动重试。通过maxRetries参数控制最大重试次数,通过delay参数控制重试间隔。这种机制特别适合处理网络请求,因为网络可能会因为临时问题而失败。通过自动重试,我们可以提高应用的可靠性,减少用户遇到的错误。

    }
    throw Exception('操作失败');
  }
}

// 使用重试机制
Future<void> loadData() async {
  try {
    final data = await DataManager.retryOperation(
      () => _fetchDataFromServer(),
      maxRetries: 3,
      delay: const Duration(seconds: 2),
    );
    setState(() {
      _data = data;
    });
  } catch (e) {
    Logger.error('数据加载失败', e);
    Get.snackbar(
      '错误',
      '加载数据失败,请重试',
      snackPosition: SnackPosition.BOTTOM,
      backgroundColor: Colors.red,
      colorText: Colors.white,
    );
  }
}

实现重试机制可以在网络不稳定时自动重试操作。

全局错误处理

在应用级别处理全局错误。

void main() {
  FlutterError.onError = (FlutterErrorDetails details) {
    Logger.error('Flutter错误', details.exception, details.stack);
  };

  runZonedGuarded(
    () {
      runApp(const MyApp());
    },
    (error, stackTrace) {
      Logger.error('应用错误', error, stackTrace);
    },
  );
}

使用FlutterError.onError和runZonedGuarded可以捕获全局错误。

表单验证错误处理

处理表单验证错误。

Widget _buildFormField(String label, TextEditingController controller) {
  return Column(
    crossAxisAlignment: CrossAxisAlignment.start,
    children: [
      Text(
        label,
        style: TextStyle(fontSize: 12.sp, fontWeight: FontWeight.w500),
      ),
      SizedBox(height: 4.h),
      TextField(
        controller: controller,
        decoration: InputDecoration(
          border: OutlineInputBorder(
            borderRadius: BorderRadius.circular(8.r),
          ),
          contentPadding: EdgeInsets.symmetric(horizontal: 12.w, vertical: 10.h),
          errorText: _validateField(controller.text),
        ),
      ),
    ],

在表单字段中显示验证错误信息。这个方法构建了一个带有验证功能的文本输入字段。当用户输入内容时,_validateField方法会检查输入的有效性。如果验证失败,errorText会显示相应的错误信息。这种实时验证方式可以帮助用户及时发现和纠正输入错误。通过在TextField的decoration中设置errorText,Flutter会自动以红色显示错误信息。

  );
}

String? _validateField(String value) {
  if (value.isEmpty) {
    return '此字段不能为空';
  }
  if (value.length < 2) {
    return '至少需要2个字符';
  }
  return null;
}

在表单字段中显示验证错误信息。

网络错误处理

处理网络相关的错误。

Future<T> _handleNetworkRequest<T>(Future<T> Function() request) async {
  try {
    return await request();
  } on SocketException {
    throw NetworkException(message: '网络连接失败');
  } on TimeoutException {
    throw NetworkException(message: '请求超时');
  } on HttpException catch (e) {
    throw NetworkException(message: '服务器错误: ${e.message}');
  } catch (e) {
    throw NetworkException(message: '网络请求失败');
  }
}

统一处理网络相关的错误。

屏幕适配处理

在整个应用中,我们使用flutter_screenutil库来处理屏幕适配。.w表示宽度单位,.h表示高度单位,.sp表示字体大小单位。这样可以确保在不同屏幕尺寸的设备上,UI元素的大小和间距都能正确显示。

例如,EdgeInsets.all(16.w)表示四周都有16个宽度单位的边距。TextStyle(fontSize: 16.sp)表示字体大小为16个字体单位。

总结

错误处理和异常管理是应用开发的重要方面。通过使用try-catch、自定义异常、日志记录、重试机制等方法,我们可以构建一个稳定可靠的应用。通过全局错误处理,我们可以捕获和处理所有的错误。

在视力保护提醒应用中,我们采用了完整的错误处理机制来确保应用的稳定运行,提高用户体验。

欢迎加入开源鸿蒙跨平台社区:https://openharmonycrossplatform.csdn.net

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐