Android中的Serializable、Parcelable">Android中的Serializable、Parcelable
1652
2025-03-31
WebView的重要類
Android 4.4以后的 WebView 瀏覽器版本內核都是Chrome,這樣就解決了內核不統一的問題。
WebView顯示H5頁面存在一個很明顯的性能問題: WebView加載H5頁面很慢
加載H5頁面慢的原因有:
渲染速度慢:
(1)首先是JS本身的解析過程復雜、解析速度慢;
(2)前端頁面又涉及較多的JS代碼文件,疊加起來就造成了JS解析效率低;
(3)其次是Android機型碎片化,導致手機硬件設備的性能不可控,有些表現良好,有些表現就較差。
頁面資源加載慢,每加載一個H5頁面都會產生較多網絡請求:
(1)HTML的主URL請求;
(2)HTML引用外部的JS、CSS、字體文件、圖片文件等都會構造一個獨立的HTTP請求。
注:每次加載都會產生這么多的網絡請求,會相當耗費流量。
解決方案
可以通過以下三種方案來解決WebView的性能問題:
WebView的緩存機制
資源預加載
資源攔截
WebView的緩存機制
緩存就是離線存儲,即H5網頁加載后會存儲在緩存里。即使在無網絡連接的情況下也可以訪問網頁。
當再次訪問H5網頁時,可以直接使用已緩存的資源,不需要訪問服務器。緩存可以有效提高頁面的加載速度。
在WebView中緩存機制和緩存模式是兩個不同的概念。緩存機制是告訴瀏覽器如何將加載過的網頁數據保存到本地;緩存模式則是告訴WebView如何讀取之前保存到本地緩存里的網頁數據。
Android WebView 的緩存模式有以下4種:
LOAD_CACHE_ONLY: 不使用網絡,只讀取本地緩存數據。
LOAD_NO_CACHE: 不使用緩存,只從網絡獲取數據。
LOAD_DEFAULT: (默認)根據cache-control決定是否從網絡上取數據。
LOAD_CACHE_ELSE_NETWORK:只要本地有,無論是否過期,或者no-cache,都使用緩存中的數據。
在代碼中的具體使用:
// 如果導航類型沒有強制指定行為,那么當緩存中的資源是可用且還沒有過期的就使用緩存數據,否則就向原始服務器發送請求。(就是根據cache-control決定是否從網絡上取數據) webView.getSettings().setCacheMode(WebSettings.LOAD_DEFAULT); // 只要緩存中有的,就使用緩存中的數據,否則就向網絡原始服務器發請求 webView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK); // 無論如何都只使用緩存中的數據,沒有也不會向原始服務器發送請求 webView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ONLY); // 這種緩存模式就是告訴WebView不要使用緩存數據,直接向原始服務器請求數據 webView.getSettings().setCacheMode(WebSettings.LOAD_NO_CACHE);
1
2
3
4
5
6
7
8
Android WebView常用的緩存機制有:
瀏覽器緩存機制
Application Cache 緩存機制
Dom Storage 緩存機制
Indexed Database 緩存機制
1.瀏覽器緩存機制
瀏覽器緩存機制是瀏覽器內核的機制,Android WebView內置實現了,不需要我們額外設置或實現。
Android WebView會將靜態資源文件如JS、CSS、字體、圖片等文件緩存在以下路徑:
/data/data/包名/cache/org.chromium.android_webview
1
瀏覽器緩存機制是由服務器響應回來的HTTP協議頭信息來控制的。《HTTP協議頭》
瀏覽器根據 HTTP 協議頭里的 Cache-Control或Expires等字段來控制文件緩存的機制。
Cache-Control的可能取值及意義:
# 當資源一旦過期,如max-age已過期,緩存就不能用這些沒有與原始服務器成功驗證過的資源去響應后面的請求 Cache-Control: must-revalidate # 同must-revalidate一樣,只是它用于共享緩存如代理,同樣會被私有緩存忽略 Cache-Control: proxy-revalidate # 在使用緩存副本的內容前,強制提交請求到原始服務做驗證,檢查是否是最新的。 Cache-Control: no-cache # 無論服務端還是瀏覽器(客戶端)都不緩存客戶的請求或服務端的響應 Cache-Control: no-store # Content-Encoding, Content-Range, Content-Type 等頭信息,禁止代理修改 Cache-Control: no-transform # 表示響應的內容可以被緩存到任何地方,即使此響應是不能緩存的(如響應中沒有max-age或Expires等頭信息)也可以被緩存。 Cache-Control: public # 表示響應的內容只能為單個用戶(此處的用戶應該理解成瀏覽器的一個會話)使用,禁止將響應緩存到共享緩存區。一個私有的緩存可以緩存響應。換言之,當你返回這個頁面時,它會用私有緩存的內容來為你服務,除非私有緩存中沒有緩存任何內容,否則它不會向原始服務器發送請求。但當你關了它再開,它就要重新向服務器請求了。因為之前的私有緩存并不是當前再打開這個用戶實例的。 Cache-Control: private # 指定一個最大的時間,在此時間內緩存的資源都將被認為是最新的與Expires剛好相反,Expires是相對于發出請求的時間的。 Cache-Control: max-age=
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
Expires
Expires:
1
2
它表示資源的過期時間,相對請求而言的。但是請注意:如果HTTP響應頭信息里有Cache-Control指定了 max-age 或 s-maxage 命令,那么Expires頭將會被忽略。
上面解決了網頁數據緩存到本地的問題,使用本地緩存數據可以通過設置WebView的緩存模式來決定,如:
// 只要緩存中有的,就使用緩存中的數據,否則就向網絡原始服務器發請求 webView.getSettings().setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
1
2
2.Dom Storage 緩存機制
Dom Storage緩存機制通過在本地存儲Key - Value 對來提供緩存信息功能。存儲空間大( 5MB),在不同瀏覽器大小會有所不同,相比之下,Cookies 大小只有4KB。Dom Storage適用于存儲臨時的、簡單的數據的場景。
DOM Storage 分為 sessionStorage 和 localStorage; 二者使用方法基本相同,區別在于作用范圍不同:
(1)sessionStorage:是臨時性的,即存儲與頁面相關的數據,它在頁面關閉后無法使用
(2)localStorage:是持久性的,即保存的數據在頁面關閉后也可以使用。
啟用方式:
// 開啟DOM storage webView.getSettings().setDomStorageEnabled(true);
1
2
3. IndexedDB緩存機制
IndexedDB屬于NoSQL數據庫,通過存儲Key - Value對來提供緩存信息功能。類似于Dom Storage的存儲方式。適用于存儲復雜、數據量大的結構化數據的場景。
啟用方式:
// 只需設置支持JS就自動打開IndexedDB存儲機制 // Android 在4.4開始加入對 IndexedDB 的支持,只需打開允許 JS 執行的開關就好了。 webView.getSettings().setJavaScriptEnabled(true);
1
2
3
4.Application Cache 緩存機制
以文件為單位進行緩存。要使用AppCache,就必須在網頁的html標簽通過 manifest 屬性引用 manifest 文件,manifest 文件是一個普通文件,列出了需要緩存的文件。瀏覽器在首次加載 HTML 文件時,會解析 manifest 屬性,并讀取 manifest 文件,獲取 Section:CACHE MANIFEST 下要緩存的文件列表,再對文件進行緩存,網頁要按如下來寫:
// manifest 文件:就是下面以 appcache 結尾的文件,
...1
2
3
4
5
6
7
8
AppCache 在首次加載生成后,如果要更新被緩存的文件,需要更新 manifest 文件。
因為瀏覽器在下次加載時,除了會默認使用緩存外,還會在后臺檢查 manifest 文件有沒有修改。
發現有修改,就會重新獲取 manifest 文件,對 Section:CACHE MANIFEST 下文件列表檢查更新。
manifest 文件與緩存文件的檢查更新也遵守瀏覽器緩存機制。如果用戶手動清了 AppCache 緩存,下次加載時,瀏覽器會重新生成緩存,這也算是一種緩存的更新。
AppCache 的緩存文件,與瀏覽器的緩存文件分開存儲的,因為 AppCache 在本地有 5MB的空間限制。適用于存儲靜態文件如JS、CSS、字體文件等。AppCache 的緩存是作為對瀏覽器緩存機制的一種補充。
WebView配置如下:
webView.getSettings().setAppCachePath(appCachePath); webView.getSettings().setAllowFileAccess(true); webView.getSettings().setAppCacheEnabled(true); // 通過設置WebView的settings來實現 WebSettings settings = webView.getSettings(); // 1. 設置緩存路徑 String appCachePath = getApplicationContext().getCacheDir().getAbsolutePath()+"appcache/"; settings.setAppCachePath(appCachePath); // 2. 設置緩存大小 settings.setAppCacheMaxSize(Long.MAX_VALUE); // 3. 開啟Application Cache存儲機制 settings.setAppCacheEnabled(true); // 特別注意 // 每個 Application 只調用一次 WebSettings.setAppCachePath()和WebSettings.setAppCacheMaxSize()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
資源預加載
提早加載將需使用的H5頁面,即提前構建緩存,使用時直接取過來用即可。可以預加載WebView對象,減少使用時再初始化時的耗時,同時預加載H5資源,提前構建緩存。
預加載WebView對象:
預加載H5資源
在應用啟動后,在Application子類BaseApplication里初始化一個WebView對象時,直接開始網絡請求加載H5頁面,構建本地緩存,因為加載后就有緩存了。后續需打開H5頁面時就可以直接從本地緩存加載數據。
對于用Android WebView作為首頁的App,建議使用這種方案,它能有效提高首頁加載的效率。
我在GitHub上分享了一個Demo,感覺十分有趣。
我在BaseApplication里預加載“百度知道”。當app進入百度的首頁,爾后,關閉網絡,點擊“知道”,你會發現它居然成功打開了,因為它在本地緩存好了,這歸功于前面做H5頁面資源在BaseApplication中提供構建了。
構建自己的資源緩存
事先將更新頻率較低又常用又固定的H5靜態資源如Js文件、CSS文件、圖片等放到本地
攔截H5頁面的資源網絡請求,并對其進行檢測:如果檢測到本地具有相同的靜態資源,則直接從本地讀取,否則發送該資源的網絡請求到原始服務器獲取
具體實現
重寫WebViewClient 的 shouldInterceptRequest 方法,攔截H5頁面的資源網絡請求,并檢測所請求的資源在本地是否存在,存在就用本地資源代替,否則就讓其向服務器請求資源。
webView.setWebViewClient(new WebViewClient(){ @Override public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) { // 步驟1:攔截資源請求URL,并判斷URL里的資源的文件名是否包含事先緩存在本地的文件名 // 假設攔截到的資源請求URL為:https://mms-secr.cdn.bcebos.com/xuanfa1/wenzi1.png // 資源文件名為:wenzi1.png if (request.getUrl().toString().contains("wenzi1.png")) { // 步驟2:創建一個輸入流 InputStream ins = null; try { // 步驟3:獲得需要替換的資源(存放在assets文件夾里) // a. 先在app/src/main下創建一個assets文件夾 // b. 在assets文件夾里再創建一個images文件夾 // c. 在images文件夾放上我們要緩存的資源wenzi1.png ins = getApplicationContext().getAssets().open("images/wenzi1.png"); } catch (IOException e) { e.printStackTrace(); } // 步驟4:替換資源 // 參數1:http請求里該圖片的Content-Type,此處圖片為image/png // 參數2:編碼類型 // 參數3:存放著替換資源的輸入流 return new WebResourceResponse("image/png","utf-8", ins); } return super.shouldInterceptRequest(view, request); } });
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
Demo已在GitHub上了
這種緩存機制有效解決 H5頁面靜態資源加載速度慢和流量消耗多的問題。該方法只是更好地加快H5加載速度,即使失效,也不會對H5頁面產生任何負面影響。
上述放到本地的靜態資源的更新方式:
發布新版本安裝包apk時一并更新
增量更新:在用戶處于WIFI環境時讓服務器推送到本地,著名的微信應用就是采用小范圍更新本地資源的。
謝謝閱讀!
Android WebView
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。
版權聲明:本文內容由網絡用戶投稿,版權歸原作者所有,本站不擁有其著作權,亦不承擔相應法律責任。如果您發現本站中有涉嫌抄襲或描述失實的內容,請聯系我們jiasou666@gmail.com 處理,核實后本網站將在24小時內刪除侵權內容。