Flutter中GetConnect偶现null响应(Android10居多)的原因及解决
问题
使用GetX框架的getConnect调用REST接口并验证响应时,偶现响应为null的情况(大多发生在Android 10设备上)。原本预期每次请求都能得到SUCCESS或FAIL结果,现在出现了null响应,想知道这是GetX包问题、Android版本问题还是其他原因,以及对应的修复方法。
相关代码实现
class ApiServices with DataStorageMixin { final Logger log = Logger(); static GetConnect? _instance; ApiServices._() { if (_instance == null) { _instance = GetConnect(timeout: const Duration(seconds: 10)); _instance!.httpClient.addRequestModifier<dynamic>((request) { log.i("Request method: ${request.method}\nUrl: ${request.url}"); log.i("Request header: ${request.headers}"); return request; }); _instance!.httpClient.addResponseModifier((request, response) { log.i("Response is : ${response.status.code}\nBody: ${response.body}"); return response; }); } } factory ApiServices.instance() => ApiServices._(); void validateResponse({ required Response? response, required Callback<Map<String, dynamic>> onSuccess, required Callback<Map<String, dynamic>> onRequestError, required Callback<Map<String, dynamic>> onServerError, }) { print('RB --- ${response!.body}'); if (response!.body != null) { Map<String, dynamic> responseBody = response.body; if (response.statusCode == 200 || response.statusCode == 201) { bool isSuccessResponse = responseBody['err'] == CODE_SUCCESS || responseBody['err'] == CODE_NEW_USER || responseBody['err'] == CODE_REGISTERED_USER || responseBody['err'] == CODE_CREATE; if (isSuccessResponse) { onSuccess(responseBody); } else { onRequestError(responseBody); } } else { onServerError(responseBody); } } } Future<void> apiPostCall({ String? bearerToken, required String endPoint, bool isFullEndPoint = false, Map<String, dynamic>? data, required Callback<Map<String, dynamic>> onSuccess, required Callback<Map<String, dynamic>> onRequestError, required Callback<Map<String, dynamic>> onServerError, }) async { // try { Response? response = await _instance!.post( isFullEndPoint ? endPoint : '$BASE_URL$endPoint', data, headers: await getHeader( url: endPoint, bearerToken: bearerToken, ), ); validateResponse( response: response, onSuccess: onSuccess, onRequestError: onRequestError, onServerError: onServerError, ); // } catch (e) { // onServerError({'error': e}); // } } }
问题现象
在validateResponse()方法中打印response.body时偶现null值,部分场景下接口返回无响应体的结果。
分析与解决方案
可能的原因
- 网络异常未捕获:当前代码注释了
try-catch块,请求过程中出现的连接中断、超时、DNS解析失败等异常不会被处理,直接返回状态异常的Response,其body为null。 - Android 10网络限制:Android 10对后台网络访问有更严格的限制,若应用在后台发起请求,可能被系统中断,导致未完整接收响应。
- 单例初始化竞态:现有单例实现存在线程安全隐患,多线程同时初始化时可能导致GetConnect实例状态异常,影响请求处理。
- 服务器端异常响应:部分场景下服务器返回无响应体的错误(如5xx状态码但无内容),Android 10的网络栈对这类响应的处理逻辑与其他版本存在差异。
修复步骤
恢复并完善异常捕获
重新启用apiPostCall中的异常捕获,处理请求过程中出现的所有异常:Future<void> apiPostCall({ String? bearerToken, required String endPoint, bool isFullEndPoint = false, Map<String, dynamic>? data, required Callback<Map<String, dynamic>> onSuccess, required Callback<Map<String, dynamic>> onRequestError, required Callback<Map<String, dynamic>> onServerError, }) async { try { Response? response = await _instance!.post( isFullEndPoint ? endPoint : '$BASE_URL$endPoint', data, headers: await getHeader( url: endPoint, bearerToken: bearerToken, ), ); validateResponse( response: response, onSuccess: onSuccess, onRequestError: onRequestError, onServerError: onServerError, ); } catch (e) { onServerError({'error': '请求异常: ${e.toString()}'}); } }完善空值处理逻辑
在validateResponse中增加对response和response.body为null的处理,避免空指针同时触发错误回调:void validateResponse({ required Response? response, required Callback<Map<String, dynamic>> onSuccess, required Callback<Map<String, dynamic>> onRequestError, required Callback<Map<String, dynamic>> onServerError, }) { print('RB --- ${response?.body}'); if (response == null) { onServerError({'error': '请求无响应'}); return; } if (response.body == null) { onServerError({'error': '响应体为空', 'statusCode': response.statusCode}); return; } Map<String, dynamic> responseBody = response.body; if (response.statusCode == 200 || response.statusCode == 201) { bool isSuccessResponse = responseBody['err'] == CODE_SUCCESS || responseBody['err'] == CODE_NEW_USER || responseBody['err'] == CODE_REGISTERED_USER || responseBody['err'] == CODE_CREATE; if (isSuccessResponse) { onSuccess(responseBody); } else { onRequestError(responseBody); } } else { onServerError(responseBody); } }优化单例实现
使用线程安全的单例写法,避免竞态条件:class ApiServices with DataStorageMixin { final Logger log = Logger(); static late final GetConnect _instance; static bool _initialized = false; ApiServices._() { _instance = GetConnect(timeout: const Duration(seconds: 10)); _instance.httpClient.addRequestModifier<dynamic>((request) { log.i("Request method: ${request.method}\nUrl: ${request.url}"); log.i("Request header: ${request.headers}"); return request; }); _instance.httpClient.addResponseModifier((request, response) { log.i("Response is : ${response.status.code}\nBody: ${response.body}"); return response; }); _initialized = true; } factory ApiServices.instance() { if (!_initialized) { ApiServices._(); } return ApiServices._(); } }适配Android 10网络策略
- 若接口使用HTTP而非HTTPS,在
AndroidManifest.xml的<application>标签中添加android:usesCleartextTraffic="true"。 - 若应用需要在后台发起请求,可申请
REQUEST_IGNORE_BATTERY_OPTIMIZATIONS权限,避免被系统限制网络。
- 若接口使用HTTP而非HTTPS,在
排查服务器响应格式
要求服务器保证所有响应(包括错误状态)都返回标准JSON格式的响应体,避免无内容的返回结果。
内容的提问来源于stack exchange,提问作者La Pyae
相关产品推荐
相关产品推荐

