fix(plc): 统一添加超时兜底机制避免调用无响应挂起
- 在 PlcHelper 中新增 withTimeout 方法,包装所有 SDK 动作和查询接口 - 通过定时器实现超时检测,超时触发 onError 回调,避免永久挂起 - 确保 onSuccess 和 onError 回调至多调用一次,防止重复回调 - 为所有 PLC 操作接口分别设置合理超时时长(3s - 10s不等) - 修改所有内部调用使用 withTimeout 包装,保证异常场景的错误回调触发 - 更新生产环境基础 URL 地址为平台测试环境地址
This commit is contained in:
@@ -40,7 +40,7 @@ object GlobalData {
|
|||||||
*/
|
*/
|
||||||
const val LOCAL_BASE_URL: String = "http://192.168.10.101:24801"
|
const val LOCAL_BASE_URL: String = "http://192.168.10.101:24801"
|
||||||
const val TEST_BASE_URL: String = "https://dev.yixiong-tech.com:8081"
|
const val TEST_BASE_URL: String = "https://dev.yixiong-tech.com:8081"
|
||||||
const val PROD_BASE_URL: String = "https://api.dm.yixiong-tech.com:8443"
|
const val PROD_BASE_URL: String = "https://platform-api.uat.shuziweidao.com"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设备id
|
* 设备id
|
||||||
|
|||||||
@@ -4,10 +4,16 @@ import android.content.Context
|
|||||||
import android.os.Handler
|
import android.os.Handler
|
||||||
import android.os.Looper
|
import android.os.Looper
|
||||||
import com.megoai.plc_aar.SDK
|
import com.megoai.plc_aar.SDK
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* PLC 操作工具类(单例)
|
* PLC 操作工具类(单例)
|
||||||
* 封装 SDK 所有接口,统一回调到主线程
|
* 封装 SDK 所有接口,统一回调到主线程
|
||||||
|
*
|
||||||
|
* 注意:底层 PLC SDK(Flutter MethodChannel 封装)的 Listener 只有 onMessage 一个回调,
|
||||||
|
* Flutter 侧 error()/notImplemented() 均为空实现,串口异常或引擎未就绪时不会回调。
|
||||||
|
* 因此本类对所有动作类、查询类接口统一加超时兜底:超时未响应则触发 onError,
|
||||||
|
* 保证上层回调链不会因“无响应”而永久挂起。
|
||||||
*/
|
*/
|
||||||
class PlcHelper private constructor(context: Context) {
|
class PlcHelper private constructor(context: Context) {
|
||||||
|
|
||||||
@@ -28,6 +34,59 @@ class PlcHelper private constructor(context: Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==================== 超时兜底封装 ====================
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 包装 SDK 动作/查询调用:超时未响应时主动触发 onError。
|
||||||
|
*
|
||||||
|
* 背景:底层 SDK 的 Listener 仅在 Flutter 侧 success() 时回调 onMessage,
|
||||||
|
* error()/notImplemented() 为空实现,串口异常时 Android 侧收不到任何回调,
|
||||||
|
* 会导致上层回调永久挂起。本方法用定时器兜底,并保证 onSuccess/onError 至多触发一次。
|
||||||
|
*
|
||||||
|
* @param timeoutMs 超时时长(毫秒)
|
||||||
|
* @param callback 上层回调(统一在主线程回调)
|
||||||
|
* @param action 实际发起 SDK 调用的逻辑,参数为经过防重入包装的“安全回调”,
|
||||||
|
* 内部所有成功/失败出口都应通过该回调触发
|
||||||
|
* @param <T> 回调结果类型
|
||||||
|
*/
|
||||||
|
private inline fun <T> withTimeout(
|
||||||
|
timeoutMs: Long,
|
||||||
|
callback: PlcCallback<T>,
|
||||||
|
crossinline action: (safeCallback: PlcCallback<T>) -> Unit
|
||||||
|
) {
|
||||||
|
// 标记回调是否已触发,保证 onSuccess/onError 至多执行一次
|
||||||
|
val fired = AtomicBoolean(false)
|
||||||
|
// 包装后的安全回调,所有出口都经过它,避免重复回调
|
||||||
|
val safeCallback = object : PlcCallback<T> {
|
||||||
|
override fun onSuccess(result: T) {
|
||||||
|
if (fired.compareAndSet(false, true)) callback.onSuccess(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(message: String) {
|
||||||
|
if (fired.compareAndSet(false, true)) callback.onError(message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 超时定时器:到期未收到 SDK 回调则触发 onError
|
||||||
|
val timeoutRunnable = Runnable {
|
||||||
|
safeCallback.onError("PLC 操作超时(${timeoutMs}ms)未响应")
|
||||||
|
}
|
||||||
|
mainHandler.postDelayed(timeoutRunnable, timeoutMs)
|
||||||
|
// 发起实际 SDK 调用,所有成功/失败都通过 safeCallback 回调
|
||||||
|
action(object : PlcCallback<T> {
|
||||||
|
override fun onSuccess(result: T) {
|
||||||
|
// 成功后取消超时定时器
|
||||||
|
mainHandler.removeCallbacks(timeoutRunnable)
|
||||||
|
safeCallback.onSuccess(result)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun onError(message: String) {
|
||||||
|
// 失败同样取消超时定时器
|
||||||
|
mainHandler.removeCallbacks(timeoutRunnable)
|
||||||
|
safeCallback.onError(message)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
// ==================== 连接与模式 ====================
|
// ==================== 连接与模式 ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -43,8 +102,10 @@ class PlcHelper private constructor(context: Context) {
|
|||||||
* 打开自动模式(应用启动时调用一次)
|
* 打开自动模式(应用启动时调用一次)
|
||||||
*/
|
*/
|
||||||
fun openAutoMode(callback: PlcCallback<String>) {
|
fun openAutoMode(callback: PlcCallback<String>) {
|
||||||
sdk.actionOpenAutoMode { result ->
|
withTimeout(5000, callback) { safe ->
|
||||||
mainHandler.post { callback.onSuccess(result.toString()) }
|
sdk.actionOpenAutoMode { result ->
|
||||||
|
mainHandler.post { safe.onSuccess(result.toString()) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -52,76 +113,90 @@ class PlcHelper private constructor(context: Context) {
|
|||||||
* 故障复位(出现 alarmCode 或补盘完成后调用)
|
* 故障复位(出现 alarmCode 或补盘完成后调用)
|
||||||
*/
|
*/
|
||||||
fun alarmReset(callback: PlcCallback<String>) {
|
fun alarmReset(callback: PlcCallback<String>) {
|
||||||
sdk.actionAlarmReset { result ->
|
withTimeout(5000, callback) { safe ->
|
||||||
mainHandler.post { callback.onSuccess(result.toString()) }
|
sdk.actionAlarmReset { result ->
|
||||||
|
mainHandler.post { safe.onSuccess(result.toString()) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 出盘操作 ====================
|
// ==================== 出盘操作 ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 出盘
|
* 出盘(机械动作,超时 10s)
|
||||||
*/
|
*/
|
||||||
fun outPlate(callback: PlcCallback<String>) {
|
fun outPlate(callback: PlcCallback<String>) {
|
||||||
sdk.actionOutPlate { result ->
|
withTimeout(10000, callback) { safe ->
|
||||||
mainHandler.post { callback.onSuccess(result.toString()) }
|
sdk.actionOutPlate { result ->
|
||||||
|
mainHandler.post { safe.onSuccess(result.toString()) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 平台控制 ====================
|
// ==================== 平台控制 ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 平台下降(开始补盘)
|
* 平台下降(开始补盘,超时 8s)
|
||||||
*/
|
*/
|
||||||
fun platformDown(callback: PlcCallback<String>) {
|
fun platformDown(callback: PlcCallback<String>) {
|
||||||
sdk.actionPlatformDown { result ->
|
withTimeout(8000, callback) { safe ->
|
||||||
mainHandler.post { callback.onSuccess(result.toString()) }
|
sdk.actionPlatformDown { result ->
|
||||||
|
mainHandler.post { safe.onSuccess(result.toString()) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 平台上升(补盘完成)
|
* 平台上升(补盘完成,超时 8s)
|
||||||
*/
|
*/
|
||||||
fun platformUp(callback: PlcCallback<String>) {
|
fun platformUp(callback: PlcCallback<String>) {
|
||||||
sdk.actionPlatformDownStop { result ->
|
withTimeout(8000, callback) { safe ->
|
||||||
mainHandler.post { callback.onSuccess(result.toString()) }
|
sdk.actionPlatformDownStop { result ->
|
||||||
|
mainHandler.post { safe.onSuccess(result.toString()) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 补盘完成返回营业(自动模式 + 故障复位)
|
* 补盘完成返回营业(自动模式 + 故障复位,超时 5s)
|
||||||
*/
|
*/
|
||||||
fun backToBusiness(callback: PlcCallback<String>) {
|
fun backToBusiness(callback: PlcCallback<String>) {
|
||||||
sdk.actionOpenAutoModeAndActionAlarmReset { result ->
|
withTimeout(5000, callback) { safe ->
|
||||||
mainHandler.post { callback.onSuccess(result.toString()) }
|
sdk.actionOpenAutoModeAndActionAlarmReset { result ->
|
||||||
|
mainHandler.post { safe.onSuccess(result.toString()) }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 状态查询 ====================
|
// ==================== 状态查询 ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 PLC 状态(解析为 PlcStatus 对象)
|
* 获取 PLC 状态(解析为 PlcStatus 对象,超时 3s)
|
||||||
*/
|
*/
|
||||||
fun getStatus(callback: PlcCallback<PlcStatus>) {
|
fun getStatus(callback: PlcCallback<PlcStatus>) {
|
||||||
sdk.getPlcStatus { json ->
|
withTimeout(3000, callback) { safe ->
|
||||||
mainHandler.post {
|
sdk.getPlcStatus { json ->
|
||||||
if (json != null) {
|
mainHandler.post {
|
||||||
callback.onSuccess(PlcStatus.Companion.fromJson(json.toString()))
|
if (json != null) {
|
||||||
} else {
|
safe.onSuccess(PlcStatus.Companion.fromJson(json.toString()))
|
||||||
callback.onError("获取状态失败")
|
} else {
|
||||||
|
safe.onError("获取状态失败")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取 PLC 状态(原始 JSON 字符串)
|
* 获取 PLC 状态(原始 JSON 字符串,超时 3s)
|
||||||
*/
|
*/
|
||||||
fun getStatusJson(callback: PlcCallback<String>) {
|
fun getStatusJson(callback: PlcCallback<String>) {
|
||||||
sdk.getPlcStatus { json ->
|
withTimeout(3000, callback) { safe ->
|
||||||
mainHandler.post {
|
sdk.getPlcStatus { json ->
|
||||||
if (json != null) callback.onSuccess(json.toString())
|
mainHandler.post {
|
||||||
else callback.onError("获取状态失败")
|
if (json != null) safe.onSuccess(json.toString())
|
||||||
|
else safe.onError("获取状态失败")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -129,16 +204,18 @@ class PlcHelper private constructor(context: Context) {
|
|||||||
// ==================== 参数设置 ====================
|
// ==================== 参数设置 ====================
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 设置 PLC 参数
|
* 设置 PLC 参数(超时 3s)
|
||||||
* @param paramType 参数类型(如 "18FD" 表示主电机运行最长时间)
|
* @param paramType 参数类型(如 "18FD" 表示主电机运行最长时间)
|
||||||
* @param paramValue 参数值(int,单位 0.1s)
|
* @param paramValue 参数值(int,单位 0.1s)
|
||||||
*/
|
*/
|
||||||
fun setParams(paramType: String, paramValue: Int, callback: PlcCallback<String>) {
|
fun setParams(paramType: String, paramValue: Int, callback: PlcCallback<String>) {
|
||||||
sdk.setPLCParams(
|
withTimeout(3000, callback) { safe ->
|
||||||
{ result -> mainHandler.post { callback.onSuccess(result.toString()) } },
|
sdk.setPLCParams(
|
||||||
paramType,
|
{ result -> mainHandler.post { safe.onSuccess(result.toString()) } },
|
||||||
paramValue
|
paramType,
|
||||||
)
|
paramValue
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// ==================== 生命周期 ====================
|
// ==================== 生命周期 ====================
|
||||||
|
|||||||
Reference in New Issue
Block a user