WebView·開車指南

WebView·開車指南

目錄

  • WebView簡(jiǎn)介
  • WebView基本使用
  • WebView常用方法
  • WebSettings
  • WebViewClient
  • WebChromeClient
  • JavaScript與WebView交互
  • WebView加載優(yōu)化
  • 駕照考試
  • 上路

WebView簡(jiǎn)介

為了方便開發(fā)者實(shí)現(xiàn)在app內(nèi)展示網(wǎng)頁(yè)并與網(wǎng)頁(yè)交互的需求软能,Android SDK提供了WebView組件心俗。它繼承自AbsoluteLayout碍拆,展示網(wǎng)頁(yè)的同時(shí)母谎,也可以在其中放入其他的子View。
現(xiàn)如今剧防,Hybrid應(yīng)用似乎占據(jù)的APP的主流類型植锉,那么關(guān)于WebView的使用就變得越發(fā)的重要。從Android 4.4(KitKat)開始峭拘,原本基于WebKit的WebView開始基于Chromium內(nèi)核俊庇,這一改動(dòng)大大提升了WebView組件的性能以及對(duì)HTML5,CSS3,JavaScript的支持。不過(guò)它的API卻沒(méi)有很大的改動(dòng)鸡挠,在兼容低版本的同時(shí)只引進(jìn)了少部分新的API辉饱,并不需要你做很大的改動(dòng)。不過(guò)有幾點(diǎn)改變需要注意拣展,但我嘗試著翻譯了下彭沼,發(fā)現(xiàn)還是英文原文說(shuō)得好,所以我貼鏈接吧~~~
Migrating to WebView in Android 4.4
在WebView中备埃,有幾個(gè)地方是我們可以使用來(lái)定制我們的WebView各種行為的姓惑,分別是:WebSettingsJavaScriptInterface按脚、WebViewClient以及WebChromeClient于毙。這些我都會(huì)在接下來(lái)的文章中一一介紹。

WebView基本使用

下面簡(jiǎn)單介紹下WebView的基本使用:
首先新建一個(gè)工程辅搬,在layout文件里放入一個(gè)WebView控件(當(dāng)然也可以通過(guò)Java代碼動(dòng)態(tài)放入唯沮,這里不演示了)

 <?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

<WebView
    android:id="@+id/web_view"
    android:layout_width="match_parent"
    android:layout_height="match_parent"/>
</LinearLayout>

然后在Activity的onCreate方法里寫入如下代碼:

String url = "https://www.google.com";
WebView webView = (WebView) findViewById(R.id.web_view);
webView.loadUrl(url);

接著在AndroidManifest聲明訪問(wèn)網(wǎng)絡(luò)的權(quán)限:

  <uses-permission android:name="android.permission.INTERNET"/>

就,完事了~
這時(shí)運(yùn)行app伞辛,它已經(jīng)可以訪問(wèn)指定地址的網(wǎng)頁(yè)了烂翰。
上面提到了WebView繼承自AbsoluteLayout夯缺,可以在其中放入一些子View蚤氏,那也順手來(lái)一下。
Layout文件改為:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <WebView
      android:id="@+id/web_view"
      android:layout_width="match_parent"
      android:layout_height="match_parent">

      <Button
          android:id="@+id/button"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:layout_x="170dp"
          android:layout_y="400dp"
          android:background="@color/colorAccent"
      android:text="@string/app_name" />
  </WebView>
</LinearLayout>

Activity的onCreate里加上:

Button button = (Button) findViewById(R.id.button);
button.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View view) {
        Toast.makeText(getApplicationContext(), "系好安全帶!", Toast.LENGTH_SHORT).show();
    }
});

這時(shí)踊兜,運(yùn)行app竿滨,里面就會(huì)多出一個(gè)Button~ 但如果你真的運(yùn)行的話,你就會(huì)發(fā)現(xiàn)捏境,app會(huì)自動(dòng)跳到瀏覽器并打開指定的網(wǎng)頁(yè)于游,而并非在app內(nèi)展示網(wǎng)頁(yè),那這就與我們的初衷背道而馳了垫言,那么要如何實(shí)現(xiàn)網(wǎng)頁(yè)在App內(nèi)打開呢?這就引出了下面的章節(jié)會(huì)提到的東西:WebViewClient贰剥。我先將代碼貼出,具體實(shí)現(xiàn)原理留到下節(jié)說(shuō)明筷频。

最終XML布局就如上面那樣蚌成,Java代碼(最終)如下:

public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    String url = "https://www.google.com";
    WebView webView = (WebView) findViewById(R.id.web_view);
    webView.loadUrl(url);

    webView.setWebViewClient(new WebViewClient() {
        @Override
        public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
            view.loadUrl(request.toString());
            return true;
        }
    });

    Button button = (Button) findViewById(R.id.button);
    button.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            Toast.makeText(getApplicationContext(), "系好安全帶!", Toast.LENGTH_SHORT).show();
        }
    });
  }
}

WebView簡(jiǎn)介

接下來(lái)再介紹一些WebView的常用方法前痘,具體演示會(huì)在后面章節(jié)的代碼里統(tǒng)一展示。

String getUrl():獲取當(dāng)前頁(yè)面的URL担忧。

reload():重新reload當(dāng)前的URL芹缔,即刷新。

boolean canGoBack():用來(lái)確認(rèn)WebView里是否還有可回退的歷史記錄瓶盛。通常我們會(huì)在WebView里重寫返回鍵的點(diǎn)擊事件最欠,通過(guò)該方法判斷WebView里是否還有歷史記錄,若有則返回上一頁(yè)惩猫。

boolean canGoForward():用來(lái)確認(rèn)WebView是否還有可向前的歷史記錄芝硬。

boolean canGoBackOrForward(int steps):以當(dāng)前的頁(yè)面為起始點(diǎn),用來(lái)確認(rèn)WebView的歷史記錄是否足以后退或前進(jìn)給定的步數(shù)帆锋,正數(shù)為前進(jìn)吵取,負(fù)數(shù)為后退。

goBack():在WebView歷史記錄后退到上一項(xiàng)锯厢。

goForward():在WebView歷史記錄里前進(jìn)到下一項(xiàng)皮官。

goBackOrForward(int steps):以當(dāng)前頁(yè)面為起始點(diǎn),前進(jìn)或后退歷史記錄中指定的步數(shù)实辑,正數(shù)為前進(jìn)捺氢,負(fù)數(shù)為后退。

clearCache(boolean includeDiskFiles):清空網(wǎng)頁(yè)訪問(wèn)留下的緩存數(shù)據(jù)剪撬。需要注意的時(shí)摄乒,由于緩存是全局的,所以只要是WebView用到的緩存都會(huì)被清空残黑,即便其他地方也會(huì)使用到馍佑。該方法接受一個(gè)參數(shù),從命名即可看出作用梨水。若設(shè)為false拭荤,則只清空內(nèi)存里的資源緩存,而不清空磁盤里的疫诽。

clearHistory():清除當(dāng)前webview訪問(wèn)的歷史記錄舅世。

clearFormData():清除自動(dòng)完成填充的表單數(shù)據(jù)。需要注意的是奇徒,該方法僅僅清除當(dāng)前表單域自動(dòng)完成填充的表單數(shù)據(jù)雏亚,并不會(huì)清除WebView存儲(chǔ)到本地的數(shù)據(jù)。

onPause():當(dāng)頁(yè)面被失去焦點(diǎn)被切換到后臺(tái)不可見狀態(tài)摩钙,需要執(zhí)行onPause操作罢低,該操作會(huì)通知內(nèi)核安全地暫停所有動(dòng)作,比如動(dòng)畫的執(zhí)行或定位的獲取等胖笛。需要注意的是該方法并不會(huì)暫停JavaScript的執(zhí)行网持,若要暫停JavaScript的執(zhí)行請(qǐng)使用接下來(lái)的這個(gè)方法宜肉。

onResume():在先前調(diào)用onPause()后,我們可以調(diào)用該方法來(lái)恢復(fù)WebView的運(yùn)行翎碑。

pauseTimers():該方法面向全局整個(gè)應(yīng)用程序的webview谬返,它會(huì)暫停所有webview的
layout,parsing日杈,JavaScript Timer遣铝。當(dāng)程序進(jìn)入后臺(tái)時(shí),該方法的調(diào)用可以降低CPU功耗莉擒。
resumeTimers():恢復(fù)pauseTimers時(shí)的所有操作酿炸。

destroy():銷毀WebView。需要注意的是:這個(gè)方法的調(diào)用應(yīng)在WebView從父容器中被remove掉之后涨冀。我們可以手動(dòng)地調(diào)用

rootLayout.removeView(webView);
webView.destroy();

getScrollY():該方法返回的當(dāng)前可見區(qū)域的頂端距整個(gè)頁(yè)面頂端的距離填硕,也就是當(dāng)前內(nèi)容滾動(dòng)的距離。

getHeight():方法都返回當(dāng)前WebView這個(gè)容器的高度鹿鳖。其實(shí)以上兩個(gè)方法都屬于View扁眯。

getContentHeight():該方法返回整個(gè)HTML頁(yè)面的高度,但該高度值并不等同于當(dāng)前整個(gè)頁(yè)面的高度翅帜,因?yàn)閃ebView有縮放功能姻檀, 所以當(dāng)前整個(gè)頁(yè)面的高度實(shí)際上應(yīng)該是原始HTML的高度再乘上縮放比例。因此涝滴,準(zhǔn)確的判斷方法應(yīng)該是

if (webView.getContentHeight() * webView.getScale() == (webView.getHeight() + webView.getScrollY())) {
//已經(jīng)處于底端
}

if(webView.getScrollY() == 0){
//處于頂端
}

pageUp(boolean top):將WebView展示的頁(yè)面滑動(dòng)至頂部绣版。

pageDown(boolean bottom):將WebView展示的頁(yè)面滑動(dòng)至底部。

WebSettings

WebSettings是用來(lái)管理WebView配置的類歼疮。當(dāng)WebView第一次創(chuàng)建時(shí)杂抽,內(nèi)部會(huì)包含一個(gè)默認(rèn)配置的集合。若我們想更改這些配置韩脏,便可以通過(guò)WebSettings里的方法來(lái)進(jìn)行設(shè)置缩麸。

WebSettings對(duì)象可以通過(guò)WebView.getSettings()獲得,它的生命周期是與它的WebView本身息息相關(guān)的骤素,如果WebView被銷毀了匙睹,那么任何由WebSettings調(diào)用的方法也同樣不能使用愚屁。

獲取WebSettings對(duì)象

 WebSettings webSettings = webView.getSettings();

WebSettings常用方法

(幾乎所有的set方法都有相應(yīng)的get方法济竹,這里就只介紹set了。另霎槐,所有未寫方法返回值類型的皆為空類型)

- setJavaScriptEnabled(boolean flag):設(shè)置WebView是否可以運(yùn)行JavaScript送浊。

- setJavaScriptCanOpenWindowsAutomatically(boolean flag):設(shè)置WebView是否可以由JavaScript自動(dòng)打開窗口,默認(rèn)為false丘跌,通常與JavaScript的window.open()配合使用袭景。

- setAllowFileAccess(boolean allow):啟用或禁用WebView訪問(wèn)文件數(shù)據(jù)唁桩。

- setBlockNetworkImage(boolean flag):禁止或允許WebView從網(wǎng)絡(luò)上加載圖片。需要注意的是耸棒,如果設(shè)置是從禁止到允許的轉(zhuǎn)變的話荒澡,圖片數(shù)據(jù)并不會(huì)在設(shè)置改變后立刻去獲取,而是在WebView調(diào)用reload()的時(shí)候才會(huì)生效与殃。
這個(gè)時(shí)候单山,需要確保這個(gè)app擁有訪問(wèn)Internet的權(quán)限,否則會(huì)拋出安全異常幅疼。
通常沒(méi)有禁止圖片加載的需求的時(shí)候米奸,完全不用管這個(gè)方法,因?yàn)楫?dāng)我們的app擁有訪問(wèn)Internet的權(quán)限時(shí)爽篷,這個(gè)flag的默認(rèn)值就是false悴晰。

- setSupportZoom(boolean support):設(shè)置是否支持縮放。

- setBuiltInZoomControls(boolean enabled):顯示或不顯示縮放按鈕(wap網(wǎng)頁(yè)不支持)逐工。

- setSupportMultipleWindows(boolean support):設(shè)置WebView是否支持多窗口铡溪。

- setLayoutAlgorithm(WebSettings.LayoutAlgorithm l):指定WebView的頁(yè)面布局顯示形式,調(diào)用該方法會(huì)引起頁(yè)面重繪泪喊。默認(rèn)值為L(zhǎng)ayoutAlgorithm#NARROW_COLUMNS佃却。

- setNeedInitialFocus(boolean flag):通知WebView是否需要設(shè)置一個(gè)節(jié)點(diǎn)獲取焦點(diǎn)當(dāng)WebView#requestFocus(int,android.graphics.Rect)被調(diào)用時(shí),默認(rèn)為true窘俺。

- setAppCacheEnabled(boolean flag):啟用或禁用應(yīng)用緩存饲帅。

- setAppCachePath(String appCachePath):設(shè)置應(yīng)用緩存路徑,這個(gè)路徑必須是可以讓app寫入文件的瘤泪。該方法應(yīng)該只被調(diào)用一次灶泵,重復(fù)調(diào)用會(huì)被無(wú)視~

- setCacheMode(int mode):用來(lái)設(shè)置WebView的緩存模式。當(dāng)我們加載頁(yè)面或從上一個(gè)頁(yè)面返回的時(shí)候对途,會(huì)按照設(shè)置的緩存模式去檢查并使用(或不使用)緩存赦邻。

緩存模式有四種:

LOAD_DEFAULT:默認(rèn)的緩存使用模式。在進(jìn)行頁(yè)面前進(jìn)或后退的操作時(shí)实檀,如果緩存可用并未過(guò)期就優(yōu)先加載緩存惶洲,否則從網(wǎng)絡(luò)上加載數(shù)據(jù)。這樣可以減少頁(yè)面的網(wǎng)絡(luò)請(qǐng)求次數(shù)膳犹。

LOAD_CACHE_ELSE_NETWORK:只要緩存可用就加載緩存恬吕,哪怕它們已經(jīng)過(guò)期失效。如果緩存不可用就從網(wǎng)絡(luò)上加載數(shù)據(jù)须床。

LOAD_NO_CACHE:不加載緩存铐料,只從網(wǎng)絡(luò)加載數(shù)據(jù)。

LOAD_CACHE_ONLY:不從網(wǎng)絡(luò)加載數(shù)據(jù),只從緩存加載數(shù)據(jù)钠惩。

通常我們可以根據(jù)網(wǎng)絡(luò)情況將這幾種模式結(jié)合使用柒凉,比如有網(wǎng)的時(shí)候使用LOAD_DEFAULT,離線時(shí)使用LOAD_CACHE_ONLY篓跛、LOAD_CACHE_ELSE_NETWORK膝捞,讓用戶不至于在離線時(shí)啥都看不到。
setDatabaseEnabled(boolean flag):啟用或禁用數(shù)據(jù)庫(kù)緩存愧沟。

setDomStorageEnabled(boolean flag):啟用或禁用DOM緩存绑警。

setUserAgentString(String ua):設(shè)置WebView的UserAgent值。

setDefaultEncodingName(String encoding):設(shè)置編碼格式央渣,通常都設(shè)為“UTF-8”计盒。

setStandardFontFamily(String font):設(shè)置標(biāo)準(zhǔn)的字體族,默認(rèn)“sans-serif”芽丹。

setCursiveFontFamily:設(shè)置草書字體族北启,默認(rèn)“cursive”。

setFantasyFontFamily:設(shè)置CursiveFont字體族拔第,默認(rèn)“cursive”咕村。

setFixedFontFamily:設(shè)置混合字體族,默認(rèn)“monospace”蚊俺。

setSansSerifFontFamily:設(shè)置梵文字體族懈涛,默認(rèn)“sans-serif”。

setSerifFontFamily:設(shè)置襯線字體族泳猬,默認(rèn)“sans-serif”

setDefaultFixedFontSize(int size):設(shè)置默認(rèn)填充字體大小批钠,默認(rèn)16,取值區(qū)間為[1-72]得封,超過(guò)范圍埋心,使用其上限值。

setDefaultFontSize(int size):設(shè)置默認(rèn)字體大小忙上,默認(rèn)16拷呆,取值區(qū)間[1-72],超過(guò)范圍疫粥,使用其上限值茬斧。

setMinimumFontSize:設(shè)置最小字體,默認(rèn)8. 取值區(qū)間[1-72]梗逮,超過(guò)范圍项秉,使用其上限值。

setMinimumLogicalFontSize:設(shè)置最小邏輯字體库糠,默認(rèn)8. 取值區(qū)間[1-72]伙狐,超過(guò)范圍,使用其上限值瞬欧。

以上就是一些WebSettings的常用方法贷屎,具體的使用以及一些緩存的問(wèn)題會(huì)在接下來(lái)的代碼以及文章中有更加直觀的說(shuō)明。

WebViewClient

從名字上不難理解艘虎,這個(gè)類就像WebView的委托人一樣唉侄,是幫助WebView處理各種通知和請(qǐng)求事件的,我們可以稱他為WebView的“內(nèi)政大臣”野建。

onLoadResource(WebView view, String url):該方法在加載頁(yè)面資源時(shí)會(huì)回調(diào)属划,每一個(gè)資源(比如圖片)的加載都會(huì)調(diào)用一次。

onPageStarted(WebView view, String url, Bitmap favicon):該方法在WebView開始加載頁(yè)面且僅在Main frame loading(即整頁(yè)加載)時(shí)回調(diào),一次Main frame的加載只會(huì)回調(diào)該方法一次。我們可以在這個(gè)方法里設(shè)定開啟一個(gè)加載的動(dòng)畫汗唱,告訴用戶程序在等待網(wǎng)絡(luò)的響應(yīng)碘勉。

onPageFinished(WebView view, String url):該方法只在WebView完成一個(gè)頁(yè)面加載時(shí)調(diào)用一次(同樣也只在Main frame loading時(shí)調(diào)用),我們可以可以在此時(shí)關(guān)閉加載動(dòng)畫积糯,進(jìn)行其他操作。

onReceivedError(WebView view, WebResourceRequest request, WebResourceError error):該方法在web頁(yè)面加載錯(cuò)誤時(shí)回調(diào),這些錯(cuò)誤通常都是由無(wú)法與服務(wù)器正常連接引起的明肮,最常見的就是網(wǎng)絡(luò)問(wèn)題。 這個(gè)方法有兩個(gè)地方需要注意:

1.這個(gè)方法只在與服務(wù)器無(wú)法正常連接時(shí)調(diào)用缭付,類似于服務(wù)器返回錯(cuò)誤碼的那種錯(cuò)誤(即HTTP ERROR)柿估,該方法是不會(huì)回調(diào)的,因?yàn)槟阋呀?jīng)和服務(wù)器正常連接上了(全怪官方文檔(︶^︶))陷猫;

2.這個(gè)方法是新版本的onReceivedError()方法秫舌,從API23開始引進(jìn),與舊方法onReceivedError(WebView view,int errorCode,String description,String failingUrl)不同的是绣檬,新方法在頁(yè)面局部加載發(fā)生錯(cuò)誤時(shí)也會(huì)被調(diào)用(比如頁(yè)面里兩個(gè)子Tab或者一張圖片)舅巷。這就意味著該方法的調(diào)用頻率可能會(huì)更加頻繁,所以我們應(yīng)該在該方法里執(zhí)行盡量少的操作河咽。

onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse):上一個(gè)方法提到onReceivedError并不會(huì)在服務(wù)器返回錯(cuò)誤碼時(shí)被回調(diào)钠右,那么當(dāng)我們需要捕捉HTTP ERROR并進(jìn)行相應(yīng)操作時(shí)應(yīng)該怎么辦呢?API23便引入了該方法忘蟹。當(dāng)服務(wù)器返回一個(gè)HTTP ERROR并且它的status code>=400時(shí)飒房,該方法便會(huì)回調(diào)。這個(gè)方法的作用域并不局限于Main Frame媚值,任何資源的加載引發(fā)HTTP ERROR都會(huì)引起該方法的回調(diào)狠毯,所以我們也應(yīng)該在該方法里執(zhí)行盡量少的操作,只進(jìn)行非常必要的錯(cuò)誤處理等褥芒。

onReceivedSslError(WebView view, SslErrorHandler handler, SslError error):當(dāng)WebView加載某個(gè)資源引發(fā)SSL錯(cuò)誤時(shí)會(huì)回調(diào)該方法嚼松,這時(shí)WebView要么執(zhí)行handler.cancel()取消加載嫡良,要么執(zhí)行handler.proceed()方法繼續(xù)加載(默認(rèn)為cancel)。需要注意的是献酗,這個(gè)決定可能會(huì)被保留并在將來(lái)再次遇到SSL錯(cuò)誤時(shí)執(zhí)行同樣的操作寝受。

WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request):當(dāng)WebView需要請(qǐng)求某個(gè)數(shù)據(jù)時(shí),這個(gè)方法可以攔截該請(qǐng)求來(lái)告知app并且允許app本身返回一個(gè)數(shù)據(jù)來(lái)替代我們?cè)疽虞d的數(shù)據(jù)罕偎。

比如你對(duì)web的某個(gè)js做了本地緩存很澄,希望在加載該js時(shí)不再去請(qǐng)求服務(wù)器而是可以直接讀取本地緩存的js,這個(gè)方法就可以幫助你完成這個(gè)需求颜及。你可以寫一些邏輯檢測(cè)這個(gè)request甩苛,并返回相應(yīng)的數(shù)據(jù),你返回的數(shù)據(jù)就會(huì)被WebView使用俏站,如果你返回null讯蒲,WebView會(huì)繼續(xù)向服務(wù)器請(qǐng)求。

boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request):哈~ 終于到了這個(gè)方法肄扎,在最開始的基礎(chǔ)演示時(shí)我們用到了這個(gè)方法爱葵。從實(shí)踐中我們知道,當(dāng)我們沒(méi)有給WebView提供WebViewClient時(shí)反浓,WebView如果要加載一個(gè)url會(huì)向ActivityManager尋求一個(gè)適合的處理者來(lái)加載該url(比如系統(tǒng)自帶的瀏覽器)萌丈,這通常是我們不想看到的。于是我們需要給WebView提供一個(gè)WebViewClient雷则,并重寫該方法返回true來(lái)告知WebView url的加載就在app中進(jìn)行辆雾。這時(shí)便可以實(shí)現(xiàn)在app內(nèi)訪問(wèn)網(wǎng)頁(yè)。

onScaleChanged(WebView view, float oldScale, float newScale):當(dāng)WebView得頁(yè)面Scale值發(fā)生改變時(shí)回調(diào)月劈。

boolean shouldOverrideKeyEvent(WebView view, KeyEvent event):默認(rèn)值為false度迂,重寫此方法并return true可以讓我們?cè)赪ebView內(nèi)處理按鍵事件。

WebChromeClient

如果說(shuō)WebViewClient是幫助WebView處理各種通知猜揪、請(qǐng)求事件的“內(nèi)政大臣”的話惭墓,那么WebChromeClient就是輔助WebView處理Javascript的對(duì)話框,網(wǎng)站圖標(biāo)而姐,網(wǎng)站title腊凶,加載進(jìn)度等偏外部事件的“外交大臣”。

onProgressChanged(WebView view, int newProgress):當(dāng)頁(yè)面加載的進(jìn)度發(fā)生改變時(shí)回調(diào)拴念,用來(lái)告知主程序當(dāng)前頁(yè)面的加載進(jìn)度钧萍。

onReceivedIcon(WebView view, Bitmap icon):用來(lái)接收web頁(yè)面的icon,我們可以在這里將該頁(yè)面的icon設(shè)置到Toolbar政鼠。

onReceivedTitle(WebView view, String title):用來(lái)接收web頁(yè)面的title风瘦,我們可以在這里將頁(yè)面的title設(shè)置到Toolbar。

以下兩個(gè)方法是為了支持web頁(yè)面進(jìn)入全屏模式而存在的(比如播放視頻)公般,如果不實(shí)現(xiàn)這兩個(gè)方法万搔,該web上的內(nèi)容便不能進(jìn)入全屏模式胡桨。

onShowCustomView(View view, WebChromeClient.CustomViewCallback callback):該方法在當(dāng)前頁(yè)面進(jìn)入全屏模式時(shí)回調(diào),主程序必須提供一個(gè)包含當(dāng)前web內(nèi)容(視頻 or Something)的自定義的View瞬雹。

onHideCustomView():該方法在當(dāng)前頁(yè)面退出全屏模式時(shí)回調(diào)昧谊,主程序應(yīng)在這時(shí)隱藏之前show出來(lái)的View。

Bitmap getDefaultVideoPoster():當(dāng)我們的Web頁(yè)面包含視頻時(shí)挖炬,我們可以在HTML里為它設(shè)置一個(gè)預(yù)覽圖揽浙,WebView會(huì)在繪制頁(yè)面時(shí)根據(jù)它的寬高為它布局状婶。而當(dāng)我們處于弱網(wǎng)狀態(tài)下時(shí)意敛,我們沒(méi)有比較快的獲取該圖片,那WebView繪制頁(yè)面時(shí)的gitWidth()方法就會(huì)報(bào)出空指針異常~ 于是app就crash了膛虫。草姻。

這時(shí)我們就需要重寫該方法,在我們尚未獲取web頁(yè)面上的video預(yù)覽圖時(shí)稍刀,給予它一個(gè)本地的圖片撩独,避免空指針的發(fā)生。

View getVideoLoadingProgressView():重寫該方法可以在視頻loading時(shí)給予一個(gè)自定義的View账月,可以是加載圓環(huán) or something综膀。

boolean onJsAlert(WebView view, String url, String message, JsResult result):處理Javascript中的Alert對(duì)話框。

boolean onJsPrompt(WebView view, String url, String message, String defaultValue, JsPromptResult result):處理Javascript中的Prompt對(duì)話框局齿。

boolean onJsConfirm(WebView view, String url, String message, JsResult result):處理Javascript中的Confirm對(duì)話框

boolean onShowFileChooser(WebView webView, ValueCallback filePathCallback, WebChromeClient.FileChooserParams fileChooserParams):該方法在用戶進(jìn)行了web上某個(gè)需要上傳文件的操作時(shí)回調(diào)剧劝。我們應(yīng)該在這里打開一個(gè)文件選擇器,如果要取消這個(gè)請(qǐng)求我們可以調(diào)用filePathCallback.onReceiveValue(null)并返回true抓歼。

onPermissionRequest(PermissionRequest request):該方法在web頁(yè)面請(qǐng)求某個(gè)尚未被允許或拒絕的權(quán)限時(shí)回調(diào)讥此,主程序在此時(shí)調(diào)用grant(String [])或deny()方法。如果該方法沒(méi)有被重寫谣妻,則默認(rèn)拒絕web頁(yè)面請(qǐng)求的權(quán)限萄喳。

onPermissionRequestCanceled(PermissionRequest request):該方法在web權(quán)限申請(qǐng)權(quán)限被取消時(shí)回調(diào),這時(shí)應(yīng)該隱藏任何與之相關(guān)的UI界面蹋半。

Js與WebView交互

既然嗨鳥應(yīng)用大行其道他巨,那么毫無(wú)疑問(wèn)Android與JavaScript的交互我們也必須了解清楚,下面來(lái)介紹一下JavaScript與Android是如何互相調(diào)用的减江。

利用WebView調(diào)用網(wǎng)頁(yè)上的JavaScript代碼

在WebView中調(diào)用Js的基本格式為webView.loadUrl("javascript:methodName(parameterValues)");

現(xiàn)有以下這段JavaScript代碼

function readyToGo() {
  alert("Hello")
    }

  function alertMessage(message) {
  alert(message)
  }

    function getYourCar(){
  return "Car";
  }

1. WebView調(diào)用JavaScript無(wú)參無(wú)返回值函數(shù)

String call = "javascript:readyToGo()";
webView.loadUrl(call);

2. WebView調(diào)用JavScript有參無(wú)返回值函數(shù)

String call = "javascript:alertMessage(\"" + "content" + "\")";
webView.loadUrl(call);

3. WebView調(diào)用JavaScript有參數(shù)有返回值的函數(shù)

@TargetApi(Build.VERSION_CODES.KITKAT)
private void evaluateJavaScript(WebView webView){
webView.evaluateJavascript("getYourCar()", new ValueCallback<String>() {
    @Override
    public void onReceiveValue(String s) {
        Log.d("findCar",s);
    }
  });
}

JavaScript通過(guò)WebView調(diào)用Java代碼

從API19開始闻蛀,Android提供了@JavascriptInterface對(duì)象注解的方式來(lái)建立起Javascript對(duì)象和Android原生對(duì)象的綁定,提供給JavScript調(diào)用的函數(shù)必須帶有@JavascriptInterface您市。

演示一 JavaScript調(diào)用Android Toast方法

1. 編寫Java原生方法并用使用@JavascriptInterface注解

 @JavascriptInterface
public void show(String s){
    Toast.makeText(getApplication(), s, Toast.LENGTH_SHORT).show();
}

2.注冊(cè)JavaScriptInterface

webView.addJavascriptInterface(this, "android");
addJavascriptInterface的作用是把this所代表的類映射為JavaScript中的android對(duì)象觉痛。

3.編寫JavaScript代碼

function toastClick(){
     window.android.show("JavaScript called~!");
 }

演示二 JavaScript調(diào)用有返回值的Java方法

1.定義一個(gè)帶返回值的Java方法,并使用@JavaInterface:

@JavaInterface
public String getMessage(){
    return "Hello,boy~";
}

2.添加JavaScript的映射

webView.addJavaScriptInterface(this,"Android");

3.通過(guò)JavaScript調(diào)用Java方法

function showHello(){
    var str=window.Android.getMessage();
    console.log(str);
}

以上就是Js與WebView交互的一些介紹茵休,希望能對(duì)你有幫助薪棒。

WebView加載優(yōu)化

當(dāng)WebView的使用頻率變得頻繁的時(shí)候手蝎,對(duì)于其各方面的優(yōu)化就變得逐漸重要了起來(lái)±荆可以知道的是棵介,我們每加載一個(gè) H5頁(yè)面,都會(huì)有很多的請(qǐng)求吧史。除了HTML主URL自身的請(qǐng)求外邮辽,HTML外部引用的 JS、CSS贸营、字體文件吨述、圖片都是一個(gè)個(gè)獨(dú)立的HTTP 請(qǐng)求,雖然請(qǐng)求是并發(fā)的钞脂,但當(dāng)網(wǎng)頁(yè)整體數(shù)量達(dá)到一定程度的時(shí)候揣云,再加上瀏覽器解析、渲染的時(shí)間冰啃,Web整體的加載時(shí)間變得很長(zhǎng)邓夕。同時(shí)請(qǐng)求文件越多,消耗的流量也會(huì)越多阎毅。那么對(duì)于加載的優(yōu)化就變得非常重要焚刚,這方面的經(jīng)驗(yàn)我也沒(méi)有什么別的,大概三個(gè)方面:

一個(gè)扇调,就是資源本地化的問(wèn)題

首先可以明確的是矿咕,以目前的網(wǎng)絡(luò)條件,通過(guò)網(wǎng)絡(luò)去服務(wù)器獲取資源的速度是遠(yuǎn)遠(yuǎn)比不上從本地讀取的肃拜。談?wù)摳鞣N優(yōu)化策略其實(shí)恰恰忽略了“需要加載”才是阻擋速度提升的最大絆腳石痴腌。所以我們的思路一,就是將一些較重的資源比如js燃领、css士聪、圖片甚至HTML本身進(jìn)行本地化處理,在每次加載到這些資源的時(shí)候猛蔽,從本地讀取進(jìn)行加載剥悟,可以簡(jiǎn)單記憶為“存·取·更”。

具體實(shí)現(xiàn)思路為:

  • “存”——將上述重量級(jí)資源打包進(jìn)apk文件曼库,每次加載相應(yīng)文件時(shí)時(shí)從本地取即可区岗。也可不打包,在第一次加載時(shí)以及接下來(lái)的若干間隔時(shí)間里動(dòng)態(tài)下載存儲(chǔ)毁枯,將所有的資源文件都存在Android的asset目錄下慈缔;
  • “取”——重寫WebViewClient的WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request)方法,通過(guò)一定的判別方法(例如正則表達(dá)式)攔截相應(yīng)的請(qǐng)求种玛,從本地讀取相應(yīng)資源并返回藐鹤;
  • “更”——建立起Cache Control機(jī)制瓤檐,定期或使用API通知的形式控制本地資源的更新,保證本地資源是最新和可用的娱节。
    這里附上一篇博客鏈接挠蛉,非常棒可供參考:caching-web-resources-in-the-android-device

第二個(gè),就是緩存的問(wèn)題

倘若你不采用或不完全采用第一條資源本地化的思路肄满,那么你的WebView緩存是必須要開啟的(雖然這一思路和第一條有重合的地方)谴古。

WebSettings settings = webView.getSettings();
settings.setAppCacheEnabled(true);
settings.setDatabaseEnabled(true);
settings.setDomStorageEnabled(true);//開啟DOM緩存
settings.setCacheMode(WebSettings.LOAD_DEFAULT);

在網(wǎng)絡(luò)正常時(shí),采用默認(rèn)緩存策略稠歉,在緩存可獲取并且沒(méi)有過(guò)期的情況下加載緩存掰担,否則通過(guò)網(wǎng)絡(luò)獲取資源以減少頁(yè)面的網(wǎng)絡(luò)請(qǐng)求次數(shù)。

這里值得提起的是轧抗,我們經(jīng)常在app里用WebView展示頁(yè)面時(shí)恩敌,并不想讓用戶覺(jué)得他是在訪問(wèn)一個(gè)網(wǎng)頁(yè)瞬测。因?yàn)樘热粑覀兊腶pp里網(wǎng)頁(yè)非常多横媚,而我們給用戶的感覺(jué)又都像在訪問(wèn)網(wǎng)頁(yè)的話,我們的app便失去了意義月趟。(我的意思是為什么用戶不直接使用瀏覽器呢灯蝴?)

所以這時(shí),離線緩存的問(wèn)題就值得我們注意孝宗。我們需要讓用戶在沒(méi)有網(wǎng)的時(shí)候穷躁,依然能夠操作我們的app,而不是面對(duì)一個(gè)和瀏覽器里的網(wǎng)絡(luò)錯(cuò)誤一樣的頁(yè)面因妇,哪怕他能進(jìn)行的操作十分有限问潭。

這里我的思路是,在開啟緩存的前提下婚被,WebView在加載頁(yè)面時(shí)檢測(cè)網(wǎng)絡(luò)變化狡忙,倘若在加載頁(yè)面時(shí)用戶的網(wǎng)絡(luò)突然斷掉,我們應(yīng)當(dāng)更改WebView的緩存策略址芯。

ConnectivityManager connectivityManager = (ConnectivityManager)getSystemService(Context.CONNECTIVITY_SERVICE);
NetworkInfo networkInfo = connectivityManager.getActiveNetworkInfo();
if(networkInfo.isAvailable()) {
    settings.setCacheMode(WebSettings.LOAD_DEFAULT);//網(wǎng)絡(luò)正常時(shí)使用默認(rèn)緩存策略
} else {
    settings.setCacheMode(WebSettings.LOAD_CACHE_ONLY);//網(wǎng)絡(luò)不可用時(shí)只使用緩存
}

既然有緩存灾茁,就要有緩存控制,與一相似的是我們也要建立緩存控制機(jī)制谷炸,定期或接受服務(wù)器通知來(lái)進(jìn)行緩存的清空或更新北专。

第三個(gè),就是延遲加載和執(zhí)行js

在WebView中旬陡,onPageFinished()的回調(diào)意味著頁(yè)面加載的完成拓颓。但該方法會(huì)在JavScript腳本執(zhí)行完成后才會(huì)觸發(fā),倘若我們要加載的頁(yè)面使用了JQuery描孟,會(huì)在處理完DOM對(duì)象驶睦,執(zhí)行完$(document).ready(function() {})后才會(huì)渲染并顯示頁(yè)面腻格。這是不可接受的,所以我們需要對(duì)Js進(jìn)行延遲加載啥繁,當(dāng)然這部分是Web前端的工作菜职。

如果說(shuō)還有什么

那就是JsBridge一律不得濫用,這個(gè)對(duì)頁(yè)面加載的完成速度是有很大影響的旗闽,倘若一個(gè)頁(yè)面很多操作都通過(guò)JSbridge來(lái)控制酬核,再怎么優(yōu)化也無(wú)濟(jì)于事(因?yàn)楫吘褂心敲炊嗖僮饕獙?shí)際執(zhí)行)。同時(shí)要注意的是适室,不管你是否對(duì)資源進(jìn)行緩存嫡意,都請(qǐng)將資源在服務(wù)器端進(jìn)行壓縮。因?yàn)闊o(wú)論是資源的獲取和更新捣辆,都是要從服務(wù)器獲取的蔬螟,所以對(duì)于資源文件的壓縮其實(shí)是最直接也最應(yīng)該做的事情之一,但是一般服務(wù)器端都會(huì)做好汽畴,所以主要就是上面這三件事旧巾。

駕照考試

介紹了這么多,希望能對(duì)你有點(diǎn)幫助忍些。接下來(lái)時(shí)純實(shí)戰(zhàn)時(shí)間鲁猩,我會(huì)將上面所介紹的很多知識(shí)點(diǎn)在接下來(lái)的代碼里實(shí)際應(yīng)用一遍,希望能夠帶給你更加直觀的使用感受罢坝。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <android.support.design.widget.AppBarLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <android.support.v7.widget.Toolbar
            android:id="@+id/toolbar"
            android:layout_width="match_parent"
            android:layout_height="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:theme="@style/ThemeOverlay.AppCompat.Light" />

        </android.support.design.widget.AppBarLayout>

        <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <WebView
            android:id="@+id/web_view"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

        <ProgressBar
            android:id="@+id/progress_bar"
            android:layout_width="50dp"
            android:layout_height="50dp"
            android:layout_gravity="center"
            android:visibility="gone" />
        </FrameLayout>
</LinearLayout>

Java部分

public class MainActivity extends AppCompatActivity {

  private WebView mWebView;

  private ProgressBar mProgressbar;
  private Toolbar mToolbar;

  @Override
  protected void onCreate(Bundle savedInstanceState) {
      supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
      super.onCreate(savedInstanceState);
      setContentView(R.layout.activity_main);

      initAppBar();//初始化Toolbar

      initWebView();//初始化WebView
      initWebSettings();//初始化WebSettings
      initWebViewClient();//初始化WebViewClient
      initWebChromeClient();//初始化WebChromeClient
  }

  private void initAppBar() {
      mToolbar = (Toolbar) findViewById(R.id.toolbar);
      mToolbar.setTitle("載入中..");
      mToolbar.setTitleTextColor(getResources().getColor(R.color.colorWhite));
      setSupportActionBar(mToolbar);
      getSupportActionBar().setDisplayHomeAsUpEnabled(false);
  }

  private void initWebView() {
      mWebView = (WebView) findViewById(R.id.web_view);
      mProgressbar = (ProgressBar) findViewById(R.id.progress_bar);
      String url = "https://www.google.com";
      mWebView.loadUrl(url);
  }

  private void initWebSettings() {
      WebSettings settings = mWebView.getSettings();
      //支持獲取手勢(shì)焦點(diǎn)
      mWebView.requestFocusFromTouch();
      //支持JS
      settings.setJavaScriptEnabled(true);
      //支持插件
      settings.setPluginState(WebSettings.PluginState.ON);
      //設(shè)置適應(yīng)屏幕
      settings.setUseWideViewPort(true);
      settings.setLoadWithOverviewMode(true);
      //支持縮放
      settings.setSupportZoom(false);
      //隱藏原生的縮放控件
      settings.setDisplayZoomControls(false);
      //支持內(nèi)容重新布局
      settings.setLayoutAlgorithm(WebSettings.LayoutAlgorithm.SINGLE_COLUMN);
      settings.supportMultipleWindows();
      settings.setSupportMultipleWindows(true);
      //設(shè)置緩存模式
      settings.setDomStorageEnabled(true);
      settings.setDatabaseEnabled(true);
      settings.setCacheMode(WebSettings.LOAD_DEFAULT);
      settings.setAppCacheEnabled(true);
      settings.setAppCachePath(mWebView.getContext().getCacheDir().getAbsolutePath());

      //設(shè)置可訪問(wèn)文件
      settings.setAllowFileAccess(true);
      //當(dāng)webview調(diào)用requestFocus時(shí)為webview設(shè)置節(jié)點(diǎn)
      settings.setNeedInitialFocus(true);
      //支持自動(dòng)加載圖片
      if (Build.VERSION.SDK_INT >= 19) {
          settings.setLoadsImagesAutomatically(true);
      } else {
          settings.setLoadsImagesAutomatically(false);
      }
      settings.setNeedInitialFocus(true);
      //設(shè)置編碼格式
      settings.setDefaultTextEncodingName("UTF-8");
  }

  private void initWebViewClient() {
      mWebView.setWebViewClient(new WebViewClient() {

          //頁(yè)面開始加載時(shí)
          @Override
          public void onPageStarted(WebView view, String url, Bitmap favicon) {
              super.onPageStarted(view, url, favicon);
              mProgressbar.setVisibility(View.VISIBLE);
          }


      //頁(yè)面完成加載時(shí)
      @Override
      public void onPageFinished(WebView view, String url) {
          super.onPageFinished(view, url);
          mProgressbar.setVisibility(View.GONE);
      }

      //是否在WebView內(nèi)加載新頁(yè)面
      @Override
      public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
          view.loadUrl(request.toString());
          return true;
      }

      //網(wǎng)絡(luò)錯(cuò)誤時(shí)回調(diào)的方法
      @Override
      public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
          super.onReceivedError(view, request, error);
          /**
               * 在這里寫網(wǎng)絡(luò)錯(cuò)誤時(shí)的邏輯,比如顯示一個(gè)錯(cuò)誤頁(yè)面
               *
               * 這里我偷個(gè)懶不寫了
               * */
      }

      @TargetApi(Build.VERSION_CODES.M)
      @Override
      public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
          super.onReceivedHttpError(view, request, errorResponse);
      }
  });
}

private void initWebChromeClient() {

  mWebView.setWebChromeClient(new WebChromeClient() {

      private Bitmap mDefaultVideoPoster;//默認(rèn)的視頻展示圖

      @Override
      public void onReceivedTitle(WebView view, String title) {
          super.onReceivedTitle(view, title);
          setToolbarTitle(title);
      }

      @Override
      public Bitmap getDefaultVideoPoster() {
          if (mDefaultVideoPoster == null) {
              mDefaultVideoPoster = BitmapFactory.decodeResource(
                      getResources(), R.drawable.video_default
              );
              return mDefaultVideoPoster;
          }
          return super.getDefaultVideoPoster();
      }
  });
}

  /**
   * 設(shè)置Toolbar標(biāo)題
   *
   * @param title
   */
  private void setToolbarTitle(final String title) {
  Log.d("setToolbarTitle", " WebDetailActivity " + title);
  if (mToolbar != null) {
      mToolbar.post(new Runnable() {
          @Override
          public void run() {
              mToolbar.setTitle(TextUtils.isEmpty(title) ? getString(R.string.loading) : title);
          }
      });
  }
 }

  @Override
  public boolean onCreateOptionsMenu(Menu menu) {
      getMenuInflater().inflate(R.menu.menu_main, menu);
      return super.onCreateOptionsMenu(menu);
  }

  @Override
  public boolean onOptionsItemSelected(MenuItem item) {
      switch (item.getItemId()) {
          case R.id.page_up:
              Toast.makeText(getApplicationContext(), "頁(yè)面向上", Toast.LENGTH_SHORT).show();
              mWebView.pageUp(true);
          break;
      case R.id.page_down:
          Toast.makeText(getApplicationContext(), "頁(yè)面向下", Toast.LENGTH_SHORT).show();
          mWebView.pageDown(true);
          break;
      case R.id.refresh:
          Toast.makeText(getApplicationContext(), "刷新~", Toast.LENGTH_SHORT).show();
          mWebView.reload();
      default:
          return super.onOptionsItemSelected(item);
  }
  return super.onOptionsItemSelected(item);
  }

  @Override
  public boolean onKeyDown(int keyCode, KeyEvent event) {

  //如果按下的是回退鍵且歷史記錄里確實(shí)還有頁(yè)面
  if ((keyCode == KeyEvent.KEYCODE_BACK) && mWebView.canGoBack()) {
      mWebView.goBack();
      return true;
  } else {
      Toast.makeText(getApplicationContext(), "考試結(jié)束,恭喜您考試合格!", Toast.LENGTH_LONG).show();
  }
  return super.onKeyDown(keyCode, event);
  }
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末廓握,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子嘁酿,更是在濱河造成了極大的恐慌隙券,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件闹司,死亡現(xiàn)場(chǎng)離奇詭異娱仔,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)开仰,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門拟枚,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人众弓,你說(shuō)我怎么就攤上這事恩溅。” “怎么了谓娃?”我有些...
    開封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵脚乡,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng)奶稠,這世上最難降的妖魔是什么俯艰? 我笑而不...
    開封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮锌订,結(jié)果婚禮上竹握,老公的妹妹穿的比我還像新娘。我一直安慰自己辆飘,他們只是感情好啦辐,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著蜈项,像睡著了一般芹关。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上紧卒,一...
    開封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天侥衬,我揣著相機(jī)與錄音,去河邊找鬼跑芳。 笑死轴总,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的聋亡。 我是一名探鬼主播肘习,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼际乘,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼坡倔!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起脖含,我...
    開封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤罪塔,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后养葵,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體征堪,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年关拒,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了佃蚜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡着绊,死狀恐怖谐算,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情归露,我是刑警寧澤洲脂,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布,位于F島的核電站剧包,受9級(jí)特大地震影響恐锦,放射性物質(zhì)發(fā)生泄漏往果。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一一铅、第九天 我趴在偏房一處隱蔽的房頂上張望陕贮。 院中可真熱鬧,春花似錦潘飘、人聲如沸飘蚯。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)局骤。三九已至,卻和暖如春暴凑,著一層夾襖步出監(jiān)牢的瞬間峦甩,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工现喳, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留凯傲,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓嗦篱,卻偏偏與公主長(zhǎng)得像冰单,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子灸促,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容

  • WebView·開車指南 目錄 WebView簡(jiǎn)介 WebView基本使用 WebView常用方法 WebSett...
    小莊bb閱讀 3,489評(píng)論 3 25
  • Tips 由于WebView的用法實(shí)在太多诫欠,如果您只是想查詢某個(gè)功能的使用——建議Ctrl+F(Commad+F)...
    BugDev閱讀 7,737評(píng)論 11 109
  • WebView·開車指南 2016-08-31BugDev 北京市東城區(qū)首席Bug布道師開山之作,一整月交通事故血...
    53c021c38a1d閱讀 826評(píng)論 0 1
  • WebView簡(jiǎn)介 String getUrl():獲取當(dāng)前頁(yè)面的URL浴栽。 reload():重新reload當(dāng)前...
    QM閱讀 3,079評(píng)論 0 52
  • WebView常用方法 String getUrl():獲取當(dāng)前頁(yè)面的URL荒叼。 reload():重新reload...
    JuSong閱讀 3,258評(píng)論 0 3