You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android WebApp恢复后刷新按钮持续旋转问题求助

Android WebApp刷新按钮切后台后持续旋转问题修复

问题描述

开发个人网站的Android WebApp时,给刷新按钮添加了旋转动画用于页面刷新。但切换到其他应用再返回该App后,刷新按钮会开始缓慢持续旋转,日志未发现异常。

相关代码

Kotlin代码(MainActivity)

class MainActivity : AppCompatActivity() {
    //define the variables here
    val weburl = "https://techdecipher.com/"
    lateinit var backhomebuttom: Button
    lateinit var scrollToTopButton: Button
    lateinit var scrollToBottomButton: Button
    lateinit var webView: WebView
    lateinit var refreshButton: Button
    private var isRefreshing = false
    val TAG = "Main Activity"
    private var rotateAnimator: ObjectAnimator? = null

    @RequiresApi(Build.VERSION_CODES.Q)
    @SuppressLint("SetJavaScriptEnabled")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        AppCompatDelegate.setDefaultNightMode(AppCompatDelegate.MODE_NIGHT_NO);
        setContentView(R.layout.activity_main)

        Log.d(TAG, "onCreate: ")

        // assign the id to each button
        webView = findViewById(R.id.webView)
        backhomebuttom = findViewById(R.id.backhomebuttom)
        scrollToTopButton = findViewById(R.id.scrollToTopButton)
        scrollToBottomButton = findViewById(R.id.scrollToBottomButton)
        refreshButton = findViewById(R.id.refreshButton)

       // network check
       // networkcheck()
        //call loadwebrulfunction
        loadweburlfunction()

        // reload button is clicked
        refreshButton.setOnClickListener {
            Log.d(TAG, "onCreate: reload")
            if (!isRefreshing) {
                // 使用ObjectAnimator实现旋转动画
                rotateAnimator = ObjectAnimator.ofFloat(refreshButton, "rotation", 0f, 360f).apply {
                    duration = 500
                    interpolator = LinearInterpolator()
                    repeatCount = ObjectAnimator.INFINITE
                    start()
                }
                isRefreshing = true

                // Reload the website
                webView.reload()

                // 使用lifecycleScope确保任务随Activity生命周期销毁
                lifecycleScope.launch {
                    delay(1000)
                    stopRefreshAnimation()
                }
            }
        }
    }

 // load web url function on webview
    @RequiresApi(Build.VERSION_CODES.Q)
    @SuppressLint("SetJavaScriptEnabled")
   private fun loadweburlfunction() {
        webView.settings.javaScriptEnabled = true
        webView.setBackgroundColor(Color.WHITE)
        webView.webChromeClient = WebChromeClient()
        webView.webViewClient = WebViewClient()
        webView.loadUrl(weburl)
    }

    private fun stopRefreshAnimation() {
        rotateAnimator?.cancel()
        refreshButton.rotation = 0f // 重置按钮旋转角度
        isRefreshing = false
    }

    override fun onResume() {
        super.onResume()
        stopRefreshAnimation()
    }

    override fun onPause() {
        super.onPause()
        Log.d(TAG, "onPause: ")
        stopRefreshAnimation() // 后台时强制停止动画
    }

    override fun onRestart() {
        super.onRestart()
        Log.d(TAG, "onRestart: ")
        stopRefreshAnimation()
    }

    override fun onDestroy() {
        super.onDestroy()
        Log.d(TAG, "onDestroy: ")
        stopRefreshAnimation()
    }
}

XML布局代码

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/swipeRefreshLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

        <!-- WebView to display content -->
        <WebView
            android:id="@+id/webView"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_above="@+id/buttonContainer" />

        <!-- Button Container at the bottom -->
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="60dp"
            android:gravity="center"
            android:id="@+id/buttonContainer"
            android:layout_alignParentBottom="true">

            <!-- Refresh Button -->
                <Button
                    android:id="@+id/refreshButton"
                    android:layout_width="40dp"
                    android:background="@drawable/refresh_icon"
                    android:layout_height="40dp"
                    android:contentDescription="@string/rotate_to_refres" />

            <!-- Home Button -->
                <Button
                    android:id="@+id/backhomebuttom"
                    android:layout_width="130dp"
                    android:layout_height="40dp"
                    android:layout_gravity="center"
                    android:layout_marginStart="15dp"
                    android:text="@string/homepage"
                    android:textStyle="bold"
                    android:background="@drawable/rounded_button_selector"
                    android:gravity="center"
                    android:padding="0dp" />

            <!-- Top Button -->
            <Button
                    android:layout_width="40dp"
                    android:layout_gravity="center"
                    android:layout_marginStart="15dp"
                    android:id="@+id/scrollToTopButton"
                    android:background="@drawable/scrollup"
                    android:layout_height="40dp"/>
            <!-- Bottom Button -->
                <Button
                    android:layout_width="40dp"
                    android:layout_gravity="center"
                    android:layout_marginStart="15dp"
                    android:id="@+id/scrollToBottomButton"
                    android:background="@drawable/scrolldown"
                    android:layout_height="40dp" />

            <!-- Share Button -->
                <Button
                    android:layout_width="40dp"
                    android:layout_marginStart="15dp"
                    android:background="@drawable/share"
                    android:layout_height="40dp" />

            </LinearLayout>

</RelativeLayout>

问题原因与修复说明

  1. 旧动画框架缺陷:原代码使用的RotateAnimation属于旧视图动画框架,与View生命周期绑定松散,Activity后台恢复时系统可能自动重启未正确停止的动画。改用ObjectAnimator属性动画,直接操作View的rotation属性,生命周期一致性更好。
  2. 后台任务不可靠:原Handler().postDelayed在Activity进入后台后可能被系统延迟或丢弃,导致isRefreshing状态未及时重置。改用lifecycleScope.launch,任务会随Activity销毁自动取消,避免内存泄漏和状态不一致。
  3. 生命周期未全面覆盖:原代码仅在onResume/onRestart判断isRefreshing后停止动画,但后台时动画可能已处于异常状态。修改为在onPause/onResume/onRestart/onDestroy中强制调用stopRefreshAnimation,确保任何场景下动画都能被正确停止并重置状态。

内容的提问来源于stack exchange,提问作者Pranav Chaudhari

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 03:54:59