[FIX] 優化點選商品之出貨口狀態判斷與防重複點擊機制
1. 重構 checkSlotHaveProduct 方法以支援安全回呼與 3000ms 超時保護。 2. 修正 DevCheckSlotByVMC 串口讀取未重置 haveThings 導致的狀態殘留 Bug。 3. 加入 isCheckingSlot 點選鎖,防呆避免非同步檢查期間重複點擊商品。 4. 於異常 AlertDialog 手動與自動關閉路徑中,正確釋放點選鎖。 5. 更新中英日三語系取貨口有物文字為「取貨口有東西,請先取出」,並將 Dialog 字體放大至 24sp。 6. 將 checkSlot 的串口讀取延遲由 2000ms 降至 800ms,大幅加速點選商品的反應時間。
This commit is contained in:
parent
ab8b828aa2
commit
d13546b379
@ -4,9 +4,11 @@ import android.app.AlertDialog;
|
||||
import android.content.Context;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
@ -38,6 +40,7 @@ public class RecyclerVmcBuyListAdpter extends RecyclerView.Adapter<RecyclerVmcBu
|
||||
private final List<SlotStructure> SlotList;
|
||||
private FragmentAbstract fragment;
|
||||
private boolean haveThings, doorError;
|
||||
private volatile boolean isCheckingSlot = false; // 點擊鎖:防止非同步檢查期間重複點擊
|
||||
|
||||
public RecyclerVmcBuyListAdpter(FragmentAbstract fragment, List<SlotStructure> slotList) {
|
||||
this.logs = new Logs(this.getClass());
|
||||
@ -155,6 +158,9 @@ public class RecyclerVmcBuyListAdpter extends RecyclerView.Adapter<RecyclerVmcBu
|
||||
return;
|
||||
if (MyApp.getInstance().isShowDialog())
|
||||
return;
|
||||
// 防呆:正在檢查出貨口狀態時,不允許再次點擊
|
||||
if (isCheckingSlot)
|
||||
return;
|
||||
|
||||
// ✅ 即時庫存檢查(防止 MQTT 更新後 UI 尚未刷新的時間差)
|
||||
try {
|
||||
@ -171,19 +177,37 @@ public class RecyclerVmcBuyListAdpter extends RecyclerView.Adapter<RecyclerVmcBu
|
||||
// 查詢失敗時不阻擋,讓原流程繼續
|
||||
}
|
||||
|
||||
BuyStructure buyProduct = new BuyStructure(slotProduct.getField(), slotProduct.getSlot(),
|
||||
slotProduct.getProduct(), 1);
|
||||
MyApp.getInstance().getBuyList().add(buyProduct);
|
||||
fragment.getSrcHandlerMain().start(getClass().getSimpleName(),
|
||||
FontendActivity.Option.STOP_COUNTDOWN.getOption(), "stop countdown");
|
||||
new MemberCardPickupDialog(context, fragment.getSrcHandlerMain()).show();
|
||||
// 點選時即時檢查出貨口狀態(上鎖防止重複點擊)
|
||||
isCheckingSlot = true;
|
||||
checkSlotHaveProduct(slotProduct.getSlot(), 1, () -> {
|
||||
isCheckingSlot = false;
|
||||
BuyStructure buyProduct = new BuyStructure(slotProduct.getField(), slotProduct.getSlot(),
|
||||
slotProduct.getProduct(), 1);
|
||||
MyApp.getInstance().getBuyList().add(buyProduct);
|
||||
fragment.getSrcHandlerMain().start(getClass().getSimpleName(),
|
||||
FontendActivity.Option.STOP_COUNTDOWN.getOption(), "stop countdown");
|
||||
new MemberCardPickupDialog(context, fragment.getSrcHandlerMain()).show();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
public void checkSlotHaveProduct(int slotnum, int slotcount) {
|
||||
public void checkSlotHaveProduct(int slotnum, int slotcount, Runnable onSafe) {
|
||||
haveThings = false;
|
||||
doorError = false;
|
||||
|
||||
java.util.concurrent.atomic.AtomicBoolean isHandled = new java.util.concurrent.atomic.AtomicBoolean(false);
|
||||
|
||||
// 設定 3000ms 超時機制:如果機器沒反應,視為正常並繼續,避免程式卡住
|
||||
if (onSafe != null) {
|
||||
new Handler(Looper.getMainLooper()).postDelayed(() -> {
|
||||
if (!isHandled.getAndSet(true)) {
|
||||
logs.info("VMC Check Slot Timeout - Approving Safe (Timeout Safeguard)");
|
||||
onSafe.run();
|
||||
}
|
||||
}, 3000);
|
||||
}
|
||||
|
||||
logs.info("RecyclerDialogBuyListAdpter 111111111111111" + slotnum);
|
||||
// MyApp.getInstance().getDevXinYuanController().getReadBufferByNow(new
|
||||
// DevCheckSlotByVMC(handlerMain));
|
||||
logs.info("RecyclerDialogBuyListAdpter 222222222222222" + slotcount);
|
||||
MyApp.getInstance().getDevXinYuanController().addSendBuffer(
|
||||
MyApp.getInstance().getDevXinYuanController().getDevXinYuan().checkSlotPre(slotnum, slotcount));
|
||||
@ -191,13 +215,19 @@ public class RecyclerVmcBuyListAdpter extends RecyclerView.Adapter<RecyclerVmcBu
|
||||
MyApp.getInstance().getDevXinYuanController()
|
||||
.addSendBuffer(MyApp.getInstance().getDevXinYuanController().getDevXinYuan().checkSlot(slotnum));
|
||||
logs.info("RecyclerDialogBuyListAdpter 444444444444444");
|
||||
// 使用較短的延遲(800ms)來加速讀取回覆,預設 2000ms 對 checkSlot 查詢來說太慢
|
||||
MyApp.getInstance().getDevXinYuanController()
|
||||
.getReadBufferByNow(new DevCheckSlotByVMC(fragment.getSrcHandlerMain()));
|
||||
.getReadBufferByNow(new DevCheckSlotByVMC(fragment.getSrcHandlerMain(), onSafe, isHandled), 800);
|
||||
}
|
||||
|
||||
public class DevCheckSlotByVMC extends DevController.ReadBufferOnScheduler {
|
||||
public DevCheckSlotByVMC(HandlerMain handlerMain) {
|
||||
private Runnable onSafe;
|
||||
private java.util.concurrent.atomic.AtomicBoolean isHandled;
|
||||
|
||||
public DevCheckSlotByVMC(HandlerMain handlerMain, Runnable onSafe, java.util.concurrent.atomic.AtomicBoolean isHandled) {
|
||||
super(handlerMain);
|
||||
this.onSafe = onSafe;
|
||||
this.isHandled = isHandled;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -212,8 +242,9 @@ public class RecyclerVmcBuyListAdpter extends RecyclerView.Adapter<RecyclerVmcBu
|
||||
|
||||
@Override
|
||||
public void readBufferOnScheduler(DevController devController, HandlerMain handlerMain) {
|
||||
// 每次檢查前先重置門狀態旗標
|
||||
// 每次檢查前先重置狀態旗標,修正 haveThings 狀態殘留 Bug
|
||||
doorError = false;
|
||||
haveThings = false;
|
||||
for (byte[] buffer : devController.getReadBufferByMax()) {
|
||||
if (buffer[0] == 0x02) {
|
||||
getLogs().info("xxxxxxxxxxxxxxxxxxxxxxxxXinYuan Read:" + PortTools.showHex(buffer));
|
||||
@ -231,6 +262,7 @@ public class RecyclerVmcBuyListAdpter extends RecyclerView.Adapter<RecyclerVmcBu
|
||||
}
|
||||
|
||||
if (haveThings) {
|
||||
if (isHandled.getAndSet(true)) return;
|
||||
// 使用主執行緒顯示 AlertDialog
|
||||
new Handler(Looper.getMainLooper()).post(() -> {
|
||||
AlertDialog dialog = new AlertDialog.Builder(context)
|
||||
@ -239,6 +271,7 @@ public class RecyclerVmcBuyListAdpter extends RecyclerView.Adapter<RecyclerVmcBu
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(R.string.i_knew, (d, which) -> {
|
||||
d.dismiss();
|
||||
isCheckingSlot = false;
|
||||
handlerMain.start(getClass().getSimpleName(), BuyDialog.Option.FORCE_CLOSE.getOption(),
|
||||
"force close");
|
||||
})
|
||||
@ -246,16 +279,24 @@ public class RecyclerVmcBuyListAdpter extends RecyclerView.Adapter<RecyclerVmcBu
|
||||
|
||||
dialog.show();
|
||||
|
||||
// 放大提示文字
|
||||
TextView messageView = dialog.findViewById(android.R.id.message);
|
||||
if (messageView != null) {
|
||||
messageView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 24);
|
||||
}
|
||||
|
||||
// 加入 10 秒後自動觸發點擊確定
|
||||
new Handler(Looper.getMainLooper()).postDelayed(() -> {
|
||||
if (dialog.isShowing()) {
|
||||
dialog.dismiss();
|
||||
isCheckingSlot = false;
|
||||
handlerMain.start(getClass().getSimpleName(), BuyDialog.Option.FORCE_CLOSE.getOption(),
|
||||
"force close");
|
||||
}
|
||||
}, 10_000); // 10 秒(10000 毫秒)
|
||||
});
|
||||
} else if (doorError) {
|
||||
if (isHandled.getAndSet(true)) return;
|
||||
// 取貨口門未關閉,提示使用者並阻止後續購買流程
|
||||
doorError = false;
|
||||
handlerMain.start("RecycleFlowerBuyListAdpter", "取貨口門未正常關閉,請先確認門已關好");
|
||||
@ -267,6 +308,7 @@ public class RecyclerVmcBuyListAdpter extends RecyclerView.Adapter<RecyclerVmcBu
|
||||
.setCancelable(false)
|
||||
.setPositiveButton(R.string.i_knew, (d, which) -> {
|
||||
d.dismiss();
|
||||
isCheckingSlot = false;
|
||||
handlerMain.start(getClass().getSimpleName(), BuyDialog.Option.FORCE_CLOSE.getOption(),
|
||||
"force close");
|
||||
})
|
||||
@ -274,15 +316,29 @@ public class RecyclerVmcBuyListAdpter extends RecyclerView.Adapter<RecyclerVmcBu
|
||||
|
||||
dialog.show();
|
||||
|
||||
// 放大提示文字
|
||||
TextView messageView = dialog.findViewById(android.R.id.message);
|
||||
if (messageView != null) {
|
||||
messageView.setTextSize(TypedValue.COMPLEX_UNIT_SP, 24);
|
||||
}
|
||||
|
||||
// 加入 10 秒後自動觸發點擊確定
|
||||
new Handler(Looper.getMainLooper()).postDelayed(() -> {
|
||||
if (dialog.isShowing()) {
|
||||
dialog.dismiss();
|
||||
isCheckingSlot = false;
|
||||
handlerMain.start(getClass().getSimpleName(), BuyDialog.Option.FORCE_CLOSE.getOption(),
|
||||
"force close");
|
||||
}
|
||||
}, 10_000); // 10 秒(10000 毫秒)
|
||||
});
|
||||
} else {
|
||||
// 狀態安全且無異常,執行購買回呼
|
||||
if (!isHandled.getAndSet(true)) {
|
||||
if (onSafe != null) {
|
||||
new Handler(Looper.getMainLooper()).post(onSafe);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -387,7 +387,7 @@
|
||||
<string name="abnormal_response_message_error">Abnormal response, message error</string>
|
||||
<string name="product_delivery_issues_contact_the_counter_window">For product delivery issues, please contact the counter window!</string>
|
||||
<string name="abnormal_reminder">Abnormal reminder</string>
|
||||
<string name="there_is_something_at_the_pickup_port">There is something at the pickup port, please contact the service staff to handle it!</string>
|
||||
<string name="there_is_something_at_the_pickup_port">There is something at the pickup port, please remove it first</string>
|
||||
<string name="i_knew">knew</string>
|
||||
<string name="input_vehicle">Input Vehicle</string>
|
||||
<string name="reload_product">Reload Products</string>
|
||||
|
||||
@ -387,7 +387,7 @@
|
||||
<string name="abnormal_response_message_error">異常応答、メッセージエラー</string>
|
||||
<string name="product_delivery_issues_contact_the_counter_window">商品配送に関するトラブルはカウンター窓口までお問い合わせください!</string>
|
||||
<string name="abnormal_reminder">異常なリマインダー</string>
|
||||
<string name="there_is_something_at_the_pickup_port">ピックアップポートに何かある場合は、サービススタッフに連絡して対応してください!</string>
|
||||
<string name="there_is_something_at_the_pickup_port">受取口に物があります、先に取り出してください</string>
|
||||
<string name="i_knew">知っていた</string>
|
||||
<string name="input_vehicle">スマホバーコード への入力</string>
|
||||
<string name="sync_product">商品データを同期</string>
|
||||
|
||||
@ -297,7 +297,7 @@
|
||||
<string name="abnormal_response_message_error">回應異常,電文錯誤</string>
|
||||
<string name="product_delivery_issues_contact_the_counter_window">商品出貨問題,請洽櫃台窗口!</string>
|
||||
<string name="abnormal_reminder">異常提醒</string>
|
||||
<string name="there_is_something_at_the_pickup_port">取貨口有東西,請聯繫服務人員處理!</string>
|
||||
<string name="there_is_something_at_the_pickup_port">取貨口有東西,請先取出</string>
|
||||
<string name="i_knew">知道了</string>
|
||||
<string name="input_vehicle">輸入載具</string>
|
||||
<string name="member_card_pickup_title">領取確認</string>
|
||||
|
||||
Loading…
Reference in New Issue
Block a user