解决Webview加载不完全导致部分js无效

1,427 阅读2分钟

「这是我参与11月更文挑战的第9天,活动详情查看:2021最后一次更文挑战

问题出现

有两种情况: 一种情况是打开activity时webview开始加载页面,但是发现加载了一部分后就停止了,余下的一直不再加载。但是当关闭这个activity时发现webview又继续加载了。

第二种情况是webview正常加载,但是进行操作时发现有些操作没有反应。比如接入支付宝国际sdk,未装支付宝app而使用h5页面时出现点击无反应的情况。

问题解析

进过反复测试发现,是因为有两个含有webview的activity:activityA和activityB。在activityA的onPause和onResume中分别有mWebView.pauseTimers()mWebView.resumeTimers(),但是activityB中没有。先打开activityA加载web页面,然后打开activityB,因为activityB没有resumeTimers,他的部分js未成功加载,所以出现上面的现象。

问题根源

问题的根源就是WebView的pauseTimers()和resumeTimers()这两个方法。它们的源码及注释如下

/**
 * Pauses all layout, parsing, and JavaScript timers for all WebViews. This
 * is a global requests, not restricted to just this WebView. This can be
 * useful if the application has been paused.
 */
public void pauseTimers() {
    checkThread();
    mProvider.pauseTimers();
}

/**
 * Resumes all layout, parsing, and JavaScript timers for all WebViews.
 * This will resume dispatching all timers.
 */
public void resumeTimers() {
    checkThread();
    mProvider.resumeTimers();
}

可以看到这两个方法都是全局的,可以停止所有WebView的加载。所以当打开activityB的时候走了activityA的生命周期onPause,这样执行了pauseTimers(),而因为是全局的所以作用到所有的webview,所以activityB的webview也被pause而停止了加载,同时因为activityB的生命周期中并没有实现这两个函数,所以在pauseTimers()后没有执行resumeTimers(),所以activityB的web页面被pause后也没有恢复,这样就导致了一部分js代码没有加载,这样相关的效果就失效了。

解决方法

通过上面分析,其实我们就知道该如何解决了,在activityB的onPause和onResume中也加入mWebView.pauseTimers()mWebView.resumeTimers()即可。但是像我们前面说的第二种情况,我们使用的是第三方sdk的话,那么我们是没办法对其进行修改的,我们可以将activityA中的mWebView.pauseTimers()mWebView.resumeTimers()方法去掉来保证页面正常。

最后注意,webview还有onPause()onResume这两个方法。这两个方法与pauseTimers()resumeTimers()不同,他们两个是作用范围在当前webview的。而且作用效果也不同:onPause()会立刻停止当前webview的加载;而pauseTimers()会停止所有webview的延时加载,即那些等待timeout才执行的function,并且不执行resumeTimers()就不会加载。