1 前言
无论是日常开发还是练习, 相信网页显示是经常需要实现的业务场景, 现在的应用一般有网页链接传入, 都直接在自己的应用中显示, 不会去跳转自带浏览器今天, 我们就来实现一个能满足基本网页浏览需求的页面国际惯例附上源码
2 效果图
从图中可以看到进入新闻网页后, 除了不能输入网址(关注自己的业务), 已经与普通浏览器浏览网页相同 下面上代码
3 代码
急用的同学下面可以直接 ctrl c + ctrl v, 如果想知道一些原理不妨接着往下看
1 添加访问网络权限(AndroidManifest.xml)
<uses-permission android:name="android.permission.INTERNET" />
2 页面布局
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- tools:context="app.main.wangliwei.enablehands.view.webDetailActivity">
- <FrameLayout
- android:id="@+id/web_frame"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:focusable="true"
- android:focusableInTouchMode="true">
- </FrameLayout>
- </RelativeLayout>
- 3WebDetailActivity.java
- public class WebDetailActivity extends AppCompatActivity {
- private Bundle bundle;
- private WebView webView;
- private FrameLayout frameLayout;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_web_detail);
- frameLayout = findViewById(R.id.xwalk_view);
- bundle = getIntent().getExtras();
- initView();
- }
- private void initView() {
- webView = new WebView(this);
- WebSettings settings = webView.getSettings();
- settings.setDomStorageEnabled(true);
- // 解决一些图片加载问题
- settings.setJavaScriptEnabled(true);
- settings.setBlockNetworkImage(false);
- webView.setWebViewClient(new WebViewClient(){
- @Override
- public boolean shouldOverrideUrlLoading(WebView view, String url) {
- Log.d("webview","url:"+url);
- view.loadUrl(url);
- return true;
- }
- });
- frameLayout.addView(webView);
- String url = bundle.getString("URL");
- webView.loadUrl(url);
- }
- // 监听 BACK 按键, 有可以返回的页面时返回页面
- @Override
- public boolean onKeyDown(int keyCode, KeyEvent event) {
- if(keyCode == KeyEvent.KEYCODE_BACK) {
- if(webView.canGoBack()) {
- webView.goBack();
- return true;
- }
- }
- return super.onKeyDown(keyCode, event);
- }
- @Override
- protected void onDestroy() {
- if (webView != null) {
- webView.loadDataWithBaseURL(null, "","text/html","utf-8", null);
- webView.setTag(null);
- webView.clearHistory();
- ((ViewGroup) webView.getParent()).removeView(webView);
- webView.destroy();
- webView = null;
- }
- super.onDestroy();
- }
- }
在浏览页面时主要做了两个处理, 一个是对页面返回的链接 (URL) 做直接显示处理, 由于我是实现一个新闻业务, 所以在浏览过程中跳转到其他页面是必须的, 重载 WebClientView 中的
shouldOverrideUrlLoading
方法另一个是监听 BACK 按键, 先用 canGoBack()判断是否有可以回退的页面, 如果有再调用 goBack()返回上一个页面
4WebView 的几种加载方式
- // 方式 1. 加载一个网页:
- webView.loadUrl("http://www.baidu.com/");
- // 方式 2: 加载 apk 包中的 html 页面
- webView.loadUrl("file:///android_asset/test.html");
- // 方式 3: 加载手机本地的 html 页面
- webView.loadUrl("content://com.android.levi/sdcard/test.html");
5Settings 的常见设置
- WebSettings settings = webView.getSettings();
- // webview 启用 javascript 支持 用于访问页面中的 javascript
- settings.setJavaScriptEnabled(true);
- // 设置 WebView 缓存模式 默认断网情况下不缓存
- settings.setCacheMode(WebSettings.LOAD_DEFAULT);
- /**
- * LOAD_CACHE_ONLY: 不使用网络, 只读取本地缓存数据
- * LOAD_DEFAULT: (默认)根据 cache-control 决定是否从网络上取数据
- * LOAD_NO_CACHE: 不使用缓存, 只从网络获取数据.
- * LOAD_CACHE_ELSE_NETWORK, 只要本地有, 无论是否过期, 或者 no-cache, 都使用缓存中的数据
- */
- // 断网情况下加载本地缓存
- settings.setCacheMode(WebSettings.LOAD_CACHE_ELSE_NETWORK);
- }
- // 让 WebView 支持 DOM storage API
- settings.setDomStorageEnabled(true);
- // 让 WebView 支持缩放
- settings.setSupportZoom(true);
- // 启用 WebView 内置缩放功能
- settings.setBuiltInZoomControls(true);
- // 让 WebView 支持可任意比例缩放
- settings.setUseWideViewPort(true);
- // 让 WebView 支持播放插件
- settings.setPluginState(WebSettings.PluginState.ON);
- // 设置 WebView 使用内置缩放机制时, 是否展现在屏幕缩放控件上
- settings.setDisplayZoomControls(false);
- // 设置在 WebView 内部是否允许访问文件
- settings.setAllowFileAccess(true);
- // 设置 WebView 的访问 UserAgent
- settings.setUserAgentString(String string);
- // 设置脚本是否允许自动打开弹窗
- settings.setJavaScriptCanOpenWindowsAutomatically(true);
- // 加快 HTML 网页加载完成速度
- if (Build.VERSION.SDK_INT >= 19) {
- settings.setLoadsImagesAutomatically(true);
- } else {
- settings.setLoadsImagesAutomatically(false);
- }
- // 开启 Application H5 Caches 功能
- settings.setAppCacheEnabled(true);
- // 设置编码格式
- settings.setDefaultTextEncodingName("utf-8");
3 跳转 Activity
拿到链接 (URL) 以后可以这样开启浏览页面
- Bundle bundle = new Bundle();
- bundle.putString("URL", url);
- Intent intent = new Intent(getActivity(), WebDetailActivity.class);
- intent.putExtras(bundle);
- startActivity(intent, bundle);
4 关于内存泄漏
每个应用在 android 中所占用的内存是有限制的, 碰巧 WebView 又是内存大户, 所以在关闭页面时, 如果不及时释放内存, 很可能导致 OOM
避免内存泄漏要做一些处理: 不在 xml 中定义 Webview , 而是在需要的时候在 Activity 中创建, 并且 Context 使用
getApplicationgContext()
, 因为 WebView 调用 destory 时, 如果传入 Activity 的 Context 对象 WebView 会仍绑定在 Activity 上在 Activity 销毁 ( WebView ) 的时候, 先让 WebView 加载 null 内容, 然后从父容器 (ViewGroup) 中移除 WebView, 再销毁 WebView, 最后置空
需要注意的是, 如果你需要在 WebView 中打开链接或者你打开的页面带有 flash, 获得你的 WebView 想弹出一个 dialog, 都会导致从 ApplicationContext 到 ActivityContext 的强制类型转换错误, 从而导致你应用崩溃这是因为在加载 flash 的时候, 系统会首先把你的 WebView 作为父控件, 然后在该控件上绘制 flash, 他想找一个 Activity 的 Context 来绘制他, 但是你传入的是 ApplicationContext
解决方法: 通常根治这个问题的办法是为 WebView 开启另外一个进程, 通过 AIDL 与主进程进行通信, WebView 所在的进程可以根据业务的需要选择合适的时机进行销毁, 从而达到内存的完整释放因为 webview 引发的 资源无法释放等问题 全部可以解决
5 最后
通过以上步骤还是可以实现一个满足基本浏览需求的页面的, 注意内存泄漏, 比较开发到后期, 对内存的使用时越来也关注如果对你有帮助, 欢迎 star 支持下, 源码地址, 个人项目里面有一些其他东西, 直接看 WebDetailActivity 中的内容即可
来源: https://juejin.im/post/5a7d8744f265da4e7a784c8c