WebView打开出现白屏和速度慢的一些原因:
1.H5页面运行在独立进程中,H5打开需要首先启动Web进程。
2.每次关闭H5页面会通过exitProcess(0)关闭Web 进程。
优化方案:
1.Web进程预启动。
通过绑定服务的方式启动一个Service来对WebView进程进行预热。
<service
android:name=".service.PreWebService"
android:enabled="true"
android:process=":Webview"
android:exported="true">
</service>
class PreWebService : Service() {
override fun onBind(intent: Intent): IBinder? {
return null
}
}
val intent = Intent(context, PreWebService::class.java)
context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)
private val mConnection =
object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
mBound = true
}
override fun onServiceDisconnected(name: ComponentName?) {
mBound = false
}
}
if (mBound) {
context.unbindService(mConnection)
mBound = false
}
2.WebView 预创建与复用。
class WebViewManager private constructor() {
companion object {
@Volatile
private var INSTANCE: WebViewManager? = null
private fun instance() = INSTANCE ?: synchronized(this) {
INSTANCE ?: WebViewManager().also {
INSTANCE = it
}
}
fun prepare(context: Context) {
instance().prepare(context)
}
fun obtain(context: Context): WebView {
return instance().obtain(context)
}
fun recycle(webView: WebView) {
instance().recycle(webView)
}
fun destroy(context: Context) {
instance().destroy(context)
}
fun goBack(webView: WebView, originalUrl: String): Boolean {
val canBack = webView.canGoBack()
if (canBack) webView.goBack()
val backForwardList = webView.copyBackForwardList()
val currentIndex = backForwardList.currentIndex
if (currentIndex == 0) {
val currentUrl = backForwardList.currentItem?.url
val currentHost = Uri.parse(currentUrl).host
//栈底不是链接则直接返回
if (currentHost.isNullOrBlank()) return false
//栈底链接不是原始链接则直接返回
if (originalUrl != currentUrl) return false
}
return canBack
}
}
private val webViewCache: MutableList<WebView> = ArrayList(1)
private var mBound = false
fun prepare(context: Context) {
if (webViewCache.isEmpty()) {
Looper.myQueue().addIdleHandler {
webViewCache.add(create(MutableContextWrapper(context)))
val intent = Intent(context, PreWebService::class.java)
context.bindService(intent, mConnection, Context.BIND_AUTO_CREATE)
false
}
}
}
fun obtain(context: Context): WebView {
if (webViewCache.isEmpty()) {
webViewCache.add(create(MutableContextWrapper(context)))
}
val webView = webViewCache.removeFirst()
val contextWrapper = webView.context as MutableContextWrapper
contextWrapper.baseContext = context
webView.clearHistory()
webView.resumeTimers()
return webView
}
fun recycle(webView: WebView) {
try {
webView.stopLoading()
webView.loadDataWithBaseURL("about:blank", "", "text/html", "utf-8", null)
webView.clearHistory()
webView.pauseTimers()
val parent = webView.parent
if (parent != null) {
(parent as ViewGroup).removeView(webView)
}
val contextWrapper = webView.context as MutableContextWrapper
contextWrapper.baseContext = webView.context.applicationContext
} catch (e: Exception) {
e.printStackTrace()
} finally {
if (!webViewCache.contains(webView)) {
webViewCache.add(webView)
}
}
}
fun destroy(context: Context) {
try {
if (mBound) {
context.unbindService(mConnection)
mBound = false
}
webViewCache.forEach {
it.removeAllViews()
it.destroy()
webViewCache.remove(it)
}
} catch (e: Exception) {
e.printStackTrace()
}
}
private fun create(context: Context): WebView {
return WebView(context)
}
private val mConnection =
object : ServiceConnection {
override fun onServiceConnected(name: ComponentName?, service: IBinder?) {
mBound = true
}
override fun onServiceDisconnected(name: ComponentName?) {
mBound = false
}
}
}
3.WebView页面关闭时不关闭Web进程,只做资源清理。