一、回顾与规划

回顾一下,我们在第一章中已经完成了一些封装:

我们看一下我们的目前的架构图片:

初步架构通信图

我们已经实现了:

抽象父类WebDelegate,用来管理webView的生命周期,以及初始化,保证不会内存泄漏,提供了一些get方法

接口回调完成了,子类作为具体的实现类,要给我实现这个接口,也就是要完成三个方法,分别是初始化settings,设置client,以及chromeClient(webView设置的三部曲)

创建js交互的本地对象类LatteWebInterface,算是为以后和js交互预留了地方,目前没用

本节我们想实现:

BaseDelegate

先来对基类fragment封装一下下,让我们所有的fragment都继承于BaseDelegate,我们给它个新统称名字叫Delegate。(上一节中你可能已经发现,WebDelegate就已经继承于一个Delegate)

WebDelegateDefault

父基类有了,我们想要一个默认的子Delegate,叫WebDelegateDefault吧!让它能够可以直接使用,也就是要实现接口,包括了初始化settings,设置client,以及chromeClient(webView设置的三部曲)。同时,别忘了还要实现它作为一个Delegate(fragment)应该实现的一些回调方法。

WebDelegateImpl

默认的实现子类有了之后,其实已经可以使用,使用 方法类似于Android sdk中自带的WebViewFragment类。但是,我们还能建立一些特殊的子类继承于WebDelegateDefault,比如下图中的WebDelegateImpl,和具体业务有关,属于业务层,不想要默认的某些设置,就可以在这个类中override方法。由于是业务相关,我们放到第三篇来说,暂且不表。

高级架构通信图

二、基类fragment封装

这里说一下,由于本人使用了非常好用的fragmentation第三方库,所以基类BaseDelegate继承自SwipeBackFragment。如果不用这个吊炸天的开源库,直接继承原生的Fragment也是一样写的。BTW,还顺便封装了一下butterknife~~

public abstract class BaseDelegate extends SwipeBackFragment {

@SuppressWarnings("SpellCheckingInspection")

private Unbinder mUnbinder = null;

//子类必须实现,可以返回一个layout的资源id,或一个view

public abstract Object setLayout();

//子类初始化时回调

public abstract void onBindView(@Nullable Bundle savedInstanceState, View rootView);

@Nullable

@Override

public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {

View rootView = null;

Object mLayout = setLayout();

if (mLayout instanceof Integer) {

rootView = inflater.inflate((Integer) mLayout, container, false);

} else if (mLayout instanceof View) {

rootView = (View) mLayout;

}

if (rootView != null) {

mUnbinder = ButterKnife.bind(this, rootView);

onBindView(savedInstanceState, rootView);

}

return rootView;

}

@Override

public void onDestroyView() {

super.onDestroyView();

if (mUnbinder != null) {

mUnbinder.unbind();

}

}

}

这样一来,在子类中,我们只要在setLayout()方法里返回一个view或者layout布局,在onBindView()方法里做一些控件的初始化即可。另外,butterKnife已经在基类里和视图绑定,子类中不用再初始化啦!

写完之后,记得让我们的WebDelegate继承它哦~

三、WebView初始化三部曲

还记得三部曲吗?包括了初始化settings,设置client,以及chromeClient。它们都应该在默认的子类WebDelegateDefault中实现,我们先来实现它们!但是有些设置代码太多,单独写几个文件比较好。

3.1 各种settings

注释写的很详细,也没啥好说的:

/**

* @function 对传入的webView进行各种settings,返回setting好的webView

* Created by 尤晟 on 2017-07-30.

*/

public class WebViewSettingsInitializer {

@SuppressLint("SetJavaScriptEnabled")

public WebView createWebView(final WebView webView) {

//api>=21时才能开启

// WebView.setWebContentsDebuggingEnabled(true);

//不能横向滚动

webView.setHorizontalScrollBarEnabled(false);

//不能纵向滚动

webView.setVerticalScrollBarEnabled(false);

//允许截图

webView.setDrawingCacheEnabled(true);

//屏蔽长按事件

webView.setOnLongClickListener(new View.OnLongClickListener() {

@Override

public boolean onLongClick(View v) {

return true;

}

});

//初始化WebSettings

final WebSettings settings = webView.getSettings();

settings.setJavaScriptEnabled(true);

final String ua = settings.getUserAgentString();

settings.setUserAgentString(ua + "Latte");

//隐藏缩放控件

settings.setBuiltInZoomControls(false);

settings.setDisplayZoomControls(false);

//禁止缩放

settings.setSupportZoom(false);

//文件权限

settings.setAllowFileAccess(true);

settings.setAllowFileAccessFromFileURLs(true);

settings.setAllowUniversalAccessFromFileURLs(true);

settings.setAllowContentAccess(true);

//缓存相关

settings.setAppCacheEnabled(true);

settings.setDomStorageEnabled(true);

settings.setDatabaseEnabled(true);

settings.setCacheMode(WebSettings.LOAD_DEFAULT);

return webView;

}

}

3.2 ChromeClient实现

与页面的js交互有关,暂时不管。

/**

* @function 不做处理,为了以后的扩展

* Created by 尤晟 on 2017-07-30.

*/

public class WebChromeClientImpl extends WebChromeClient {

@Override

public boolean onJsAlert(WebView view, String url, String message, JsResult result) {

return super.onJsAlert(view, url, message, result);

}

}

3.3 WebViewClient实现

里面有一系列常用的重写方法,不过由于我们只想让页面由此webView处理,所以只需重写shouldOverrideUrlLoading方法,返回一个false。由于代码过少,我们就在子类里用匿名类方式实现吧。

3.4 Router路由转发与加载类

这个类负责路由的截断处理,以及页面的一些重载加载,用单例模式。以后还会往里面添加方法。

/**

* @function 路由截断, 线程安全的惰性单例模式

* Created by 尤晟 on 2017-07-30.

*/

public class Router {

private Router() {

}

private static class Holder {

private static final Router INSTANCE = new Router();

}

public static Router getInstance() {

return Holder.INSTANCE;

}

private void loadWebPage(WebView webView, String url) {

if (webView != null) {

webView.loadUrl(url);

} else {

throw new NullPointerException("WebView is null!");

}

}

//在assets文件夹中的本地页面(和res文件夹同级)

private void loadLocalPage(WebView webView, String url) {

loadWebPage(webView, "file:///android_asset/" + url);

}

private void loadPage(WebView webView, String url) {

if (URLUtil.isNetworkUrl(url) || URLUtil.isAssetUrl(url)) {

loadWebPage(webView, url);

} else {

loadLocalPage(webView, url);

}

}

public final void loadPage(WebDelegate delegate, String url) {

loadPage(delegate.getWebView(), url);

}

}

四、WebDelegateDefault默认子类的实现

写了这么多基类,零件也初始化好了,终于要写一个默认的子类了!由于有了很多的封装,现在写起来非常简单。

另外,此类实现了IWebViewInitializer 接口,setInitializer()方法里返回自身,而非在setInitializer()方法里返回一个新的接口实例,这是有理由的:方便在下一个子类中,只用override部分需要重写的方法就行了(比如只需要改变子类的WebViewClient,那我们只需重写initWebViewClient()方法),不然要重写整个setInitializer()方法了。

/**

* @function WebDelegate的默认子类,点击链接会在webView内部跳转

* Created by 尤晟 on 2017-07-31.

*/

public class WebDelegateDefault extends WebDelegate implements IWebViewInitializer {

//必须用这种方式创建WebDelegateDefault 类

public static WebDelegateDefault create(String url) {

final Bundle bundle = new Bundle();

//RouteKeys是个枚举类罢了,里面只有一个值URL

bundle.putString(RouteKeys.URL.name(), url);

final WebDelegateDefault delegate = new WebDelegateDefault();

delegate.setArguments(bundle);

return delegate;

}

@Override

public WebView initWebViewSettings(WebView webView) {

return new WebViewSettingsInitializer().createWebView(webView);

}

//匿名内部类方式实现WebViewClient

@Override

public WebViewClient initWebViewClient() {

return new WebViewClient() {

//谷歌已经不推荐用这个方法,而推荐用另一个重载方法。但是那个方法必须要api>=21。

//为了兼容性和简单性,我们继续使用这个方法。你也可以判断一下api,我偷懒了。

@Override

public boolean shouldOverrideUrlLoading(WebView view, String url) {

//将页面内的点击链接,交给此webView自己处理

return false;

}

};

}

@Override

public WebChromeClient initWebChromeClient() {

return new WebChromeClientImpl();

}

//基类Delegate中封装的方法,Fragment会加载这个方法返回的view或者layout布局

@Override

public Object setLayout() {

return getWebView();

}

@Override

public void onBindView(@Nullable Bundle savedInstanceState, View rootView) {

if (getUrl() != null) {

//进行页面加载

Router.getInstance().loadPage(this, getUrl());

}

}

@Override

public IWebViewInitializer setInitializer() {

//自身实现接口,向上转型返回自身给父类,父类获取到了初始化三部曲后进行初始化

return this;

}

//这是第三方库fragmentation自带的方法,用来重写返回键,表示返回上一个页面而非退出webView。

//若没用这个第三方库,可以在webView的三部曲之一settings时调用 webView.setOnKeyListener来设置。

@Override

public boolean onBackPressedSupport() {

if (getWebView().canGoBack()) { //表示按返回键时的操作

getWebView().goBack(); //后退

//webview.goForward();//前进

return true; //已处理

}

return false;

}

}

五、总结

至此,基本的类已经实现完毕,可以实例化默认的子类,然后当做Fragment随意使用了。但是,下一篇中,我将继续对client也做一个默认的封装,实现网页的loading界面。同时,还将针对某个具体的业务案例,实现一个特殊化的子类,配合我们的默认子类食用,其中包括了一些有关shouldOverrideUrlLoading重定向的深坑。

欢迎大家点击关注,以及喜欢~~~

android webview 类,Android开罐头——WebView高可扩展性封装(二)相关推荐

  1. android 初始化类,Android 常用编程技巧/Java类的初始化顺序 (静态变量、静态初始化块、变量、初始化块、构造器)...

    1.设置屏幕的亮度: WindowManager.LayoutParams lp=getWindow().getAttributes(); lp.screenBrightness=1.0f; getW ...

  2. android webview 基类,Android开罐头——WebView高可扩展性封装(一)

    一.架构搭建 首先,我们确定第一步应该完成什么: 作为封装,一个抽象的父类是必须要的,比如初始化webView,webView的生命周期管理,因为大家知道webView容易内存泄漏.我们建立一个抽象类 ...

  3. android 管理类,android 线程管理类

    1. 延时任务以及取消延时的应用场景:实时搜索,文字内容变化时候不发送请求,当停止变化指定时间后再发送请求 2. 使用方法: // 回到主线程 MainThreadHelper.runOnUIthre ...

  4. android+坐标类,Android Path和PathMeasure类的使用之获取圆弧上的坐标值

    问题: 已知图中的中心圆点在屏幕上的坐标为(x, y),分别求出点1.2.3.4的坐标值! 解决方法: 1)以圆点坐标(x,y)为中心画一个矩形RectF, 2)再通过Path类画一个90度(180- ...

  5. 百度地图android绘图类,Class:android总类/android离线地图类

    出自百度地图API 跳转到:导航 , 搜索 com.baidu.mapapi 类 MKOfflineMap java.lang.Object ∟ com.baidu.mapapi.MKOfflineM ...

  6. android 多线程类,Android 多线程处理之多线程用法大集合

    类型:服务器区大小:21KB语言:中文 评分:6.6 标签: 立即下载 第 3 页 ExecutorServie线程池 5.ExecutorServie线程池 通过Executors的静态方法来创建, ...

  7. Android Canvas类

    1. Canvas类 Canvas主要用于2D绘图,它提供了很多相应的drawXxx()方法,Canvas的获取方式有三种 重写View的onDraw(Canvas)方法 @Override prot ...

  8. Android Paint类

    1. Paint常用方法 setColor(int),设置画笔的颜色 setAlpha(int),设置画笔的透明度 setARGB(int a, int r, int g, int b),设置画笔的颜 ...

  9. Android Toast类

    1. 默认创建 Toast是一种简易的消息提示框,toast提示框不能被用户点击,会根据用户设置的显示时间后自动消失. Toast静态方法makeText(),生成Toast实例,并调用show()方 ...

最新文章

  1. 安装编译PHP7.X
  2. python列表常用方法_第24p,必须掌握,列表的常用方法
  3. 打开AzureRay园子的大门,欢迎大家串门哟~
  4. 【智能汽车与自动驾驶】
  5. VS2015和QTcreator冲突解决办法
  6. 泰亚史诗萨拉斯服务器维护,泰亚史诗上古馈赠介绍 这个可是好东西
  7. Node --- Promise中的多异步协作
  8. 搭建IC设计EDA虚拟机服务器,忆往昔--集成门控时钟技术的前世--分离门控时钟技术...
  9. HttpClient系列~StringContent与FormUrlEncodedContent
  10. 年终盘点 | 2019年Java面试题汇总篇(附答案)
  11. windows安装TortoiseGit
  12. Ajax异步方式实现登录与參数的校验
  13. 动态规划之子序列问题
  14. 面向对象编程的四大特性
  15. 尝试做一个简单的文件系统
  16. 使用IDEA创建Android项目
  17. Hive微博数据统计分析
  18. linux如何释放swap空间,释放linux的swap内存
  19. 进阶篇:2)DFMA方法的运用
  20. vue实现伸缩菜单功能

热门文章

  1. oracle数据库怎用,oracle数据库怎么打开
  2. mysql 统计每年的数据统计_MySQL 统计每年每个月的数据 -- 详细教程
  3. java处理日期的类_Java实现的日期处理类完整实例
  4. uniapp小视频项目:消息列表开发
  5. 纳尼!7d聚拉提和热玛吉哪个效果好,30岁阿姨说7d聚拉提的功效和原理,这一篇全齐活了
  6. 如何查看论文来自哪个期刊! 教你一个又快又对的方法~~~
  7. 名编辑电子杂志大师教程 | 名编辑支持导入什么样的视频格式?
  8. java删不掉_java删除文件删不掉相关阅读-java删除文件删不掉文章阅读-123文学网...
  9. Java 14 GA 版本正式发布
  10. Android图片上传(头像裁切+原图原样)