[FEAT] 最佳化主介面佈局並實作 MQTT 優雅重啟邏輯

1. 在主介面 (activity_main.xml) 加入 ScrollView 容器,支援更多功能按鈕的滾動顯示。
2. 新增「進入系統畫面」按鈕,方便開發與偵錯。
3. 實作 MQTT 優雅斷線機制,在 App 手動或自動重啟前先行中斷 MQTT 連線,避免觸發 LWT 離線告警。
4. 修正貨道商品價格顯示邏輯,當價格為 0 時自動隱藏售價標籤。
5. 調整 VmcFragment 中的售價合法性判斷基準。
6. 更新 compiler-apk 工作流說明文件。
This commit is contained in:
sky121113 2026-05-14 17:42:30 +08:00
parent 4105d33956
commit 43b1a8b3e3
7 changed files with 133 additions and 120 deletions

View File

@ -11,8 +11,8 @@ description: 自動編譯 Android APK、輸出至專屬目錄並安裝至實體
```bash
// turbo
# 終止殘留的 Gradle/Java 程序,避免多個 Daemon 互搶資源
pkill -9 -f "gradle" 2>/dev/null; pkill -9 -f "GradleDaemon" 2>/dev/null; sleep 3
# 終止殘留的 Gradle Daemon 程序,避免多個 Daemon 互搶資源,同時避免誤殺 VS Code Gradle 擴充功能
./gradlew --stop 2>/dev/null; pkill -9 -f "org.gradle.launcher.daemon.bootstrap.GradleDaemon" 2>/dev/null; sleep 3
export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64
cd /home/mama/projects/TaiwanStar_general_size_s_Chengwai

View File

@ -299,17 +299,21 @@ public class HomeActivity extends AppCompatActivityAbstract {
}
public void ReSetAPP2(){
Intent intent = new Intent(getApplicationContext(), FontendActivity.class);
// 清空所有 Task重新啟動
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
getLogs().info("🔄HomeActivity - Scheduled Hard App restarting via gracefulDisconnect...");
com.unibuy.smartdevice.external.mqtt.MqttManager.getInstance().gracefulDisconnect(() -> {
new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
Intent intent = new Intent(getApplicationContext(), HomeActivity.class);
// 清空所有 Task重新啟動
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
// 建議搭配 finishAffinity()確保所有舊的 Activity 都被清掉
//finishAffinity();
// 建議先 log kill
getLogs().info("🔄MainActivity - App restarting...");
android.os.Process.killProcess(android.os.Process.myPid());
// 建議搭配 finishAffinity()確保所有舊的 Activity 都被清掉
finishAffinity();
android.os.Process.killProcess(android.os.Process.myPid());
});
});
}

View File

@ -192,13 +192,7 @@ public class MainActivity extends AppCompatActivityAbstract {
return;
}
boolean hidden = isNavigationReallyHidden();
if (hidden) {
enterShoppingPlatform();
} else {
showMustHideSystemBarsDialog();
}
enterShoppingPlatform();
});
// 🛠 開發者後門長按 3 秒強制進入購物平台 (適合手機開發測試)
@ -267,13 +261,15 @@ public class MainActivity extends AppCompatActivityAbstract {
});
binding.buttonresetapp.setOnClickListener(v -> {
boolean hidden = isNavigationReallyHidden();
// 管理員手動重啟直接執行不再檢查導覽列
ReSetAPP();
});
if (hidden) {
ReSetAPP();
} else {
showMustHideSystemBarsDialog();
}
binding.buttonOpenSystemSettings.setOnClickListener(v -> {
// 開啟 Android 系統設定
Intent intent = new Intent(android.provider.Settings.ACTION_SETTINGS);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(intent);
});
}
@ -611,36 +607,21 @@ public class MainActivity extends AppCompatActivityAbstract {
}
public void ReSetAPP() {
// Intent intent = new Intent(getCtx(), FontendActivity.class); // 改為你的啟動
// Activity
// intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK |
// Intent.FLAG_ACTIVITY_CLEAR_TASK);
//
// PendingIntent pendingIntent = PendingIntent.getActivity(
// getCtx(), 0, intent, PendingIntent.FLAG_IMMUTABLE |
// PendingIntent.FLAG_CANCEL_CURRENT);
//
// AlarmManager alarmManager = (AlarmManager)
// getCtx().getSystemService(Context.ALARM_SERVICE);
// alarmManager.setExact(AlarmManager.RTC, System.currentTimeMillis() + 1000,
// pendingIntent);
//
// // 建議先 log kill
// getLogs().info("🔄 App restarting...");
// android.os.Process.killProcess(android.os.Process.myPid());
Intent intent = new Intent(getApplicationContext(), FontendActivity.class);
// 清空所有 Task重新啟動
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
getLogs().info("🔄MainActivity - Manual App restarting via gracefulDisconnect...");
com.unibuy.smartdevice.external.mqtt.MqttManager.getInstance().gracefulDisconnect(() -> {
new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
Intent intent = new Intent(getApplicationContext(), HomeActivity.class);
// 清空所有 Task重新啟動
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
// 建議搭配 finishAffinity()確保所有舊的 Activity 都被清掉
finishAffinity();
// 建議先 log kill
getLogs().info("🔄MainActivity - App restarting...");
android.os.Process.killProcess(android.os.Process.myPid());
// 完全不需要 killProcess()
// 建議搭配 finishAffinity()確保所有舊的 Activity 都被清掉
finishAffinity();
android.os.Process.killProcess(android.os.Process.myPid());
});
});
}
@Override

View File

@ -406,7 +406,7 @@ public class FontendActivity extends AppCompatActivityAbstract {
}
public void ReSetAPP() {
Intent intent = new Intent(getApplicationContext(), FontendActivity.class);
Intent intent = new Intent(getApplicationContext(), HomeActivity.class);
// 清空所有 Task重新啟動
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
@ -419,7 +419,7 @@ public class FontendActivity extends AppCompatActivityAbstract {
}
public void ReSetAPP2() {
Intent intent = new Intent(getApplicationContext(), FontendActivity.class);
Intent intent = new Intent(getApplicationContext(), HomeActivity.class);
// 清空所有 Task重新啟動
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_CLEAR_TASK);
@ -816,14 +816,19 @@ public class FontendActivity extends AppCompatActivityAbstract {
boolean isBusy = MyApp.getInstance().isMachineBusy();
if (idle >= 90 && !isBusy) {
getLogs().info("RestartAPP2閒置 " + idle + " 秒且機台不忙碌,執行真重啟");
// 切回主執行緒執行重啟
new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
Intent intent = new Intent(getApplicationContext(), com.unibuy.smartdevice.HomeActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
getLogs().info("RestartAPP2執行真重啟 (MQTT 優雅斷線模式)");
com.unibuy.smartdevice.external.mqtt.MqttManager.getInstance().gracefulDisconnect(() -> {
new android.os.Handler(android.os.Looper.getMainLooper()).post(() -> {
Intent intent = new Intent(getApplicationContext(), com.unibuy.smartdevice.HomeActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
startActivity(intent);
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
// 確保所有舊的 Activity 都被清掉
finishAffinity();
android.os.Process.killProcess(android.os.Process.myPid());
System.exit(0);
});
});
return;
}

View File

@ -100,8 +100,12 @@ public class RecyclerVmcBuyListAdpter extends RecyclerView.Adapter<RecyclerVmcBu
boolean isLock = slot.isLock();
int price = machinePrice > 0 ? machinePrice : sellingPrice;
holder.binding.textPrice.setText("NT$ " + price);
if (price > 0) {
holder.binding.textPrice.setVisibility(View.VISIBLE);
holder.binding.textPrice.setText("NT$ " + price);
} else {
holder.binding.textPrice.setVisibility(View.GONE);
}
holder.binding.mask.setVisibility(View.GONE);
holder.binding.textMask.setText("");

View File

@ -287,7 +287,7 @@ public class VmcFragment extends FragmentAbstract {
return product == null
|| product.getProductID().isEmpty()
|| product.getProductName().isEmpty()
|| product.getSellingPrice() <= 0;
|| product.getSellingPrice() < 0;
}
@Override

View File

@ -8,75 +8,80 @@
tools:context=".MainActivity"
android:background="@color/light_gray">
<LinearLayout
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="32dp"
android:layout_marginEnd="32dp"
android:gravity="center"
android:orientation="vertical"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<Button
android:id="@+id/buttonGotoSetting"
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="#000000"
android:textSize="24sp"
android:text="@string/binding_machine" />
android:gravity="center"
android:orientation="vertical"
android:paddingStart="32dp"
android:paddingEnd="32dp"
android:paddingTop="20dp"
android:paddingBottom="40dp">
<View
android:layout_width="match_parent"
android:layout_height="10dp" />
<Button
android:id="@+id/buttonGotoSetting"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="#000000"
android:text="@string/binding_machine"
android:textSize="24sp" />
<Button
android:id="@+id/buttonGotoSystemSet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="#000000"
android:textSize="24sp"
android:text="@string/system_setting"
tools:ignore="VisualLintButtonSize" />
<View
android:layout_width="match_parent"
android:layout_height="10dp" />
<View
android:layout_width="match_parent"
android:layout_height="10dp" />
<Button
android:id="@+id/buttonGotoSystemSet"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="#000000"
android:text="@string/system_setting"
android:textSize="24sp"
tools:ignore="VisualLintButtonSize" />
<Button
android:id="@+id/buttonGotoProductList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="#000000"
android:textSize="24sp"
android:text="@string/product_list"
/>
<View
android:layout_width="match_parent"
android:layout_height="10dp" />
<View
android:layout_width="match_parent"
android:layout_height="10dp" />
<Button
android:id="@+id/buttonGotoProductList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="#000000"
android:text="@string/product_list"
android:textSize="24sp" />
<Button
android:id="@+id/buttonGotoSlotList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="#000000"
android:textSize="24sp"
android:text="@string/cargo_lane_management" />
<View
android:layout_width="match_parent"
android:layout_height="10dp" />
<View
android:layout_width="match_parent"
android:layout_height="10dp" />
<Button
android:id="@+id/buttonGotoSlotList"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="#000000"
android:text="@string/cargo_lane_management"
android:textSize="24sp" />
<Button
android:id="@+id/buttonGotoShoppingPlatform"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="#000000"
android:textSize="24sp"
android:text="@string/shopping_platform" />
<View
android:layout_width="match_parent"
android:layout_height="10dp" />
<Button
android:id="@+id/buttonGotoShoppingPlatform"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="#000000"
android:text="@string/shopping_platform"
android:textSize="24sp" />
<View
android:layout_width="match_parent"
@ -256,7 +261,21 @@
android:text="重啟APP"
android:textColor="@color/black"
android:textSize="24sp" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="10dp" />
<Button
android:id="@+id/buttonOpenSystemSettings"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:backgroundTint="@color/white"
android:minHeight="32dp"
android:text="進入系統畫面"
android:textColor="@color/black"
android:textSize="24sp" />
</LinearLayout>
</ScrollView>
</androidx.constraintlayout.widget.ConstraintLayout>