@@ -164,9 +164,9 @@ class ActionPage : AppCompatActivity() {
164164 if (menuOptions == null ) {
165165 menuOptions = PageMenuLoader (applicationContext, config).load()
166166 }
167-
167+
168168 menu?.clear()
169-
169+
170170 menuOptions?.forEach { option ->
171171 if (option.isFab) {
172172 addFab(option)
@@ -178,69 +178,66 @@ class ActionPage : AppCompatActivity() {
178178 }
179179 }
180180 }
181+
182+ // Chỉ refresh 1 lần sau khi menu được dựng xong
183+ handler.post {
184+ requestCheckboxMenuRefresh()
185+ }
186+
181187 return true
182188 }
183189
184190 override fun onPrepareOptionsMenu (menu : Menu ): Boolean {
185- // Chỉ cập nhật trạng thái hiển thị từ dữ liệu hiện có, không chạy shell ở đây
191+ // Chỉ cập nhật giao diện từ dữ liệu đã có sẵn, tuyệt đối không chạy shell ở đây
186192 menuOptions?.forEach { option ->
187193 if (! option.isFab && option.type == " checkbox" ) {
188194 val uniqueItemId = option.key.hashCode()
189- val menuItem = menu.findItem(uniqueItemId)
190- menuItem?.isChecked = option.checked
195+ menu.findItem(uniqueItemId)?.isChecked = option.checked
191196 }
192197 }
193-
194- // Vẫn giữ hành vi cũ: menu sẵn sàng thì refresh checkbox
195- refreshCheckboxMenuStates()
196198 return super .onPrepareOptionsMenu(menu)
197199 }
198200
199- private fun refreshCheckboxMenuStates () {
201+ private fun requestCheckboxMenuRefresh () {
200202 val config = currentPageConfig ? : return
201-
203+
202204 val checkboxOptions = menuOptions?.filter { option ->
203- val uniqueItemId = option.key.hashCode()
204205 option.type == " checkbox" &&
205206 option.checkedSh.isNotEmpty() &&
206- ! justClickedItemIds.contains(uniqueItemId )
207+ ! justClickedItemIds.contains(option.key.hashCode() )
207208 }.orEmpty()
208-
209+
209210 if (checkboxOptions.isEmpty() || menuCheckboxRefreshing) return
210-
211+
211212 menuCheckboxRefreshing = true
212213 checkboxRefreshJob?.cancel()
213-
214+
214215 checkboxRefreshJob = lifecycleScope.launch(Dispatchers .IO ) {
215216 try {
216- // Chạy song song thay vì chạy nối tiếp từng item
217- val results = coroutineScope {
218- checkboxOptions.map { option ->
219- async {
220- val result = ScriptEnvironmen .executeResultRoot(
221- this @ActionPage,
222- option.checkedSh,
223- config
224- )?.trim()
225- option to result
226- }
227- }.awaitAll()
228- }
229-
217+ val results = checkboxOptions.map { option ->
218+ async {
219+ val result = ScriptEnvironmen .executeResultRoot(
220+ this @ActionPage,
221+ option.checkedSh,
222+ config
223+ )?.trim()
224+ option to result
225+ }
226+ }.awaitAll()
227+
230228 withContext(Dispatchers .Main ) {
231229 if (isFinishing || isDestroyed) return @withContext
232-
230+
233231 var changed = false
234232 results.forEach { (option, result) ->
235233 val uniqueItemId = option.key.hashCode()
236-
237234 if (! justClickedItemIds.contains(uniqueItemId)) {
238235 val newChecked = result == " 1" || result.equals(" true" , ignoreCase = true )
239236 if (option.checked != newChecked) changed = true
240237 option.checked = newChecked
241238 }
242239 }
243-
240+
244241 if (changed) {
245242 invalidateOptionsMenu()
246243 }
@@ -600,4 +597,5 @@ class ActionPage : AppCompatActivity() {
600597 } catch (_: Exception ) {}
601598 }
602599 }
603- }
600+ }
601+
0 commit comments