Skip to content

Commit 409f6d0

Browse files
feat: Offload storage clearing to background thread to prevent ANR
Refactored `clearInternalStorage` in `SyncActivity` to be a `suspend` function, moving the file deletion logic to a background thread using `withContext(Dispatchers.IO)`. This prevents the main thread from being blocked during the potentially long-running storage cleanup process, resolving a critical ANR risk. Additionally, the `StrictMode` policy was strengthened to include `penaltyDeath()` in debug builds. This will proactively catch similar main-thread I/O regressions in the future by causing the app to crash during development, making such issues impossible to ignore. A race condition was also fixed by ensuring the sync process only starts after the storage clearing is complete.
1 parent 83a17ba commit 409f6d0

File tree

2 files changed

+29
-19
lines changed

2 files changed

+29
-19
lines changed

app/src/main/java/org/ole/planet/myplanet/MainApplication.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -229,6 +229,7 @@ class MainApplication : Application(), Application.ActivityLifecycleCallbacks {
229229
.detectDiskWrites()
230230
.detectNetwork()
231231
.penaltyLog()
232+
.penaltyDeath()
232233
.build()
233234
StrictMode.setThreadPolicy(threadPolicy)
234235
}

app/src/main/java/org/ole/planet/myplanet/ui/sync/SyncActivity.kt

Lines changed: 28 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -230,13 +230,15 @@ abstract class SyncActivity : ProcessUserDataActivity(), SyncListener, CheckVers
230230
.show()
231231
}
232232

233-
private fun clearInternalStorage() {
234-
val myDir = File(FileUtils.getOlePath(this))
235-
if (myDir.isDirectory) {
236-
val children = myDir.list()
237-
if (children != null) {
238-
for (i in children.indices) {
239-
File(myDir, children[i]).delete()
233+
private suspend fun clearInternalStorage() {
234+
withContext(Dispatchers.IO) {
235+
val myDir = File(FileUtils.getOlePath(this@SyncActivity))
236+
if (myDir.isDirectory) {
237+
val children = myDir.list()
238+
if (children != null) {
239+
for (i in children.indices) {
240+
File(myDir, children[i]).delete()
241+
}
240242
}
241243
}
242244
}
@@ -728,20 +730,27 @@ abstract class SyncActivity : ProcessUserDataActivity(), SyncListener, CheckVers
728730
processedUrl = saveConfigAndContinue(dialog, url, isAlternativeUrl, defaultUrl)
729731
if (TextUtils.isEmpty(processedUrl)) return
730732
isSync = true
731-
if (checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) && settings.getBoolean("firstRun", true)) {
732-
clearInternalStorage()
733-
}
734-
Service(this).isPlanetAvailable(object : PlanetAvailableListener {
735-
override fun isAvailable() {
736-
Service(context).checkVersion(this@SyncActivity, settings)
737-
}
738-
override fun notAvailable() {
739-
if (!isFinishing) {
740-
syncFailed = true
741-
showAlert(context, "Error", getString(R.string.planet_server_not_reachable))
733+
val startSyncFlow = {
734+
Service(this).isPlanetAvailable(object : PlanetAvailableListener {
735+
override fun isAvailable() {
736+
Service(context).checkVersion(this@SyncActivity, settings)
737+
}
738+
override fun notAvailable() {
739+
if (!isFinishing) {
740+
syncFailed = true
741+
showAlert(context, "Error", getString(R.string.planet_server_not_reachable))
742+
}
742743
}
744+
})
745+
}
746+
if (checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) && settings.getBoolean("firstRun", true)) {
747+
lifecycleScope.launch {
748+
clearInternalStorage()
749+
startSyncFlow()
743750
}
744-
})
751+
} else {
752+
startSyncFlow()
753+
}
745754
}
746755

747756
override fun onSuccess(success: String?) {

0 commit comments

Comments
 (0)