基于Android的电子词典设计
基于Android的电子词典设计
单词数据的爬取
借助Python的Requests库和lxml库
Requests
Requests是一个功能强大、简单易用的HTTP请求库,主要用来发起请求和获取响应内容,对应的方法为get方法。
首先,使用HTTP库向词典网站发起请求,即发送一个Request,其中包含请求方式、请求URL、请求头和请求体,其中构建HTTP的请求头的目的在于伪装成浏览器与词典网站进行通信,如果服务器能正常响应,则会得到一个Response,包含响应状态、响应头和响应体,最后通过Text方法即可得到网页的源代码。
XPath
XPath,全称 XML Path Language,即XML路径语言,它是一门在XML文档中查找信息的语言。
最初是用来搜寻XML文档的,但同样适用于HTML文档的搜索。
所以在做爬虫时完全可以使用XPath做相应的信息抽取。
Python为此提供了lxml第三方库。
XPath以XML树结构为基础,能够在数据的结构树中查找各类节点,比如属性节点、文本节点和元素节点等等。
在检查元素中右键即可复制它的XPath路径,分析规律并且结合XPath的表达式语法,就可获取相关文本内容。
多进程
使用Multiprocessing的Pool方法,设置一定数量的进程放在进程池中提供给用户调用。
新请求提交时,首先判断池有没有满,若没有满,就开辟一个新进程执行,若已满就等待池中的某个进程结束。
Pool类适用于需要执行的目标比较多而且手动限制进程数量又非常复杂的情况。
本项目设置一定进程数量的进程池,通过循环将所有需要爬虫的单词异步执行,也就是非阻塞的方式。
执行完毕后,关闭进程池并继续执行主进程。
SQLite
当时遇到的问题多进程爬取的数据无法同时向SQLite数据库中保存,因此先爬取内容到TXT,再保存到数据库中。
在Python中导入SQLite3模块,打开或连接数据库,若没有数据库则新建;然后,创建游标对象,使用它的execute()方法执行SQL命令,即创建表和插入数据;最后,关闭游标和连接并提交事务。
界面设计
根布局就是DrawerLayout
,在根布局之后又主要分为两大部分,第一部分就是我们主界面的内容,第二部分是左边滑出的布局,这里用NavitationView来代替。
线性布局(LinearLayout
)和相对布局(RelativeLayout
)实现。
线性布局是将界面中的全部控件按照水平或竖直方向进行排列,同时它也是最基本的布局方式。
相对布局则是通过控件之间的相对位置关系实现控件的摆放,有利于适配不同屏幕大小的手机,因此使用更为普遍。
一般布局都是用dp
,字体用sp
(手机字体调大了,APP的字体会随之变大)来布局的,用来适配移动端分辨率。
API或SDK
调用百度API实现句子翻译的功能。
调用讯飞开放平台的SDK实现语音输入的功能。
调用Stanford Core NLP的JAR文件实现句子分析(词性分析和词形还原)。
API
API 的特点
通信
首先我们要明白的是 API 是和通信有关的,是用于应用(服务)与其他应用(服务)对话所定义的协议。
API 全称 Application Programming Interface,即「应用程序接口」。
一般是指一些预先定义的函数,目的是供应用程序与开发人员基于某软件或硬件得以访问一组程序的能力,而又无需访问源码,或理解内部工作机制的细节。
以 JS为例,当你想要实现一个数组排序的功能时,你是会先手写一个排序算法,还是直接使用sort()
函数?我想你心里是有答案的。
抽象
其次,我们要理解,API 的另一个重要特点——抽象。
在你的 APP 和 服务之间,API 抽象出所有复杂的逻辑,简化了调用过程,这使得你只需要考虑获取所需的数据即可。
标准化
API 是标准化的,这意味着存在有关如何定义 API 的行业标准,比如 SOAP、REST、GraphQL 等。
SDK
SDK 全称 Software Development Kit,软件开发工具包。
一般都是一些软件工程师为特定的软件包、软件框架、硬件平台、操作系统等建立应用软件时的开发工具的集合。
通俗来讲就是第三方服务商提供的实现产品软件某项功能的工具包。例如 JDK 就是一种 SDK。
以 OCR 应用为例,如果使用了某厂商的 SDK 服务,那么我们连 HTTP 请求的构建都不需要了,仅调用一个方法,可能的代码如下图所示。
1 | OCRResult res = ocrClient.ocr("pic.jpg").getResult(); |
通过调用这行代码,SDK 会自动封装 API 请求,而且作为响应,你获得的结果也不一定是 JSON 对象,也有可能是代码,例如上述代码段里的OCRResult
,这是因为 SDK 也已经将 JSON 对象反序列化成你需要的对象,比如一个 Java Model。
SDK 相当于开发集成工具环境,API 就是数据接口。API 可以在 SDK 提供的“环境”里请求。同样的,这里的“环境”也是一个抽象的概念。如果不使用 SDK,也可以直接调用 API,只不过,这个环境就要由开发者自己实现了。
区别
其实从上面的内容,我们也已了解到,API 在更多场合下更像是 SDK 的一个子集,他们的区别如下:
- API 通常是一个函数,有特定的功能;而 SDK 是一个很多功能函数的集合体,更像是一个工具包。
- API 通常扮演数据接口的形象,SDK 相当于一个工具环境,通常是需要在 SDK 的环境下调用 APl。
- SDK 相较于 API 封装层次更高。
框架
MVC 框架
在 Smalltalk 发展到 80 版本的时候,MVC 框架被一位工程师提出来,MVC 框架的出现在很大程度上降低了应用程序的管理难度,之后被广泛应用于构架桌面和服务器应用程序。MVC 框架如图2所示(实线表示调用,虚线表示通知)。
Controller 是 MVC 中的 C,指控制层,在 Controller 层会接收用户所有的操作,并根据写好的代码进行相应的操作——触发 Model 层,或者触发 View 层,抑或是两者都触发。
需要注意:Controller 层触发 View 层时,并不会更新 View 层中的数据,View 层中的数据是通过监听 Model 层数据变化而自动更新的,与 Controller 层无关。
MVC 框架主要有两个缺点:
- MVC 框架的大部分逻辑都集中在 Controller 层,代码量也都集中在 Controller 层,这带给 Controller 层很大的压力,而已经有独立处理事件能力的 View 层却没有用到。
- 还有一个问题,就是 Controller 层和 View 层之间是一一对应的,断绝了 View 层复用的可能,因而产生了很多冗余代码。
为了解决以上问题,MVP 框架被提出来。
Android MVC
View:XML布局文件。 Model:实体模型(数据的获取、存储、数据状态变化)。 Controller:对应于Activity,处理数据、业务和UI。
从上面这个结构来看,Android本身的设计还是符合MVC架构的,但是Android中纯粹作为View的XML视图功能太弱,我们大量处理View的逻辑只能写在Activity中,这样Activity就充当了View和Controller两个角色,直接导致Activity中的代码大爆炸。相信大多数Android开发者都遇到过一个Acitivty数以千行的代码情况吧!所以,更贴切的说法是,这个MVC结构最终其实只是一个Model-View(Activity:View&Controller)的结构。
MVP 框架
MVP 指 Model-View-Presenter。
MVP 框架比 MVC 框架大概晚出现 20 年,1990 年,MVP 由 IBM 的子公司 Taligent 公司提出,它最开始好像是一个用于 C++ CommonPoint 的框架,这种说法正确与否这里不做考证,先来看一下 MVP 框架图。
在 MVC 框架中,View 层可以通过访问 Model 层来更新,但在 MVP 框架中,View 层不能再直接访问 Model 层,必须通过 Presenter 层提供的接口,然后 Presenter 层再去访问 Model 层。
这看起来有点多此一举,但用处着实不小,主要有两点:
- 首先是因为 Model 层和 View 层都必须通过 Presenter 层来传递信息,所以完全分离了 View 层和 Model 层,也就是说,View 层与 Model 层一点关系也没有,双方是不知道彼此存在的,在它们眼里,只有 Presenter 层。
- 其次,因为 View 层与 Model 层没有关系,所以 View 层可以抽离出来做成组件,在复用性上比 MVC 模型好很多。
MVP 框架流程如图所示:
从图中可以看出,View 层与 Model 层确实互不干涉,View 层也自由了很多。但还是有问题,因为 View 层和 Model 层都需经过 Presenter 层,致使 Presenter 层比较复杂,维护起来会有一定的问题。
而且因为没有绑定数据,所有数据都需要 Presenter 层进行“手动同步”,代码量比较大,虽然比 MVC 模型好很多,但也是有比较多的冗余部分。
为了让 View 层和 Model 的数据始终保持一致,避免同步,MVVM 框架出现了。
Android MVP
**View: **对应于Activity和XML,负责View的绘制以及与用户的交互。 **Model: **依然是实体模型。 **Presenter: **负责完成View与Model间的交互和业务逻辑。
前面我们说,Activity充当了View和Controller两个角色,MVP就能很好地解决这个问题,其核心理念是通过一个抽象的View接口(不是真正的View层)将Presenter与真正的View层进行解耦。Persenter持有该View接口,对该接口进行操作,而不是直接操作View层。这样就可以把视图操作和业务逻辑解耦,从而让Activity成为真正的View层。
但MVP也存在一些弊端:
- Presenter(以下简称P)层与View(以下简称V)层是通过接口进行交互的,接口粒度不好控制。粒度太小,就会存在大量接口的情况,使代码太过碎版化;粒度太大,解耦效果不好。同时对于UI的输入和数据的变化,需要手动调用V层或者P层相关的接口,相对来说缺乏自动性、监听性。如果数据的变化能自动响应到UI、UI的输入能自动更新到数据,那该多好!
- MVP是以UI为驱动的模型,更新UI都需要保证能获取到控件的引用,同时更新UI的时候要考虑当前是否是UI线程,也要考虑Activity的生命周期(是否已经销毁等)。
- MVP是以UI和事件为驱动的传统模型,数据都是被动地通过UI控件做展示,但是由于数据的时变性,我们更希望数据能转被动为主动,希望数据能更有活性,由数据来驱动UI。
- V层与P层还是有一定的耦合度。一旦V层某个UI元素更改,那么对应的接口就必须得改,数据如何映射到UI上、事件监听接口这些都需要转变,牵一发而动全身。如果这一层也能解耦就更好了。
- 复杂的业务同时也可能会导致P层太大,代码臃肿的问题依然不能解决。
MVVM 框架
MVVM 最早是由微软在使用 Windows Presentation Foundation 和 SilverLight 时定义的,2005 年微软正式宣布 MVVM 的存在。VM 是 ViewModel 层,ViewModel 层把 Model 层和 View 层的数据同步自动化了,解决了 MVP 框架中数据同步比较麻烦的问题,不仅减轻了 ViewModel 层的压力,同时使得数据处理更加方便——只需告诉 View 层展示的数据是 Model 层中的哪一部分即可。
读者可能感觉 MVVM 的框架图与 MVP 的框架图相似,确实如此,两者都是从 View 层开始触发用户的操作,之后经过第三层,最后到达 Model 层。但是关键问题是这第三层的内容, ViewModel 层双向绑定了 View 层和 Model 层,因此,随着 View 层的数据变化,系统会自动修改 Model 层的数据,反之同理。而 Presenter 层是采用手动写方法来调用或者修改 View 层和 Model 层,两者孰优孰劣不言而喻。
从图7可以看出,View 层和 Model 层之间数据的传递也经过了 ViewModel 层, ViewModel 层并没有对其进行“手动绑定”,不仅使速度有了一定的提高,代码量也减少很多,相比于 MVC 和 MVP,MVVM 有了长足的进步。
至于双向数据绑定,可以这样理解:双向数据绑定是一个模板引擎,它会根据数据的变化实时渲染。这种说法可能不是很恰当,但是很好理解。
如图所示,View 层和 Model 层之间的修改都会同步到对方。
MVVM 模型中数据绑定方法一般有以下3种:
- 数据劫持
- 发布-订阅模式
- 脏值检查
Vue.js 使用的是数据劫持和发布-订阅模式两种方法。
首先来了解三个概念:
- Observer:数据监听器
- Compiler:指定解析器
- Watcher:订阅者
Observer 用于监听数据变化,如果数据发生改变,不论是在 View 层还是 Model 层, Oberver 都会知道,然后告诉 Watcher。Compiler 的作用是对数据进行解析,之后绑定指定的事件,在这里主要用于更新视图。
Vue.js 数据绑定的流程:首先将需要绑定的数据用数据劫持方法找出来,之后用 Observer 监听这堆数据,如果数据发生变化,Observer 就会告诉 Watcher,然后 Watcher 会决定让哪个 Compiler 去做出相应的操作,这样就完成了数据的双向绑定。
Android MVVM
**View: **对应于Activity和XML,负责View的绘制以及与用户交互。 **Model: **实体模型。 **ViewModel: **负责完成View与Model间的交互,负责业务逻辑。
Android为此提供了一套架构组件,主要有LiveData、ViewModel 和Room。
- LiveData是用来构建数据对象,当基础数据库改变时会通知视图;
- ViewModel是用来存储和管理与界面相关的数据,这些数据在应用跳转时不会被销毁;
- Room是一个SQLite对象映射库,它可以轻松地将SQLite表数据转换为Java对象,主要负责底层数据库的处理,本文调用其中的Dao接口来执行数据库增删改查等操作,利用 Database创建和管理数据库。同时,Room可以为SQLite语句提供编译时检查,并能够返回RxJava、Flowable和LiveData可观察对象。
- Repository是一个仓库类,介于视图层与数据映射层(数据访问层)之间。它的作用是让视图层感觉不到数据访问层的存在,提供了一个类似集合的接口给视图层进行访问。
采用MVVM模式最大的优点就是编写代码是思路明确,视图层与模型层完全解耦,方便后期的管理与维护,在代码中的其他地方使用数据库相关的操作只需一行代码,极其方便。
MVC、MVP 和 MVVM三者的区别和优劣
详细了解 MV 系列框架之后,相信读者已经了解 MVC、MVP、MVVM 这三者的优劣了。其实从 MVC 到 MVP 再到 MVVM,是一个不断进步的过程,后两者都是在 MVC 的基础上做的变化,使 MVC 更进一步,使用起来也更加方便。
MVC、MVP、MVVM 三者的主要区别就在于除 View 层和 Model 层之外的第三层,这一层的不同使得 MV 系列框架区分开来。
其实很难说出 MVC、MVP、MVVM 哪一个更好,从表面上看,显然是 MVVM 最好,使用起来更方便,代码相对也较少。但问题是 MVVM 的框架体积较大,相比于 MVC 的不用框架、MVP 的 4KB 框架,MVVM 遥遥领先。虽然 MVVM 框架可以单独引用,但现在更多使用前端脚手架工具进行开发,并且使用打包工具,这样一来,它跟 MVC 相比,体积是天差地别。
虽然机能过剩更令人放心,但是轻巧一些的框架会令项目锦上添花。所以要根据实际项目的需求来选择 MVC、MVP、MVVM,只有最适合的模式才是最好的框架。
每项新技术都要经历一个从一开始不被大众认可到后来人尽皆知的过程,其实就是一个改变的过程。只要这个框架能跟上时代的潮流,满足人们开发的需求,这就是一个合适的框架。