diff --git a/.changelog/lang_zh-Hans.json b/.changelog/lang_zh-Hans.json index 90496344..cb3ef2c8 100644 --- a/.changelog/lang_zh-Hans.json +++ b/.changelog/lang_zh-Hans.json @@ -98,6 +98,7 @@ "Canvas 构造函数可接受的参数类型错误 _[`issue #402`](http://issues.autojs6.com/402)_", "崩溃报告页面复制详细信息功能失效的问题", "Android 16+ 自定义返回逻辑失效导致返回功能异常的问题", + "文件管理器搜索结果展示后点击返回按钮或切换标签页面时可能导致应用崩溃的问题", "文件管理器删除项目文件夹后 UI 未能自动刷新的问题", "任务面板列表项频繁变动时可能导致应用崩溃的问题", "使用 \"三按钮\" 手势导航时导航栏前景色可能与夜间模式关联异常的问题", diff --git a/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.kt b/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.kt index c7a80389..f4246621 100644 --- a/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.kt +++ b/app/src/main/java/org/autojs/autojs/ui/explorer/ExplorerView.kt @@ -22,6 +22,7 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout import io.reactivex.Completable import io.reactivex.Observable import io.reactivex.android.schedulers.AndroidSchedulers +import io.reactivex.disposables.Disposable import io.reactivex.schedulers.Schedulers import org.autojs.autojs.core.pref.Pref.getInt import org.autojs.autojs.core.pref.Pref.getLinkedList @@ -84,8 +85,8 @@ import java.util.concurrent.Callable /** * Created by Stardust on Aug 21, 2017. * Transformed by SuperMonster003 on Nov 23, 2024. - * Modified by JetBrains AI Assistant (GPT-5.2) as of Apr 20, 2026. - * Modified by SuperMonster003 as of Feb 2, 2026. + * Modified by JetBrains AI Assistant (GPT-5.2) as of Feb 3, 2026. + * Modified by SuperMonster003 as of Feb 3, 2026. */ @SuppressLint("CheckResult", "NonConstantResourceId", "NotifyDataSetChanged") open class ExplorerView : ThemeColorSwipeRefreshLayout, SwipeRefreshLayout.OnRefreshListener, PopupMenu.OnMenuItemClickListener { @@ -131,6 +132,10 @@ open class ExplorerView : ThemeColorSwipeRefreshLayout, SwipeRefreshLayout.OnRef private val mPageStateHistories = Stack() private var mDirectorySpanSize = 2 + // Keep only one refresh chain running to avoid concurrent updates. + // zh-CN: 只允许一个刷新链路运行, 避免并发更新导致竞态问题. + private var mRefreshDisposable: Disposable? = null + // Unify action icon tint to match day/night theme, especially for overlay dialogs. // zh-CN: 统一操作图标着色以匹配日/夜主题, 尤其用于 overlay 对话框场景. private val mActionIconTint by lazy { @@ -244,6 +249,11 @@ open class ExplorerView : ThemeColorSwipeRefreshLayout, SwipeRefreshLayout.OnRef mExplorer?.unregisterChangeListener(this) mPageStateHistories.clear() binding = null + + // Cancel pending refresh to avoid late UI updates and concurrent iterations. + // zh-CN: 取消未完成的刷新, 避免延迟 UI 更新以及并发遍历导致的问题. + mRefreshDisposable?.dispose() + mRefreshDisposable = null } override fun onRefresh() { @@ -588,24 +598,41 @@ open class ExplorerView : ThemeColorSwipeRefreshLayout, SwipeRefreshLayout.OnRef private fun refreshCurrentPage() { val explorer = mExplorer ?: return isRefreshing = true - explorer.fetchChildren(currentPage) + + // Cancel the previous refresh to prevent multiple concurrent iterators on mutable data. + // zh-CN: 取消上一次刷新, 防止对可变数据产生多个并发迭代器. + mRefreshDisposable?.dispose() + + mRefreshDisposable = explorer.fetchChildren(currentPage) .subscribeOn(Schedulers.io()) .flatMapObservable { page: ExplorerPage? -> currentPageState.page = page - Observable.fromIterable(page) + + // Snapshot the iterable to avoid ConcurrentModificationException during iteration. + // zh-CN: 对可迭代对象做快照, 避免迭代期间被修改触发 ConcurrentModificationException. + val snapshot: List = page?.toList() ?: emptyList() + + Observable.fromIterable(snapshot) } .filter { f: ExplorerItem -> mFilter == null || mFilter!!.invoke(f) } .collectInto(explorerItemManager.cloneConfig(), ExplorerItemManager::add) .observeOn(Schedulers.computation()) .doOnSuccess(ExplorerItemManager::sort) .observeOn(AndroidSchedulers.mainThread()) - .subscribe { newManager: ExplorerItemManager -> + .doFinally { + // Always end the refreshing state even when errors happen. + // zh-CN: 无论成功或失败都要结束刷新状态. + isRefreshing = false + } + .subscribe({ newManager: ExplorerItemManager -> mProjectToolbar.updateVisibility() explorerItemManager = newManager notifyDataSetChanged() - isRefreshing = false post { scrollToPositionImmediately() } - } + }, { e -> + Log.e(LOG_TAG, "refreshCurrentPage() failed", e) + showSnack(this, R.string.error_refresh_failed, true) + }) } private fun scrollToPositionSmoothly() { diff --git a/app/src/main/res/values-ar/strings.xml b/app/src/main/res/values-ar/strings.xml index 0fb1ec34..5098fa00 100644 --- a/app/src/main/res/values-ar/strings.xml +++ b/app/src/main/res/values-ar/strings.xml @@ -1225,4 +1225,5 @@ اكتب إعدادات الأمان كتابة إعدادات النظام النوافذ المنبثقة في الخلفية + فشل التحديث \ No newline at end of file diff --git a/app/src/main/res/values-en/strings.xml b/app/src/main/res/values-en/strings.xml index aad9b0f7..5521e8b5 100644 --- a/app/src/main/res/values-en/strings.xml +++ b/app/src/main/res/values-en/strings.xml @@ -1220,4 +1220,5 @@ Write security settings Write system settings Display pop-up windows while running in the background + Refresh failed \ No newline at end of file diff --git a/app/src/main/res/values-es/strings.xml b/app/src/main/res/values-es/strings.xml index fe831496..3a954ce8 100644 --- a/app/src/main/res/values-es/strings.xml +++ b/app/src/main/res/values-es/strings.xml @@ -1223,4 +1223,5 @@ Escribir la configuración de seguridad Escribir la configuración del sistema Ventanas emergentes en segundo plano + Error al actualizar \ No newline at end of file diff --git a/app/src/main/res/values-fr/strings.xml b/app/src/main/res/values-fr/strings.xml index 79109aaa..6c74a9d3 100644 --- a/app/src/main/res/values-fr/strings.xml +++ b/app/src/main/res/values-fr/strings.xml @@ -1223,4 +1223,5 @@ Écrire les paramètres de sécurité. Écrire les paramètres système Fenêtres contextuelles en arrière-plan + Echec de l\'actualisation \ No newline at end of file diff --git a/app/src/main/res/values-ja/strings.xml b/app/src/main/res/values-ja/strings.xml index ccbff6e2..1bdc1e6a 100644 --- a/app/src/main/res/values-ja/strings.xml +++ b/app/src/main/res/values-ja/strings.xml @@ -1224,4 +1224,5 @@ セキュリティ設定の書き込み システム設定の書き込み バックグラウンドでのポップアップ表示 + 更新に失敗しました \ No newline at end of file diff --git a/app/src/main/res/values-ko/strings.xml b/app/src/main/res/values-ko/strings.xml index 550dc7d4..62dd9bca 100644 --- a/app/src/main/res/values-ko/strings.xml +++ b/app/src/main/res/values-ko/strings.xml @@ -1225,4 +1225,5 @@ 보안 설정을 작성하십시오 시스템 설정을 작성하십시오 백그라운드 팝업 + 새로고침에 실패했습니다 \ No newline at end of file diff --git a/app/src/main/res/values-ru/strings.xml b/app/src/main/res/values-ru/strings.xml index 03276a52..1a596b60 100644 --- a/app/src/main/res/values-ru/strings.xml +++ b/app/src/main/res/values-ru/strings.xml @@ -5,7 +5,6 @@ - Строительство... Очистка... Упаковка... @@ -1224,5 +1223,5 @@ Параметры безопасности записи Запись системных настроек Всплывающие окна в фоне - - + Не удалось обновить + \ No newline at end of file diff --git a/app/src/main/res/values-zh-rHK/strings.xml b/app/src/main/res/values-zh-rHK/strings.xml index 77aee88e..53445d37 100644 --- a/app/src/main/res/values-zh-rHK/strings.xml +++ b/app/src/main/res/values-zh-rHK/strings.xml @@ -1221,4 +1221,5 @@ 修改安全設置 修改系統設置 後台彈出界面 + 刷新失敗 \ No newline at end of file diff --git a/app/src/main/res/values-zh-rTW/strings.xml b/app/src/main/res/values-zh-rTW/strings.xml index 748f8124..340a3119 100644 --- a/app/src/main/res/values-zh-rTW/strings.xml +++ b/app/src/main/res/values-zh-rTW/strings.xml @@ -1221,4 +1221,5 @@ 修改安全設定 修改系統設定 後臺彈出介面 + 刷新失敗 \ No newline at end of file diff --git a/app/src/main/res/values-zh/strings.xml b/app/src/main/res/values-zh/strings.xml index f79e01d5..cbe487fa 100644 --- a/app/src/main/res/values-zh/strings.xml +++ b/app/src/main/res/values-zh/strings.xml @@ -1221,4 +1221,5 @@ 修改安全设置 修改系统设置 后台弹出界面 + 刷新失败 \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 8c0fe811..bfe77450 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1481,4 +1481,5 @@ Write security settings Write system settings Display pop-up windows while running in the background + Refresh failed \ No newline at end of file