最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android?WebView預(yù)渲染介紹

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

前言

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

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

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

術(shù)語對(duì)齊

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

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

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

image.png

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

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

這里要分3種情況去看:

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

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

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

優(yōu)化思路

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

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

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

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

預(yù)創(chuàng)建

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

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

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

預(yù)創(chuàng)建時(shí)機(jī)

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

第二個(gè)時(shí)機(jī)是在預(yù)創(chuàng)建的WebView被拿去復(fù)用后,此時(shí)也是需要預(yù)創(chuàng)建的。因?yàn)橐坏┍荒萌?fù)用,意味著我們緩存中已經(jīng)沒有可用的WebView了,若一個(gè)pha頁面又打開了另外一個(gè)pha頁面,我們?cè)谶@個(gè)case最好也能提供預(yù)創(chuàng)建的WebView。

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

void preload(Context context, String url);

預(yù)創(chuàng)建復(fù)用

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

大致的邏輯如下圖所示:

image.png

這里也貼出部分偽代碼:

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

/**
 * 獲取預(yù)創(chuàng)建的WebView
 * @param context 要與使用的webview綁定的context
 * @return
 */
public PHAWebView acquirePreCreateWebView(Context context) {
    WebView webview;
    // 緩存中無可用WebView時(shí),直接新建
    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;
}

預(yù)渲染

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

預(yù)渲染時(shí)機(jī)

預(yù)渲染的時(shí)機(jī)也是分為兩個(gè),一個(gè)是冷啟動(dòng)后的主線程閑時(shí)階段進(jìn)行預(yù)渲染,這一點(diǎn)跟預(yù)加載的時(shí)機(jī)保持一致。還有一個(gè)我們可以選擇在頁面關(guān)閉時(shí)進(jìn)行預(yù)渲染。打比方說,假設(shè)我預(yù)渲染了頁面A,那么用戶在訪問完頁面A后,我需要再次預(yù)渲染頁面A,從而保證頁面A的實(shí)效性。

預(yù)渲染白名單

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

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

預(yù)渲染有效性校驗(yàn)

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

時(shí)間有效性

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

狀態(tài)有效性

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

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

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

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

其它注意事項(xiàng)

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

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

預(yù)渲染存在哪些局限性?

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

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

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

總結(jié)

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

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

相關(guān)文章

  • Android自定義控件基本原理詳解(一)

    Android自定義控件基本原理詳解(一)

    這篇文章主要為大家詳細(xì)介紹了Android自定義控件基本原理,了解一下自定義控件的要求和實(shí)現(xiàn)的基本原理,感興趣的小伙伴們可以參考一下
    2016-08-08
  • Android變形(Transform)之Matrix用法

    Android變形(Transform)之Matrix用法

    Android的2D變形(包括縮放,扭曲,平移,旋轉(zhuǎn)等)可以通過Matrix來實(shí)現(xiàn),本文研究了一下;接下來就將我這倆天研究的東西和大家分享下,先來看看Matrix的用法感興趣的你可不要錯(cuò)過了哈
    2013-02-02
  • Android Canvas繪制文字橫縱向?qū)R

    Android Canvas繪制文字橫縱向?qū)R

    這篇文章主要介紹了Android Canvas繪制文字橫縱向?qū)R,Align屬性決定了使用該畫筆時(shí),相較于繪制點(diǎn)的水平對(duì)稱方式,分別是LEFT、CENTER、RIGHT,更多相關(guān)內(nèi)容需要的小伙伴可以參考下面文章詳細(xì)內(nèi)容
    2022-06-06
  • 使用RecylerView完成拖動(dòng)排序高仿qq側(cè)滑刪除功能

    使用RecylerView完成拖動(dòng)排序高仿qq側(cè)滑刪除功能

    最近在做一個(gè)android項(xiàng)目,使用到Recylerview完成拖動(dòng)排序,側(cè)滑刪除功能,今天小編把思路分享到腳本之家平臺(tái),供大家學(xué)習(xí)
    2016-10-10
  • Android開發(fā)應(yīng)用第一步 安裝及配置模擬器Genymotion

    Android開發(fā)應(yīng)用第一步 安裝及配置模擬器Genymotion

    這篇文章主要介紹了Android開發(fā)應(yīng)用第一步,即安裝及配置模擬器Genymotion,感興趣的小伙伴們可以參考一下
    2015-12-12
  • Android編程實(shí)現(xiàn)控件不同狀態(tài)文字顯示不同顏色的方法

    Android編程實(shí)現(xiàn)控件不同狀態(tài)文字顯示不同顏色的方法

    這篇文章主要介紹了Android編程實(shí)現(xiàn)控件不同狀態(tài)文字顯示不同顏色的方法,涉及Android針對(duì)控件布局文件屬性設(shè)置及狀態(tài)判定等相關(guān)技巧,需要的朋友可以參考下
    2016-02-02
  • Android繪制簡單條形圖

    Android繪制簡單條形圖

    這篇文章主要為大家詳細(xì)介紹了Android繪制簡單條形圖,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-08-08
  • Android實(shí)現(xiàn)懸浮窗效果

    Android實(shí)現(xiàn)懸浮窗效果

    這篇文章主要為大家詳細(xì)介紹了Android實(shí)現(xiàn)懸浮窗效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-04-04
  • Android評(píng)分控件RatingBar使用實(shí)例解析

    Android評(píng)分控件RatingBar使用實(shí)例解析

    這篇文章主要為大家詳細(xì)介紹了Android評(píng)分控件RatingBar使用實(shí)例,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2016-10-10
  • Android利用ContentProvider獲取本地?cái)?shù)據(jù)的方法

    Android利用ContentProvider獲取本地?cái)?shù)據(jù)的方法

    這篇文章主要介紹了Android利用ContentProvider獲取本地?cái)?shù)據(jù)的方法,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2018-04-04

最新評(píng)論

寻乌县| 林周县| 保山市| 千阳县| 榆树市| 永春县| 邹平县| 新建县| 南昌县| 吉隆县| 弥渡县| 香格里拉县| 易门县| 成安县| 安福县| 土默特右旗| 嘉鱼县| 瑞安市| 安达市| 秦安县| 鄂托克旗| 桂阳县| 定南县| 屏山县| 海门市| 庄浪县| 湾仔区| 聂荣县| 华亭县| 灌阳县| 密山市| 北碚区| 乌苏市| 南昌县| 依安县| 祁门县| 田东县| 利津县| 革吉县| 吉林市| 读书|