1. 程式人生 > >webview api介紹+解決記憶體洩漏+js互動

webview api介紹+解決記憶體洩漏+js互動

1:建立webview

一般建立webview不採用在layout中直接去定義,而是用程式碼new一個webview出來,並且用RelativeLayout或LinearLayout做一個佔位.

<LinearLayout
android:id="@+id/wv_robot"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent">

</LinearLayout>

mLayout = (LinearLayout) findViewById(R.id.wv_robot
); mWv = new WebView(getApplicationContext()); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT); mWv.setLayoutParams(params); mLayout.addView(mWv);

2:載入方式

//載入一個網頁:
mWv.loadUrl("http://www.google.com/");
//載入apk包中的一個
html頁面 mWv.loadUrl("file:///android_asset/receptionmode.html"); //載入手機本地的一個html頁面的方法: mWv.loadUrl("content://com.Android.htmlfileprovider/sdcard/test.html");

其中,載入本地時(第二種),把html檔案放置在asste資料夾中


3:API介紹

WebSettings webSettings = mWv.getSettings();
//支援js互動,這句程式碼必須加上,如果不加上,會造成圖片不能顯示,並且無法與js進行互動
webSettings.setJavaScriptEnabled(true
);
//自適應螢幕
webSettings.setUseWideViewPort(true);
webSettings.setLoadWithOverviewMode(true);

//支援手勢進行放大縮小
webSettings.setBuiltInZoomControls(true);
webSettings.setSupportZoom(true);

//隱藏放大鏡圖示
webSettings.setDisplayZoomControls(false);

//監聽載入進度
mWv.setWebChromeClient(new WebChromeClient(){
    @Override
public void onProgressChanged(WebView view, int newProgress) {
        super.onProgressChanged(view, newProgress);
    }
});
//監聽載入完成,開始===>設定WebViewClient就不會跳到我們的內建瀏覽器
mWv.setWebViewClient(new WebViewClient(){
    @Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
        super.onPageStarted(view, url, favicon);
    }

    @Override
public void onPageFinished(WebView view, String url) {
        super.onPageFinished(view, url);
    }
});

//獲取當前的url
mWv.getUrl();

//當用戶在當前webview中點選了按鈕,跳到下一個webview頁面,這時如果按物理返回鍵,是會銷燬當前的activty,那我們想
//返回上一個webview頁面應該怎麼辦呢,加下面程式碼即可!
@Override
public boolean onKeyDown(int keyCode, KeyEvent event) {
    if (keyCode == KeyEvent.KEYCODE_BACK) {
        if (mWv.canGoBack()) {//判斷能不能後退
mWv.goBack();
            return true;
        }
    }
    return super.onKeyDown(keyCode, event);
}

mWv.setWebChromeClient(new WebChromeClient(){

    //返回當前頁面的標題
@Override
public void onReceivedTitle(WebView view, String title) {
        RobotActivity.this.setTitle(title);
        super.onReceivedTitle(view, title);
    }
});
//回退的時候標題沒有換回來,這時再做一下操作即可
mWv.setWebViewClient(new WebViewClient() {
    @Override
public boolean shouldOverrideUrlLoading(WebView view, String url) {
        // TODO Auto-generated method stub
view.loadUrl(url);
        return false;
    }

    @Override
public void onPageFinished(WebView view, String url) {
        setTitle(view.getTitle());
        super.onPageFinished(view, url);
    }
});

3:解決記憶體洩漏

載入一個Web頁面一般需要用到100M左右,而如果我們不及時清理WebView的記憶體,那最後可能會隨著記憶體消耗的不斷增加而發生OOM(Out Of Memory)導致程式崩潰;

第一:

建立webview時,用Application的Context而不是用Activity的,理由同網上一致的說法,這樣能夠避免記憶體洩漏;同時網上也說如果用Application的Context的話,在有些時候會出錯,原因是Application到Activity型別轉換錯誤;但是這種說法並非正確的,所以這裡還是用Application的Context;

因為經過我的實際測試,在反覆New和銷燬WebView時,採用Application要比採用Activity的context要穩定地少用20~30M左右的記憶體,雖然

他們的記憶體都維持在一個穩定的消耗水平,但總體看來,Application要比Activity少那麼一點;

第二:

開啟另一個程序去開啟這個activity,避免記憶體洩漏

<activity android:name=".iwith_control.ui.activity.RobotActivity"
android:process=":xxx.xxx.process.web">
    <intent-filter>
        <action android:name="com.xxx.xxx.robotactivity"/>
        <category android:name="android.intent.category.DEFAULT"/>
    </intent-filter>
</activity>

一般情況下,同一個應用程式的Activity元件都是執行在同一個程序中,但是,如果Activity配置了android:process這個屬性,那麼,它就會執行在自己

的程序中。如果android:process屬性的值以":"開頭,則表示這個程序是私有的;如果android:process屬性的值以小寫字母開頭,則表示這是一個全域性

程序,允許其它應用程式元件也在這個程序中執行。因此,這裡我們以":"開頭,表示建立的是私有的程序。事實上,這裡我們不要前面的":"也是可以

的,但是必須保證這個屬性性字串內至少有一個"."字元

跳轉:

Intent robotIntent = new Intent("com.xxx.xxx.robotactivity");
Bundle bbb = new Bundle();
bbb.putString("url", "哈哈");
robotIntent.putExtras(bbb);
startActivity(robotIntent);
接收:
String url = getIntent().getExtras().getString("url");
LogUtil.d("資料="+url);

第三:

回收記憶體

第一種做法:

@Override
protected void onDestroy() {
    super.onDestroy();

    clearWebViewResource();
}

/**
 * Description: release the memory of web view, otherwise it's resource will not be recycle.
 * Created by Michael Lee on 7/18/16 20:38
 */
public void clearWebViewResource() {
    if (mWv != null) {
        mWv.removeAllViews();
        // in android 5.1(sdk:21) we should invoke this to avoid memory leak
        // see (https://coolpers.github.io/webview/memory/leak/2015/07/16/
        // android-5.1-webview-memory-leak.html)
((ViewGroup) mWv.getParent()).removeView(mWv);
        mWv.setTag(null);
        mWv.clearHistory();
        mWv.destroy();
        mWv = null;
    }
}

第二種做法,直接殺掉當前程序(當橫屏切換到豎屏時,會直接返回到上一個頁面)
@Override
protected void onDestroy() {
    super.onDestroy();

    System.exit(0);
}

還有一個問題要說的,也是在WebView使用的時候出現的問題:WebView中包含一個ZoomButtonsController,當使用web.getSettings().setBuiltInZoomControls(true);啟用該設定後,使用者一旦觸控式螢幕幕,就會出現縮放控制圖示。這個圖示過上幾秒會自動消失,但在3.0系統以上上,如果圖示自動消失前退出當前Activity的話,就會發生ZoomButton找不到依附的Window而造成程式崩潰,解決辦法很簡單就是在Activity的ondestory方法中呼叫web.setVisibility(View.GONE);方法,手動將其隱藏,就不會崩潰了。在3.0一下系統上不會出現該崩潰問題,真是各種崩潰,防不勝防啊!

最後還有記憶體洩漏的一些個建議:

In summary, to avoid context-related memory leaks, remember the following:

  • Do not keep long-lived references to a context-activity (a reference to an activity should have the same life cycle as the activity itself)
  • Try using the context-application instead of a context-activity
  • Avoid non-static inner classes in an activity if you don’t control their life cycle, use a static inner class and make a weak reference to the activity inside

And remember that a garbage collector is not an insurance against memory leaks. Last but not least, we try to make such leaks harder to make happen whenever we can.

js互動請看: