一款漫画APP的实现(三)- 数据拉取 ② - 拉取速度改进
在上篇博客里我们谈到了漫画数据的拉取思路以及获取数据的基本操作,不过最后我们也遇到了一些问题。
上篇里,我们发现获取到的数据中,只有图片是无法正常显示的,而在文章最后我们也知道了造成这一问题的原因就在于,Jsoup本身无法渲染JS的动态内容,从而导致了获取到的图片URL只是网页本来的静态数据。
本篇我就分享一下针对这个问题的其中一种解决方案吧。
如果您还没有看过之前的篇章,可以直接点击下列标题前往查看:
- 一款漫画APP的实现(一)- 前言
- 一款漫画APP的实现(二)- 数据拉取 ①
本篇说明性内容较多,还请耐心观看QAQ。
在开始前,我们可以稍微思考一下,我们平时是怎么看到这些动态生成的图片URL的呢?嗯是的,当然是浏览器帮忙处理好的了。
如果Jsoup无法动态加载JS,那如果我们拉个帮手来呢?嗯,好主意。
对的,本篇我们要做的就是拉一个“浏览器”来做帮手!
不过你可能要吐槽了,用浏览器来辅助加载,那速度也太慢了吧?平时加载一个网页都十分费劲了。
是的,但也不全是。平时我们使用的浏览器,为了兼容各种情况,所以性能会有所妥协。但我们要实现的功能,并非真的去加载一整个完整的网页,我们只需要获取到图片的动态Tag值就够了。
安卓本身也自带了WebView这样一个用来加载网页的控件,不过你要是真的用过的话,会发现这个控件加载网页的速度非常慢,甚至网页也会经常加载不出来。
那么我们可能会考虑使用其他厂商提供的一些浏览器内核来进行优化。
比如腾讯的X5内核,也就是QQ、微信上用来加载网页那个(有兴趣可以点击这里前往下载),不过经过我的测试发现,将QX5内核应用到我们当前这个项目中,带来的改进效果并不明显,稳定性是提高了,但是带来的加载速度提升只有1~2倍。
比方说在测试中,我加载下列示例APP漫画首页内容所需要的时间:
// 安卓自带的WebView
time = 9 ~ 11s;// 腾讯X5内核
time = 5 ~ 10s;
这样的加载时间真的是考验用户的耐心啊...
不过呢今天我们用到的内核,并非上述二者。这里我推荐一个加载速度特别快的轻量级内核:AgentWeb(GitHub地址)
有多快呢?经过测试,我们来看看本项目应用上述三种内核的对比数据:
// 安卓自带的WebView
time = 9 ~ 11s;// 腾讯X5内核
time = 5 ~ 10s;// AgentWeb
time = 1 ~ 2s;
这带来了与WebView相比将近10倍的速度提升!那无疑能够满足我们的项目需求!
AgentWeb的GitHub开源地址我已经贴在上面了
如果不想太折腾的也可以使用我上传好的一个通用类(点这里),里面将一系列本项目会用到的东西都集成封装好了,直接下载好粘贴到自己的项目就行了。
那么回归正篇,解决图片src动态值获取失败的思路其实很简单:每次拉取数据时,就模拟浏览器加载一次网页,将渲染好的源码交给Jsoup解析。
这时候跟Jsoup的connect方法获取静态网页不同的是,我们要获取的是渲染加载了JS后的网页,具体该怎么操作呢?
大体思路就是:
新建两个类,分别继承 WebViewClient 和 WebChromeClient,然后重写 onPageFinished、onReceivedSslError、onProgressChanged等方法,最后在重写方法里将源码数据传给一个自定义的JavaScript接口类。
为了节省大家的时间,我在上面给出的AgentWeb封装类里已经把这些步骤都集成好了,大家直接对onWebLoading 这个回调函数里的html值进行处理就OK了。
封装类下载地址:点这里
// 初始化
AWCoreController awCoreController = new AWCoreController(Activity或Fragment, new AWCoreController.OnAgentDataLoadingListener() {@Overridepublic void onWebLoading(String html) {// html为加载中的目标网页源码}});
// 加载URL
awCoreController.loadUrl(url);
值得注意的是:上述onWebLoading(html)的html是实时加载的网页源码。也就是说,它不是最终的网页源码,所以在处理时我们需要进行一些简单的逻辑判断:
// 比如先获取到漫画图片src值
String src = document.select("div.mh_comicpic>img").attr("src");if (src != null && !src.equals("")) {// 判断src是否为空或静态网页值(这里代码没写)
}
再唠叨一下,至于为什么我传回来的是实时的html而不是最终html,是因为如果完整加载整个网页后再回传HTML数据,比单纯只获取<img>标签的一个动态值所花的时间要长。按照上面的测试数据,前者可能需要1~2s,而后者只用0.5s左右就够了。
封装类的使用就先说到这吧。
当然如果你想自己实现Web加载的功能,也可以参考上述封装类的源码来自行编写。
再之后我们就可以使用Jsoup的 Parse() 方法来直接解析HTML数据了:
Document document = Jsoup.parse(html)
而对于那些不需要加载图片数据的地方,比如漫画目录,我们可以直接使用Jsoup的connect("url").get()方法,速度会快很多(毕竟不用加载JS嘛)
Document document = Jsoup.connect(comic.getComicWebUrl()).validateTLSCertificates(false).get();
那么之后的操作其实就跟上一篇差不多了。
总的来说就是:
1、如果需要加载图片的动态src值,那么建议采取本篇介绍的解决方案。相对应使用Jsoup的Parse()方法。
2、如果不需要加载图片,只有单纯的文本数据需求的话,直接使用上一篇介绍的方法就行了,这样加载速度会非常快。相对应使用Jsoup的connect()方法。
如果大家有什么更好的方法或建议,欢迎在评论区指出~
【本项目DEMO源码】:ComicDemoSourceCode
===== 补充说明 ======
有人问到最关键的浏览漫画图片部分没怎么提,其实整体思路跟其它部分是差不多的
这里我稍微提一下吧:
大部分的网站浏览漫画基本是一个网页只显示一张图片,这时候怎么办呢?我们可以【递归加载】所有网页,把其中的图片链接提取出来。可实际上,等待它模拟加载完所有图片再显示的话,速度整体是很慢的。
所以我建议采取以下方法:
1、在你的加载函数里新加一个接口,每加载完成一个网页就回调一次图片src地址,再更新你的RecyclerView或者ListView就可以了,不必等待全部递归加载完再回调,代码如下(仅做参考):
@Override
protected void loadPicsData(final String html) {try {if (!isLoaded) {Document document = Jsoup.parse(html);String src = document.select("img#mhpic").first().attr("src");if (src != null && src != "" && !src.isEmpty() && !isLoaded && !src.equals(lastSrc)) {// lastSrc = src;// isLoaded = true;// 每加载完成一次更新一张图片mHandler.sendMessage(getMessage(src, LOAD_SUCCESS));// 准备递归加载下一张图String nextPage = document.select("div#mhimg0>a").attr("href");if (nextPage != null && !nextPage.isEmpty() && nextPage != "") {// 递归加载load(currentUrl + nextPage);} else {// 递归完成的操作}}}} catch (Exception e) {// Log.d(TAG, "loadPicsData:错误 " + e.toString());}
}
Handler里接口函数的回调:
protected Handler mHandler = new Handler() {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);switch (msg.what) {case LOAD_SUCCESS:dataLoadListener.onLoadFinished(msg.obj, null);break;case LOAD_FAILURE:dataLoadListener.onLoadFinished(null, (Exception) msg.obj);break;default:break;}}
};
2、有些网站图片的url地址是有规律排列的,只要找到规律(比如:图片1是xxx_1,图2是xxx_2,那么图3基本就是xxx_3了,以此类推...),这时候只需要加载一张,就能把剩下的URL都自己构建出来了(当然这个都是碰运气的了...)
所以通用方法就是方法1啦
一款漫画APP的实现(三)- 数据拉取 ② - 拉取速度改进相关推荐
- 一款漫画APP的实现(二)- 数据拉取 ①
本篇主要分享一下之前提到的漫画APP中数据拉取的技术实现 在开始之前,我们需要明确两点:我们的漫画数据从哪来?利用什么工具获取这些数据? 对于第一点,由于我们大部分人可能都没有能直接获取漫画原稿链接的 ...
- 一款漫画APP的实现(一)- 前言
对于那些喜欢看漫画的小伙伴来说,手机上几乎常备了一款漫画app,像腾讯动漫.看漫画等等,都是比较优秀的漫画应用,不过这些正版app都有个共同点--在一定程度上会收费 想我这种不喜欢氪金的人来说,最好就 ...
- 用Swift实现一款天气预报APP(三)
这个系列的目录: 用Swift实现一款天气预报APP(一) 用Swift实现一款天气预报APP(二) 用Swift实现一款天气预报APP(三) 通过前面的学习,一个天气预报的APP已经基本可用了.至少 ...
- 一款仿知音漫客的漫画 APP
Q_Comic 项目地址:LinYaoTian/Q_Comic 简介:一款仿知音漫客的漫画 APP 更多:作者 提 Bug 标签: 仿知音漫客 APP,目前已经完成了基本浏览.搜索.收藏等基本功 ...
- 公安摧毁6款淫秽漫画APP,查冻涉案资金5100余万元
央广网北京8月11日消息 据公安部网站消息,全国公安机关夏季治安打击整治"百日行动"开展以来,公安机关紧盯侵害未成年人身心健康的违法犯罪活动,坚持"快准狠"重拳 ...
- 个人开发者做一款Android App需要知道的事情
在大学时, 自己是学计算机专业的,而且还和老师一起做过一年半的项目. 有时候是不是有这样的想法,做一个自己的网站.但一直未付诸行动. 2012年时, 终于付诸行动了,花了三个月,现学现卖, 熬夜通宵用 ...
- 从零开发一款笔记APP——神马笔记WhatsNote
从零开发一款笔记APP--神马笔记WhatsNote 一.主要功能 二.开发过程 三.优质的笔记应用 四.附录 一.主要功能 笔记的主要功能分为三个部分: 管理 目录--多层目录结构 标签--单层结构 ...
- 【Android】RecycleView简单仿漫画APP图片相关样式
真的真的想不到起什么标题好了,这次的内容真的是太简单了,没有什么挑战性,一天以内就完成了.最近在学kotlin,也会有一份kotlin的代码,鉴于很多人都是从java开始进行android开发的,ko ...
- 10款移动app安全测试工具推荐
移动互联网时代,我们的生活和工作深受 App 影响.伴随移动 App 的广泛应用,App 安全日益重要.本文介绍了 App 开发可能用到的安全测试工具. 当今,全球移动用户大约超过37亿.Google ...
最新文章
- plasma桌面设置好的面板消失了_Ubuntu Studio 将用 KDE Plasma 桌面环境替换 Xfce | Linux 中国...
- Tableau系列之使用日期
- swift - 根试图控制器的手势返回冲突 - push 新的tabbar控制器手势冲突
- 什么浏览器好用_手机浏览器不只UC,好用的浏览器还有这些
- 英特尔携手ATT和爱立信进行DIRECTV NOW流媒体直播服务的5G试验
- OpenCVQt学习之一——打开图片文件并显示
- iOS开发UI篇—控制器的创建
- 关于锐捷校园网断网的解决办法
- [Daozy][区块链 EOS 课程]第2课 EOS编译和启动
- ABP文档笔记 - 通知
- 【建模算法】Python调用Gurobi求解TSP问题
- matlab 语音识别为文字,语音识别(Speech Recognition)是让机器通过识别和理解过程把语音信号转变为相应的文本...
- Android实现平板的类股票列表联动
- App进程被回收问题总结
- 第3章(3.11~3.16节)模型细节/Kaggle实战【深度学习基础】--动手学深度学习【Tensorflow2.0版本】
- 转一位计算机牛人的心得,谈计算机和数学,很实用~
- x265 windwos使用wsl调试
- 桌面打开计算机没反应,点击显示桌面没反应? 显示桌面没反应解决方法
- 国外最牛逼的17种商业模式
- K-Means Clustering