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交互请看: