亚洲乱码中文字幕综合,中国熟女仑乱hd,亚洲精品乱拍国产一区二区三区,一本大道卡一卡二卡三乱码全集资源,又粗又黄又硬又爽的免费视频

Android?WebView預渲染介紹

 更新時間:2022年09月05日 09:08:45   作者:孝之請回答???????  
這篇文章主要介紹了Android?WebView預渲染介紹,文章圍繞主題展開詳細的內(nèi)容介紹,具有一定的參考價值,需要的小伙伴可以參考一下

前言

在一個Hybrid項目中,必不可少的就是加載h5頁面。h5頁面的加載性能極大影響著用戶體驗,并會從各方面影響到我們APP的業(yè)務數(shù)據(jù)。試想,假設一個h5頁面要花好幾秒才能打開,那用戶還會使用我們的APP嗎?所以今天我們講一講,客戶端上優(yōu)化h5頁面加載速度的一種方式:預渲染

照例,拋出本篇文章要解決的幾個問題:

  • 客戶端可以從哪些方面優(yōu)化h5頁面的加載速度?
  • 預渲染的基本實現(xiàn)邏輯是怎樣的?
  • 預渲染存在哪些局限性?

術(shù)語對齊

術(shù)語描述
WebView用于承載h5頁面的native組件。
預創(chuàng)建在用戶打開一個h5頁面之前,在內(nèi)存中先創(chuàng)建好一個WebView實例。當用戶打開h5頁面時,可以直接取到預先創(chuàng)建好的WebView實例,用于承載h5頁面。
預渲染在用戶打開一個h5頁面之前,在內(nèi)存中不僅預創(chuàng)建好了WebView實例,還進一步根據(jù)url提前渲染好了WebView。當用戶打開指定的url頁面時,可以直接拿預先渲染好了的WebView進行展示。

客戶端可以從哪些方面優(yōu)化h5頁面的加載速度?

我們可以看一下,在Android上完整打開一個WebView需要經(jīng)歷怎樣的一個鏈路(來自優(yōu)秀的前輩們):

image.png

所以,要想優(yōu)化WebView的加載速度,就要想辦法去縮短鏈路中這些節(jié)點所耗費的時間。

從客戶端的角度上來講,Page初始化就是H5容器的初始化。一般而言,容器初始化時間是比較快的(如果沒有太多初始化邏輯的話),優(yōu)化空間有限。WebView的初始化相對就比較復雜,涉及到了瀏覽器內(nèi)核在主線程的初始化。APP冷啟動后,首次創(chuàng)建WebView時需要去初始化瀏覽器內(nèi)核。

這里要分3種情況去看:

  • 全新安裝APP,冷啟動后首次打開一個WebView,耗時最長,可能會需要1000ms左右,取決于瀏覽器內(nèi)核。
  • 非全新安裝APP,冷啟動后首次打開一個WebView,耗時分布在500ms左右。
  • 冷啟動后,非首次打開一個WebView,耗時就非常短了,分布在15ms左右。

這里我們可以看到,第1種和第2種情況是存在比較大的提升空間的

當我們創(chuàng)建好WebView,執(zhí)行WebView#loadUrl()時,WebView就會經(jīng)歷上圖中的白屏-loading-可交互狀態(tài)。這幾個階段,可以說是整個鏈路中耗時占比最大的一部分。但客戶端在這里能做的優(yōu)化是很有限的,而且通常需要跟前端、服務端去配合優(yōu)化,比如可以并行請求數(shù)據(jù),這里就先不發(fā)散了。但如果換個角度思考,客戶端先不去干涉后面這幾個階段的邏輯,而是提前去執(zhí)行后面這幾個階段的邏輯,那么不也就相當于提高加載速度了么?這其實就是我們要講的預加載。

優(yōu)化思路

所以我們的優(yōu)化思路主要針對WebView初始化階段,以及WebView加載階段。

通過預創(chuàng)建WebView,去解決首次創(chuàng)建WebView耗時長的問題。

通過預渲染W(wǎng)ebView,去提前經(jīng)歷用戶需要等待的白屏-loading階段,當用戶打開相應頁面時,能夠直接上屏展示,給用戶的感覺就是秒開。

預渲染的基本實現(xiàn)邏輯是怎樣的?

預創(chuàng)建

預創(chuàng)建是預渲染的前提(沒有預創(chuàng)建好怎么預渲染呢..),所以我們先講下預創(chuàng)建。預創(chuàng)建WebView,一個基本原則就是,當內(nèi)存中沒有預創(chuàng)建的WebView可以復用(即預創(chuàng)建沒有命中)時,就走原來創(chuàng)建WebView的邏輯。

預創(chuàng)建個數(shù)

這里我們選擇只預創(chuàng)建1個WebView。之所以選擇1個,是因為我們預創(chuàng)建WebView的根本目的,是為了解決APP首次安裝/冷啟動時,第一個WebView加載慢的問題。后續(xù)的WebView實例的創(chuàng)建都是很快的。所以,即使后面沒有命中預創(chuàng)建的WebView,用的重新創(chuàng)建的WebView,也就是多花了15ms左右的時間,影響是很小的。所以綜合下來,預創(chuàng)建1個WebView的性價比是最高的,多了反而浪費內(nèi)存。

預創(chuàng)建時機

這里的時機要分為三個,第一個時機是在冷啟動后,我們需要進行預創(chuàng)建??梢赃x擇把這個時機放到進入首頁后,用IdleHandler進行主線程閑時創(chuàng)建。當然也可以選擇前置。前置的話有可能會影響到APP的啟動,所以如果不是特別有必要的話,建議還是后置一些。

第二個時機是在預創(chuàng)建的WebView被拿去復用后,此時也是需要預創(chuàng)建的。因為一旦被拿去復用,意味著我們緩存中已經(jīng)沒有可用的WebView了,若一個pha頁面又打開了另外一個pha頁面,我們在這個case最好也能提供預創(chuàng)建的WebView。

以上兩個時機都是自動觸發(fā)。后來發(fā)現(xiàn)一個場景,當用戶在某個路徑比較深的頁面時,若需要預加載下一個頁面,那么這個頁面往往是不需要一冷啟動就預渲染的。這時候就需要一個接口讓業(yè)務方能在用戶打開頁面之前將該頁面進行預加載。

void preload(Context context, String url);

預創(chuàng)建復用

復用WebView需要注意一點,每個WebView都是跟指定的Context綁定的,但預創(chuàng)建時,還獲取不到WebView未來要綁定的Context。因此預創(chuàng)建時可以用MutableContextWrapper包ApplicationContext去創(chuàng)建。MutableContextWrapper支持我們將其中的BaseContext進行替換,復用預創(chuàng)建的WebView時,將ApplicationContext替換為需要綁定的Context即可。同時根據(jù)“預創(chuàng)建時機”中說的,在復用時,往棧頂插入一個新的預創(chuàng)建的WebView。相應的,當頁面關閉時,我們也需要將綁定的Context解綁,防止內(nèi)存泄漏。

大致的邏輯如下圖所示:

image.png

這里也貼出部分偽代碼:

/**
 * 閑時預創(chuàng)建
 */
private void preCreateWebView() {
    Looper.myQueue().addIdleHandler(new MessageQueue.IdleHandler() {
        @Override
        public boolean queueIdle() {
            // 預創(chuàng)建webView
            WebView webView = new WebView(new MutableContextWrapper(APPLICATION_CONTEXT));
            cache.add(webView);
            return false;
        }
    });
}

/**
 * 獲取預創(chuàng)建的WebView
 * @param context 要與使用的webview綁定的context
 * @return
 */
public PHAWebView acquirePreCreateWebView(Context context) {
    WebView webview;
    // 緩存中無可用WebView時,直接新建
    if (cache.isEmpty()) {
        webview = createWebView();
    } else {
        webview = cache.peekWebView();
    }
    // 更改context
    if (webview != null && webview.getContext() instanceof MutableContextWrapper) {
        MutableContextWrapper webViewMutableContext = (MutableContextWrapper) webview.getContext();
        webViewMutableContext.setBaseContext(context);
    }
    return webview;
}

預渲染

預渲染,其實就是在預創(chuàng)建的基礎上,執(zhí)行WebView#loadUrl(),將頁面提前渲染完成。但這里面還有一些細節(jié)點需要關注。

預渲染時機

預渲染的時機也是分為兩個,一個是冷啟動后的主線程閑時階段進行預渲染,這一點跟預加載的時機保持一致。還有一個我們可以選擇在頁面關閉時進行預渲染。打比方說,假設我預渲染了頁面A,那么用戶在訪問完頁面A后,我需要再次預渲染頁面A,從而保證頁面A的實效性。

預渲染白名單

首先,預渲染是有對象的,預渲染的對象就是頁面url。而預創(chuàng)建是沒有特定對象的,只需要隨時準備一個可用的WebView就行了,誰都可以用。但預渲染不行,不告訴我預渲染誰,我還怎么預渲染。

所以,從初始化開始,我們就已經(jīng)決定好了該預渲染哪些頁面,也就是預渲染白名單。白名單可通過服務器配置的方式進行下發(fā)。但也不能一股腦把頁面全都配上,因為內(nèi)存是有限的,配太多可能會引起低端機型的OOM。

預渲染有效性校驗

所謂的有效性校驗,就是在復用預渲染W(wǎng)ebView時,校驗這個WebView是否被正常預渲染了。如果失效,就走預創(chuàng)建/重新創(chuàng)建的邏輯。這里分兩個角度來校驗WebView的有效性:時間有效性與狀態(tài)有效性。

時間有效性

存在這樣一種場景:當我們已經(jīng)預渲染了A頁面,且用戶一直沒有訪問。某個時刻這個頁面做了更新,即重新發(fā)布了,那么如果用戶這時候去訪問A頁面,看到的還是舊的A頁面。所以這里需要在預渲染頁面時,給頁面設置一個過期時間,若復用預渲染W(wǎng)ebView時已經(jīng)過期了,就說明WebView已經(jīng)失效了,需要重新loadUrl保證頁面的實效性。

狀態(tài)有效性

狀態(tài)有效性就是去校驗預渲染的WebView最終是否有渲染成功,這一點我們可以通過WebViewClient的生命周期回調(diào)(onPageFinished/onReceivedError)來進行判斷。之所以要做這個校驗,是為了防止一開始預渲染就失敗了,卻還是拿這個WebView去進行展示。比如,假設我們在網(wǎng)絡異常狀態(tài)下去進行了預渲染,在網(wǎng)絡恢復正常后用戶訪問預渲染頁面,若不進行狀態(tài)校驗,那么看到的就會是網(wǎng)絡異常狀態(tài)下的WebView了。

頁面顯示狀態(tài)通知

頁面顯示狀態(tài),通俗來講就是頁面現(xiàn)在是離屏的,還是上屏的。在h5的一些業(yè)務場景中,有一部分是需要感知到頁面的顯示狀態(tài)的。比如引導類的動畫,比如會場的一些倒計時等等。所以我們需要將頁面的顯示狀態(tài)同步到h5那邊。

實現(xiàn)上,就是要在預渲染W(wǎng)ebView時給h5注入一個全局的環(huán)境變量,window.page_on_screen=false。當復用WebView,即上屏時,再將window.page_on_screen設置為true,同時發(fā)一個通知給h5。這樣h5就可以根據(jù)同步到的顯示狀態(tài)來控制自己的業(yè)務邏輯。

其它注意事項

預渲染、預創(chuàng)建,本質(zhì)上是用空間換時間的優(yōu)化,所以是比較耗費內(nèi)存的。所以我們需要在內(nèi)存不足的時候,及時將內(nèi)存中待使用的WebView給回收掉,避免APP發(fā)生OOM。

另外,因為預渲染離屏加載了頁面,所以頁面的初始化行為是需要納入評估的,只有評估通過后,才能放入預渲染白名單中。具體的初始化行為包括但不限于:業(yè)務的曝光埋點、前端邏輯(如倒計時、跨天活動)、消費型(如首次引導)、后端流量評估、頁面在后臺是否會有聲音、是否會彈框(系統(tǒng)框、權(quán)限框、對話框...)等等。

預渲染存在哪些局限性?

  • 低端機內(nèi)存空間有限,預渲染白名單的實際配置數(shù)量需要視情況進行調(diào)整。
  • 預渲染頁面必須經(jīng)過白名單配置。頁面url、參數(shù)發(fā)生改變,配置也需要改變。這一點其實也是有優(yōu)化空間的,即離屏預渲染時加載url前綴域名,上屏時再根據(jù)完整的url參數(shù)做邏輯調(diào)整。實現(xiàn)上會比較麻煩,可以視ROI情況進行投入。
  • 預渲染頁面的實效性無法保證。預渲染頁面一旦重新部署,端上是不能立刻感知到并重新加載的。按上面的預渲染時機,目前只有以下二個場景會觸發(fā)端上對預渲染頁面的更新:
    • 1.冷啟動;
    • 2.頁面被訪問后關閉;
    • 3.業(yè)務調(diào)用接口主動注入。

所以大家如果有比較好的方案歡迎分享給我呀!

  • 命中率。預渲染頁面是不能百分百命中的,即即使我們把某個頁面配置進了預渲染白名單,app也有可能沒預渲染上這個頁面。有很多異常場景會影響到命中率,比如:
    • 1.上面講到的預渲染的時間有效性與狀態(tài)有效性;
    • 2.服務端下發(fā)的預渲染白名單沒有及時拉取到;
    • 3.主線程一直繁忙,導致預渲染邏輯一直沒執(zhí)行;
    • 4.內(nèi)存不夠,將緩存的預渲染W(wǎng)ebView回收掉了。

總結(jié)

所以雖然預渲染能從表面上實現(xiàn)h5頁面的秒開,但也不是萬能的,是存在一些缺陷的(否則也不需要別的優(yōu)化手段了)。但我認為是諸多優(yōu)化手段中比較簡單卻又能立竿見影的一個手段,特別是對本身h5頁面加載就非常慢的app而言。所以如果還沒做起來的同學可以試一試,后面再結(jié)合其它優(yōu)化的手段抹除不足。今天就講到這里啦。

到此這篇關于Android WebView預渲染介紹的文章就介紹到這了,更多相關Android WebView預渲染內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!

相關文章

最新評論