fix: OTA 弹窗进度条修复

1. 进度条宽度用 post{} 延迟设置,确保容器已布局(width>0)
2. 进度回调限频 200ms,避免主线程过载
3. 用 runOnUiThread 替代 launch(Main),更简单可靠
4. 各状态切换加日志

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
dongliang
2026-04-30 21:42:06 +09:30
parent acd262a3a6
commit 3ced3c74cf
2 changed files with 36 additions and 10 deletions

View File

@@ -209,10 +209,13 @@ class MainActivity : AppCompatActivity() {
/** 待下载的更新 URL */ /** 待下载的更新 URL */
private var pendingUpdateUrl: String? = null private var pendingUpdateUrl: String? = null
/** 上次进度更新时间(限制频率,避免主线程过载) */
private var lastProgressUpdate = 0L
/** 开始下载并安装 APK */ /** 开始下载并安装 APK */
private fun startDownloadAndInstall() { private fun startDownloadAndInstall() {
val url = pendingUpdateUrl ?: return val url = pendingUpdateUrl ?: return
Timber.d("OTA: 开始下载安装流程, url=%s", url)
updateManager.isUpdating = true updateManager.isUpdating = true
// 保持屏幕常亮 // 保持屏幕常亮
screenController.turnOn() screenController.turnOn()
@@ -221,19 +224,23 @@ class MainActivity : AppCompatActivity() {
activityScope.launch { activityScope.launch {
val file = updateManager.downloadApk(url) { progress, bytes -> val file = updateManager.downloadApk(url) { progress, bytes ->
// 进度回调在 IO 线程,切回主线程更新 UI // 限制进度更新频率:最多每 200ms 更新一次 UI
launch(kotlinx.coroutines.Dispatchers.Main) { val now = System.currentTimeMillis()
if (now - lastProgressUpdate >= 200 || progress >= 100) {
lastProgressUpdate = now
runOnUiThread {
updateDialog.updateProgress(progress, bytes) updateDialog.updateProgress(progress, bytes)
} }
} }
}
// 回到主线程处理结果 // 回到主线程处理结果
kotlinx.coroutines.withContext(kotlinx.coroutines.Dispatchers.Main) { kotlinx.coroutines.withContext(kotlinx.coroutines.Dispatchers.Main) {
if (file != null) { if (file != null) {
// 下载成功 → 触发安装 Timber.d("OTA: 下载完成,触发安装")
updateManager.installApk(file) updateManager.installApk(file)
} else { } else {
// 下载失败 → 显示错误 Timber.d("OTA: 下载失败")
updateManager.isUpdating = false updateManager.isUpdating = false
updateDialog.showError() updateDialog.showError()
} }

View File

@@ -7,6 +7,7 @@ import android.view.View
import android.widget.FrameLayout import android.widget.FrameLayout
import android.widget.TextView import android.widget.TextView
import com.xiaoqu.watch.R import com.xiaoqu.watch.R
import timber.log.Timber
/** /**
* OTA 更新弹窗 View全屏覆盖 * OTA 更新弹窗 View全屏覆盖
@@ -59,18 +60,23 @@ class UpdateDialogView @JvmOverloads constructor(
tvProgress.visibility = View.GONE tvProgress.visibility = View.GONE
btnAction.visibility = View.VISIBLE btnAction.visibility = View.VISIBLE
btnAction.text = "立即更新" btnAction.text = "立即更新"
Timber.d("OTA弹窗: 显示发现新版本")
} }
/** 显示"下载中"状态 */ /** 显示"下载中"状态 */
fun showDownloading() { fun showDownloading() {
visibility = View.VISIBLE
tvIcon.text = "\ueb2c" tvIcon.text = "\ueb2c"
tvTitle.text = "请勿关机!" tvTitle.text = "请勿关机!"
tvDesc.visibility = View.VISIBLE tvDesc.visibility = View.VISIBLE
tvDesc.text = "正在升级系统..." tvDesc.text = "正在升级系统..."
progressContainer.visibility = View.VISIBLE progressContainer.visibility = View.VISIBLE
tvProgress.visibility = View.VISIBLE tvProgress.visibility = View.VISIBLE
tvProgress.text = "0%"
btnAction.visibility = View.GONE btnAction.visibility = View.GONE
updateProgress(0) // 进度条初始归零
setProgressPercent(0)
Timber.d("OTA弹窗: 显示下载中")
} }
/** /**
@@ -80,10 +86,7 @@ class UpdateDialogView @JvmOverloads constructor(
*/ */
fun updateProgress(percent: Int, downloadedBytes: Long = 0) { fun updateProgress(percent: Int, downloadedBytes: Long = 0) {
if (percent >= 0) { if (percent >= 0) {
// 已知进度:显示百分比 setProgressPercent(percent)
val params = progressBar.layoutParams
params.width = (progressContainer.width * percent / 100).coerceAtLeast(0)
progressBar.layoutParams = params
tvProgress.text = "${percent}%" tvProgress.text = "${percent}%"
} else { } else {
// 未知进度:显示已下载大小 // 未知进度:显示已下载大小
@@ -101,10 +104,26 @@ class UpdateDialogView @JvmOverloads constructor(
tvProgress.visibility = View.GONE tvProgress.visibility = View.GONE
btnAction.visibility = View.VISIBLE btnAction.visibility = View.VISIBLE
btnAction.text = "重新下载" btnAction.text = "重新下载"
Timber.d("OTA弹窗: 显示错误 %s", message)
} }
/** 隐藏弹窗 */ /** 隐藏弹窗 */
fun hide() { fun hide() {
visibility = View.GONE visibility = View.GONE
} }
/**
* 设置进度条百分比(用 post 确保在布局完成后设置宽度)
*/
private fun setProgressPercent(percent: Int) {
progressContainer.post {
val containerWidth = progressContainer.width
if (containerWidth > 0) {
val barWidth = containerWidth * percent / 100
val params = progressBar.layoutParams
params.width = barWidth
progressBar.layoutParams = params
}
}
}
} }