1.自定义WebView说明

1.1.这个WebView可以加载缓存的数据。(需要后端配合,将html转换成一个字符串,主要是图片要用特殊格式)

1.2.注入了图片链接,为了方便点击webView中的图片而跳转。

1.3.这是一个FrameLayout动态加载的WebView,布局中没有任何声明这个WebView。

2.源代码及应用

2.1.源代码如下,可以直接Copy。

public class MarkdownView extends WebView {
private static final String TAG = MarkdownView.class.getSimpleName();
// 带有点击的图片 => 为了防止被转换,提前转化为 html
// [text ![text](image_url) text](link) => <a href="link" ><img src="data:image_url" /></a>
private static final String IMAGE_LINK_PATTERN = "\\[(.*)!\\[(.*)\\]\\((.*)\\)(.*)\\]\\((.*)\\)";
private static final String IMAGE_LINK_REPLACE = "<a href=\"$5\" >$1<img src=\"$3\" />$4</a>";
// 纯图片 => 添加点击跳转,方便后期拦截
// ![text](image_url) => <img class="gcs-img-sign" src="data:image_url" />
private static final String IMAGE_PATTERN = "!\\[(.*)\\]\\((.*)\\)";
private static final String IMAGE_REPLACE = "<img class=\"gcs-img-sign\" src=\"$2\" />"; private String mPreviewText; public MarkdownView(Context context) {
this(context, null);
} public MarkdownView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
} @SuppressLint({"AddJavascriptInterface", "SetJavaScriptEnabled"})
public MarkdownView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
if (isInEditMode()) {
return;
}
WebSettings settings = getSettings();
settings.setJavaScriptEnabled(true);
settings.setDomStorageEnabled(true);
settings.setDatabaseEnabled(true);
initialize();
} private void initialize() {
loadUrl("file:///android_asset/html/preview.html");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
getSettings().setAllowUniversalAccessFromFileURLs(true);
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
} setWebChromeClient(new WebChromeClient() {
@SuppressLint("JavascriptInterface")
@Override
public void onProgressChanged(WebView view, int newProgress) {
super.onProgressChanged(view, newProgress);
if (newProgress == 100) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
loadUrl(mPreviewText);
} else {
evaluateJavascript(mPreviewText, null);
}
}
}
});
} public void loadMarkdownFromFile(File markdownFile) {
String mdText = "";
try {
FileInputStream fileInputStream = new FileInputStream(markdownFile);
InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream);
BufferedReader bufferedReader = new BufferedReader(inputStreamReader);
String readText;
StringBuilder stringBuilder = new StringBuilder();
while ((readText = bufferedReader.readLine()) != null) {
stringBuilder.append(readText);
stringBuilder.append("\n");
}
fileInputStream.close();
mdText = stringBuilder.toString();
} catch (FileNotFoundException e) {
Log.e(TAG, "FileNotFoundException:" + e);
} catch (IOException e) {
Log.e(TAG, "IOException:" + e);
}
setMarkDownText(mdText);
} public void loadMarkdownFromAssets(String assetsFilePath) {
try {
StringBuilder buf = new StringBuilder();
InputStream json = getContext().getAssets().open(assetsFilePath);
BufferedReader in = new BufferedReader(new InputStreamReader(json, "UTF-8"));
String str;
while ((str = in.readLine()) != null) {
buf.append(str).append("\n");
}
in.close();
setMarkDownText(buf.toString());
} catch (IOException e) {
e.printStackTrace();
}
} public void setMarkDownText(String markdownText) {
String injectMdText = injectImageLink(markdownText);
String escMdText = escapeForText(injectMdText);
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.KITKAT) {
mPreviewText = String.format("javascript:preview('%s')", escMdText);
} else {
mPreviewText = String.format("preview('%s')", escMdText);
}
initialize();
} /**
* 注入图片链接
*/
private String injectImageLink(String mdText) {
// TODO 修复代码区md格式图片被替换问题
mdText = mdText.replaceAll(IMAGE_LINK_PATTERN, IMAGE_LINK_REPLACE);
mdText = mdText.replaceAll(IMAGE_PATTERN, IMAGE_REPLACE);
return mdText;
} private String escapeForText(String mdText) {
String escText = mdText.replace("\n", "\\\\n");
escText = escText.replace("'", "\\\'");
escText = escText.replace("\r", "");
return escText;
} @Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isInEditMode()) {
canvas.drawColor(Color.WHITE);
canvas.translate(canvas.getWidth() / 2, 30);
Paint paint = new Paint();
paint.setTextAlign(Paint.Align.CENTER);
paint.setTextSize(30);
paint.setColor(Color.GRAY);
canvas.drawText("MarkdownView", -30, 0, paint);
}
}
}

2.2.然后如何动态加载WebView。

  

2.3.从缓存中获取字符串

  

  这个body就是一些缓存的数据了。还要进行转换才能得到html。

3.局部分析

3.1.成员变量的定义

  

  因为这里用到了将网页内容缓存。

  所以缓存后的数据,特别是缓存后的图片就变成

  ![text](image_url)这样的东西了

  [text![text](image_url)text](link)这样的东西了

  然后需要替换成原始的html。所以就用到了2个模板来替换。

  private String mPreviewText; 就是缓存的html内容。

3.2.有三个构造函数

  一个参数的构造函数

  

  

  两个参数的构造函数

  

  三个参数的构造函数

  

  这是最重要的构造函数。

  setJavaScriptEnabled(true)==>支持js

  setDomStorageEnabled(true)==>开启DOM storage API功能

  setDatabaseEnabled(true)==>开启database storage API功能

3.3.初始化函数initialize()

  

  首先加载本地文件(file://android_asset/html/preview.html)

  为了防止webView加载一些链接出现白板现象

  这里需要判断一下如果SDK>=16,需要设置:

    getSettings().setAllowUniversalAccessFromFileURLs(true);

  为了防止加载https的URL时在5.0以上加载不了,5.0以下可以加载,SDK>=21,需要设置:

    getSettings().setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);

  然后设置一个新的WebChromeClient

    当newProgress到百分之百了,需要判断SDK<19

    小于19的话,执行loadUrl(缓存text);

    大于19的话,执行evaluateJavascript(缓存text,null);==>专门用于异步调用javascript方法,有一个回调。

    

3.4.加载一个缓存文件

  

  作用就是:先从一个文件中读取字符,存放到一个字符串中,然后再调用setMarkDownText(字符串);

3.5.加载一个缓存资源

  

  作用:从应用的资源文件中获取字符流,然后转换成字符串。

3.6.将缓存数据替换成html标签

  

  首先是将图片替换成正常的html

  然后是将一些制表符、换行符替换成正常的html

  最后再执行初始化函数。

3.7.注入图片链接,将图片翻译成正常的html

  

3.8.将换行符,特殊字符,翻译成正常的html

  

3.9.重写WebView的onDraw函数

   重画WebView的界面。

  

  这个函数估计没什么用,我注释掉以及修改代码都没有反应。

  但是我将isInEditMode()删除之后就有影响了。可能这个只有在编辑模式下才需要这样设置的。

Android 自定义WebView 实现可以加载缓存数据的更多相关文章

  1. Spring Boot 启动以后然后再加载缓存数据 CommandLineRunner

    实际应用中,我们会有在项目服务启动完成以后去加载一些数据或做一些事情(比如缓存)这样的需求. 为了解决这样的问题,Spring Boot 为我们提供了一个方法,通过实现接口 CommandLineRu ...

  2. Android项目框架之图片加载框架的选择

    本文来自http://blog.csdn.net/liuxian13183/ ,引用必须注明出处! 从Android爆发以后,自定义的控件如EditTextWithDelete.ActionBar.P ...

  3. 控件WebView网页的加载

    Android:控件WebView网页的加载 WebView可以使得网页轻松的内嵌到app里,还可以直接跟js相互调用. webview有两个方法:setWebChromeClient 和 setWe ...

  4. [MISSAJJ原创]cell内 通过SDWebImage自定义创建动态菊花加载指示器

    最后更新已经放到了github上了 MISSAJJ自己写的一个基于SDWebImage自定义的管理网络图片加载的工具类(普通图片加载,渐现Alpha图片加载,菊花Indicator动画加载) 经常在项 ...

  5. android优化从网络中加载图片速度。。

    从网络中加载图片主要要注意两个方面的问题: 1.内存管理:图片占的内存很大,假如图片数量多,很容易让系统抛出out of memory的异常. 同时我们也要注意不同android版本中内存管理的区别. ...

  6. Android引入高速缓存的异步加载全分辨率

    Android引进高速缓存的异步加载全分辨率 为什么要缓存 通过图像缩放,我们这样做是对的异步加载优化的大图,但现在的App这不仅是一款高清大图.图.动不动就是图文混排.以图代文,假设这些图片都载入到 ...

  7. 浅试 Webview 一app 加载 H5小游戏

    整体架构: InventionActivity:实现UI的实例化,基本的按钮Activity之间跳转 GameActivity:实现UI的实例化,Webview的基本使用 MyProgressDial ...

  8. Xamarin Android Fragment的两种加载方式

    android Fragment的重点: 3.0版本后引入,即minSdk要大于11 Fragment需要嵌套在Activity中使用,当然也可以嵌套到另外一个Fragment中,但这个被嵌套的Fra ...

  9. Android 应用开发 之通过AsyncTask与ThreadPool(线程池)两种方式异步加载大量数据的分析与对比--转载

     在加载大量数据的时候,经常会用到异步加载,所谓异步加载,就是把耗时的工作放到子线程里执行,当数据加载完毕的时候再到主线程进行UI刷新.在数据量非常大的情况下,我们通常会使用两种技术来进行异步加载,一 ...

随机推荐

  1. 《ArcGIS Runtime SDK for Android开发笔记》——(9)、空间数据的容器-地图MapView

    1.前言 在上一篇内容里介绍了 关于ArcGIS Android开发的未来(“Quartz”版Beta)相关内容,期间也提到了关于API接口的重构,开发思路的调整,根据2015UC资料也可以知道新版预 ...

  2. 如何在SecureCRT中给linux上传和下载文件

    方法/步骤     需要上传或者下载,需要使用rz和sz命令.如果linux上没有这两个命令工具,则需要先安装.可以使用yum安装.运行命令yum install lrzsz.   安装完成后就可以使 ...

  3. 笨办法学Python(四)

    习题 4: 变量(variable)和命名 你已经学会了 print 和算术运算.下一步你要学的是“变量”.在编程中,变量只不过是用来指代某个东西的名字.程序员通过使用变量名可以让他们的程序读起来更像 ...

  4. python从字符串中提取数字,使用正则表达式

    使用正则表达式 import re D = re.findall(r"\d+\.?\d*",line) print(D) -7.23246 10.8959 5.19534 0.06 ...

  5. 支持多域名的免费SSL证书

    知乎网友称其支持多域名: https://www.zhihu.com/question/19578422 配置教程: https://www.cnblogs.com/duanweishi/p/8483 ...

  6. *521. Longest Uncommon Subsequence I (bit manipulation 2^n)

    Given a group of two strings, you need to find the longest uncommon subsequence of this group of two ...

  7. NO.003-2018.02.08《江城子·乙卯正月二十日夜记梦》宋代:苏轼

    江城子·乙卯正月二十日夜记梦_古诗文网 江城子·乙卯正月二十日夜记梦 乙卯:公元1075年,即北宋熙宁八年. 宋代:苏轼 十年生死两茫茫,不思量,自难忘.千里孤坟,无处话凄凉.纵使相逢应不识,尘满面, ...

  8. IOS中 copy ,strong ,weak ,assign使用区别

      .@property属性的用法 * weak(assign) :  代理\UI控件 * strong(retain) : 数组.模型)其他对象(除代理\UI控件\字符串以外的对象) * copy ...

  9. 轻量级HTTP服务器Nginx(入门与安装篇)

    轻量级HTTP服务器Nginx(入门篇)   文章来源于南非蚂蚁   一.什么是Nginx 相信很多读者都对Apache非常熟悉,与Apache类似,Nginx是一款高性能的HTTP和反向代理服务器软 ...

  10. 2018.8.6 学习 log4j.properties 配置文件

    配置文件的话第一步当然是解决乱码问题 Eclipse中properties文件中文乱码解决方式 打开eclipse的properties文件时你会发现,其中部分中文注释乱码了,下面将写出如何设置pro ...