记录一次 WebView.pauseTimers 引发的问题及该方法的真实含义

问题背景:

在某个 H5 页面可能会有视频信息,为了解决页面退出后视频继续播放的问题,在页面销毁时会对 WebView 进行一些回收销毁操作,其中包括 pauseTimers 操作。

问题描述:

同时打开两个 WebView 页面,关闭第二个页面,第一个页面中的部分操作不再响应。

首先,这个问题是由于 pauseTimers 导致的,因为 pauseTimers 会暂停所有 WebView 的 layoutparsingJavaScript timers,这是一个全局生效的方法,所以导致第一个页面中的 js 方法也被暂停了(这个说法是错误的,下文中会纠正)。但是程序有在页面 onResume 时调用 resumeTimers 恢复 js 方法的调用,那么为何没有生效呢?

进一步分析后发现,导致这个问题的原因还包括页面切换时生命周期的执行顺序。假设打开 A 页面后再打开 B 页面,此时关闭 B 页面,两个页面的生命周期执行顺序为:B:onPause -> A:onRestart -> A:onStart -> A:onResume -> B:onStop -> B:onDestroy

扫描二维码关注公众号,回复: 14943749 查看本文章

从这里可以看出,关闭 B 页面后,会先进入 A 页面的 onResume 并执行 resumeTimers,然后再进入 B 页面的 onDestroy 并执行 pauseTimers。所以最终执行的是 pauseTimers,导致的结果是全局的 WebView 都被停止了 js 的调用。

解决方案:

pauseTimers 方法改为在页面 onPause 时调用。

拓展思考:

在研究 pauseTimers 的过程中发现,很多人对其的理解是暂停全局所有的 js 方法,网上也普遍是这个说法。但在测试过程中发现并不是这样的,比如我在测试时写了个 html 页面,其中有两个按钮对应调用两段 js 方法,一段是调用 H5 中的 alert 弹窗,一段是调用 Android 中的方法弹出 toast,发现在调用 pauseTimers 之后这两个 js 方法都还可以继续响应执行。html 代码如下:

    <html>
        <body>
            <button style="width:100px;height:50px;" onclick="jsAlert()">alert</button>
            <button style="width:100px;height:50px;" onclick="androidToast()">toast</button>
        </body>
    </html>
    <script>
        function jsAlert() {
            alert("Can Alert!");
        }

        function androidToast() {
            window.market.showToast("Can Toast!");
        }
    </script>

所以我对于 pauseTimers 的实际作用有点疑惑,它的注释中提到 Pauses all layout, parsing, and JavaScript timers for all WebViews.,其中的 JavaScript timers 从字面意思来看也不是指 js 方法,而像是指定时器之类的。所以这里进一步测试,在 html 中实现一个计时器:

    <html>
        <body>
            <button style="width:100px;height:50px;" onclick="startTimer()">start</button>
            <button style="width:100px;height:50px;" onclick="resetTimer()">reset</button>
            <button style="width:100px;height:50px;" onclick="jsAlert()">alert</button><br><br>
            <input style="width:100px;height:50px;" value="0" id="show_num">
        </body>
    </html>
    <script>
        var timer = null;
        var num = 0;

        function startTimer() {
            timer = setInterval(function() {
                document.getElementById("show_num").value = ++num;
            }, 1000);
        }

        function resetTimer() {
            clearInterval(timer);
            document.getElementById("show_num").value = 0;
            countdown = null;
            num = 0;
        }

        function jsAlert() {
            alert("Can Alert!");
        }
    </script>

在 Android 中实现两个按钮,分别去调用 WebView 的 pauseTimersresumeTimers 方法:

        findViewById(R.id.pause).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mWebView.pauseTimers();
            }
        });

        findViewById(R.id.resume).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mWebView.resumeTimers();
            }
        });

页面如下:
在这里插入图片描述
开始测试,首先点击 H5 页面中 start 按钮,H5 页面上的计时器开始计数,此时点击 alert 可以弹出弹窗。然后点击 Native 界面中的 pause 按钮,执行 pauseTimers 操作,发现 H5 页面上的计时器暂停了,此时 alert 弹窗仍可弹出。再点击 Native 界面中的 resume 按钮,执行 resumeTimers 操作,H5 页面上的计时器继续开始计数。

通过上述研究过程可以发现,pauseTimers 仅暂停了 js 中的计时器,并不会影响 js 方法的调用和响应,所以 pauseTimers 能停止全局 js” 这个说法是不正确的。而之前提到的页面中部分操作不响应的问题,可能是和 WebView 中 layoutparsing 相关,比如内部跳转、页面渲染等。

猜你喜欢

转载自blog.csdn.net/qq_27489007/article/details/130137247