急急急!有哪位大神知道中国铁路12306官网app里用户名忘记了(密码知道),在哪里能重新找回账号

android 一些开源框架链接
以下是github fork的框架链接:数据库:数据库框架LitePal&github:&/LitePalFramework/LitePal数据库框架LitePal&教程:http://blog.csdn.net/column/details/android-database-pro.html说明:LitePal 是一个开发者可以极其方便使用的SQLite数据库框架。可以完成数据库的基本操作,增删改查等等。可以很方便地集成到项目开发中使用。具体可以看链接的详细内容。xUtils:/androidKaKa/xUtils说明:xUtils有四大模块:DbUtils模块:android中的orm框架,一行代码就可以进行增删改查;支持事务,默认关闭;可通过注解自定义表名,列名,外键,唯一性约束,NOT NULL约束,CHECK约束等(需要混淆的时候请注解表名和列名);支持绑定外键,保存实体时外键关联实体自动保存或更新;自动加载外键关联实体,支持延时加载;支持链式表达查询,更直观的查询语义,参考下面的介绍或sample中的例子。ViewUtils模块:android中的ioc框架,完全注解方式就可以进行UI,资源和事件绑定;新的事件绑定方式,使用混淆工具混淆后仍可正常工作;目前支持常用的20种事件绑定,参见ViewCommonEventListener类和包com.lidroid.xutils.view.annotation.event。HttpUtils模块:支持同步,异步方式的请求;支持大文件上传,上传大文件不会oom;支持GET,POST,PUT,MOVE,COPY,DELETE,HEAD,OPTIONS,TRACE,CONNECT请求;下载支持301/302重定向,支持设置是否根据Content-Disposition重命名下载的文件;返回文本内容的请求(默认只启用了GET请求)支持缓存,可设置默认过期时间和针对当前请求的过期时间。BitmapUtils模块:加载bitmap的时候无需考虑bitmap加载过程中出现的oom和android容器快速滑动时候出现的图片错位等现象;支持加载网络图片和本地图片;内存管理使用lru算法,更好的管理bitmap内存;可配置线程加载线程数量,缓存大小,缓存路径,加载显示动画等...fresco:/androidKaKa/frescoawesome-android-libraries:/androidKaKa/awesome-android-libraries
最新教程周点击榜
微信扫一扫3371人阅读
android(65)
最近看了郭神的框架感觉愣牛逼牛逼之余也很好奇他是如何实现的好奇心害死猫啊跟随大神脚步看源码
先贴一下litepal.xml代码:
&?xml version=&1.0& encoding=&utf-8&?&
&!-- 数据库名 --&
&dbname value=&demo& &
&!-- 数据库版本 --&
&version value=&1& &
&/version&
&!-- 映射模型 --&
&mapping class=&com.sdufe.thea.guo.model.News& &
&/mapping&
&/litepal&
下面是litepal.xml对应函数中的属性代码:
解析xml文件中出现了这么一个函数:
* Analyze litepal.xml, and store the analyzed result in LitePalParser. Use
* DomParse to parse the configuration file as default. SAXParser and
* XmlPullParser is also optional, but not visible to developers.
public static void parseLitePalConfiguration() {
if (parser == null) {
parser = new LitePalParser();
parser.useSAXParser();
从函数名上就猜到使用了SAX解析xml,也不能胡乱猜,继续看郭哥的源码,赶紧去useSAXParser()看看到底是如何实现的
* Use SAXParser to parse the litepal.xml file. It will get the parsed
* result from LitePalContentHandler and stored in the instance of
* LitePalAttr.
* Note while analyzing litepal.xml file, ParseConfigurationFileException
* could be thrown. Be careful of writing litepal.xml file, or developer's
* application may be crash.
void useSAXParser() {
LitePalContentHandler handler =
SAXParserFactory factory = SAXParserFactory.newInstance();
XMLReader xmlReader = factory.newSAXParser().getXMLReader();
handler = new LitePalContentHandler();
xmlReader.setContentHandler(handler);
xmlReader.parse(new InputSource(getConfigInputStream()));
} catch (NotFoundException e) {
throw new ParseConfigurationFileException(
ParseConfigurationFileException.CAN_NOT_FIND_LITEPAL_FILE);
} catch (SAXException e) {
throw new ParseConfigurationFileException(
ParseConfigurationFileException.FILE_FORMAT_IS_NOT_CORRECT);
} catch (ParserConfigurationException e) {
throw new ParseConfigurationFileException(
ParseConfigurationFileException.PARSE_CONFIG_FAILED);
} catch (IOException e) {
throw new ParseConfigurationFileException(ParseConfigurationFileException.IO_EXCEPTION);
是的,你没有猜错,上面的就是SAX解析xml的格式了,使用SAX解析xml差不多就是这么个格式,不同的就在那个handler了,当然郭神的代码相当规范,向大神学习,要想知道他是怎么解析litepal.xml还是继续看handler的实现吧!这里只贴主要代码,不能弄得很长,长了就不太好了哈!
* Start analysis the litepal.xml file. Set all the parsed value into the
* LitePalAttr model.
public void startElement(String uri, String localName, String qName, Attributes attributes)
throws SAXException {
if (LitePalParser.NODE_DB_NAME.equalsIgnoreCase(localName)) {
for (int i = 0; i & attributes.getLength(); i++) {
if (LitePalParser.ATTR_VALUE.equalsIgnoreCase(attributes.getLocalName(i))) {
litePalAttr.setDbName(attributes.getValue(i).trim());
} else if (LitePalParser.NODE_VERSION.equalsIgnoreCase(localName)) {
for (int i = 0; i & attributes.getLength(); i++) {
if (LitePalParser.ATTR_VALUE.equalsIgnoreCase(attributes.getLocalName(i))) {
litePalAttr.setVersion(Integer.parseInt(attributes.getValue(i).trim()));
} else if (LitePalParser.NODE_MAPPING.equalsIgnoreCase(localName)) {
for (int i = 0; i & attributes.getLength(); i++) {
if (LitePalParser.ATTR_CLASS.equalsIgnoreCase(attributes.getLocalName(i))) {
litePalAttr.addClassName(attributes.getValue(i).trim());
} else if (LitePalParser.NODE_CASES.equalsIgnoreCase(localName)) {
for (int i = 0; i & attributes.getLength(); i++) {
if (LitePalParser.ATTR_VALUE.equalsIgnoreCase(attributes.getLocalName(i))) {
litePalAttr.setCases(attributes.getValue(i).trim());
}上面的就是handler的解析内容了,根据开始元素解释开始元素,个人猜测,既然是用SAX解析xml,就可以有多个Lite标签,所以我觉得可以使用LitePal框架可以建多个数据库,不过LitePal是继承自SQLite数据库,一般一个app应该不会有很多数据库吧,本来就很小!当然源代码中还有用Pull解析的xml,这里也贴一下代码
* Use XmlPullParser to parse the litepal.xml file. It will store the result
* in the instance of LitePalAttr.
* Note while analyzing litepal.xml file, ParseConfigurationFileException
* could be thrown. Be careful of writing litepal.xml file, or developer's
* application may be crash.
void usePullParse() {
LitePalAttr litePalAttr = LitePalAttr.getInstance();
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser xmlPullParser = factory.newPullParser();
xmlPullParser.setInput(getConfigInputStream(), &UTF-8&);
int eventType = xmlPullParser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
String nodeName = xmlPullParser.getName();
switch (eventType) {
case XmlPullParser.START_TAG: {
if (NODE_DB_NAME.equals(nodeName)) {
String dbName = xmlPullParser.getAttributeValue(&&, ATTR_VALUE);
litePalAttr.setDbName(dbName);
} else if (NODE_VERSION.equals(nodeName)) {
String version = xmlPullParser.getAttributeValue(&&, ATTR_VALUE);
litePalAttr.setVersion(Integer.parseInt(version));
} else if (NODE_MAPPING.equals(nodeName)) {
String className = xmlPullParser.getAttributeValue(&&, ATTR_CLASS);
litePalAttr.addClassName(className);
} else if (NODE_CASES.equals(nodeName)) {
String cases = xmlPullParser.getAttributeValue(&&, ATTR_VALUE);
litePalAttr.setCases(cases);
eventType = xmlPullParser.next();
} catch (XmlPullParserException e) {
throw new ParseConfigurationFileException(
ParseConfigurationFileException.FILE_FORMAT_IS_NOT_CORRECT);
} catch (IOException e) {
throw new ParseConfigurationFileException(ParseConfigurationFileException.IO_EXCEPTION);
当然知道了解析方法,知道了属性对应的函数,那他是如何找到的litepal.xml的呢?不急,我们继续看
* Iterates all files in the root of assets folder. If find litepal.xml,
* open this file and return the input stream. Or throw
* ParseConfigurationFileException.
* @return The input stream of litepal.xml.
* @throws IOException
private InputStream getConfigInputStream() throws IOException {
AssetManager assetManager = LitePalApplication.getContext().getAssets();
String[] fileNames = assetManager.list(&&);
if (fileNames != null && fileNames.length & 0) {
for (String fileName : fileNames) {
if (Const.LitePal.CONFIGURATION_FILE_NAME.equalsIgnoreCase(fileName)) {
return assetManager.open(fileName, AssetManager.ACCESS_BUFFER);
throw new ParseConfigurationFileException(
ParseConfigurationFileException.CAN_NOT_FIND_LITEPAL_FILE);
以上就是他找到本地litepal.xml的方法啦,通过getAssets()读到本地的asset里面的文件,那文件名跟Const.LitePal.CONFIGURATION_FILE_NAME对比,相同的话就读到本地文件了,当然我开始也有个疑问,我是否可以随便起个名字呢?这里当然不可以,因为asset可以有很多文件,他不知道要用哪一个,这里郭哥直接写死了,文件名只能叫litepal.xml
public static final String CONFIGURATION_FILE_NAME = &litepal.xml&;看到这,你应该大概连接到郭哥是怎么操作litepal.xml,理一理,首先你使用LitePal框架引进包之后,需要建一个litepal.xml文件,郭哥通过getAsset()读到本地asset文件夹的文件名,通过跟litepal.xml文件名对比,获得里面的内容,在使用SAX解析本地的文件,获得文件中的内容,赋值到LitePalAttr里.
2.在框架的使用中需要配置AndroidManifest.xml,在application中加入android:name=&org.litepal.LitePalApplication&&那我们不妨从LitePalApplication开始看
public class LitePalApplication extends Application {
* Global application context.
private static Context mC
* Construct of LitePalApplication. Initialize application context.
public LitePalApplication() {
mContext =
* Get the global application context.
* @return Application context.
* @throws GlobalException
public static Context getContext() {
if (mContext == null) {
throw new GlobalException(GlobalException.APPLICATION_CONTEXT_IS_NULL);
public void onLowMemory() {
super.onLowMemory();
mContext = getApplicationContext();
郭哥这里为了方便用户多次调用将配置到AndroidManifest.xml,并在LitePalApplication中给context赋值,这里需要注意一下,郭哥为了防止context为空,所以在onLowMemory给context赋值.大神不愧是大神,这么机智的保护措施.
今天就到这,欲知后事如何,请听下回解说!
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:197244次
积分:3572
积分:3572
排名:第7129名
原创:79篇
评论:436条
(2)(3)(3)(3)(2)(1)(1)(2)(4)(1)(1)(1)(4)(2)(1)(1)(3)(7)(3)(4)(8)(13)(3)(4)(6)(2)&&&&Android数据库框架:LitePal
Android数据库框架:LitePal
Android数据库框架:LitePal,该源码介绍了如何搭建LitePal框架和利用LitePal框架来进行对数据的增删改查等操作,较多的都是如何操作的例子。
若举报审核通过,可奖励20下载分
被举报人:
举报的资源分:
请选择类型
资源无法下载
资源无法使用
标题与实际内容不符
含有危害国家安全内容
含有反动色情等内容
含广告内容
版权问题,侵犯个人或公司的版权
*详细原因:
VIP下载&&免积分60元/年(1200次)
您可能还需要
移动开发下载排行Android(8)
转载请注明出处:
上一篇文章中我们学习了一些Android数据库相关的基础知识,和几个颇为有用的SQLite命令,都是直接在命令行操作的。但是我们都知道,数据库是要和程序结合在一起使用的,单独对一个数据库去进行増删改查操作并没有什么意义,因此今天我们就来学习一下如何在Android程序当中去操作SQLite数据库&。
操作数据库的第一步当然是创建表了,传统创建表的方法相信大多数人都知道,那么今天我除了会展示传统的建表方法之外,还会讲解LitePal这个框架的基本用法,并使用它来完成同样的建表操作,让大家体会到使用框架来操作数据库的魅力。
那么先来简单介绍一下吧,LitePal是一款开源的Android数据库框架,它采用了对象关系映射(ORM)的模式,并将我们平时开发时最常用到的一些数据库功能进行了封装,使得不用编写一行SQL语句就可以完成各种建表、増删改查的操作。并且LitePal很“轻”,jar包只有100k不到,而且近乎零配置,这一点和Hibernate这类的框架有很大区别。目前LitePal的源码已经托管到了GitHub上,地址是&&。
OK,简单介绍完了LitePal,我们还是先来看一下,在传统的Android开发中,需要怎么去创建表。
传统的建表方式
其实为了方便我们对数据库表进行管理,Android本身就提供了一个帮助类:SQLiteOpenHelper。这个类集创建和升级数据库于一身,并且自动管理了数据库版本,算是一个非常好用的工具。
那我们现在就来试试SQLiteOpenHelper的用法吧。首先你要知道SQLiteOpenHelper是一个抽象类,这意味着如果我们想要使用它的话,就需要创建一个自己的帮助类去继承它。SQLiteOpenHelper中有两个抽象方法,分别是onCreate()和onUpgrade(),我们必须在自己的帮助类里面重写这两个方法,然后分别在这两个方法中去实现创建、升级数据库的逻辑。本篇文章只需要把注意力放在创建数据库这里就行了,升级数据库我们会在下一篇文章中去讨论。
新建一个MySQLiteHelper类并让它继承SQLiteOpenHelper,这样一个最基本的数据库帮助类的代码如下所示:
其中,当数据库创建的时候会调用onCreate()方法,在这里去执行建表操作就可以了。比如说我们想新建一张news表,其中有title,content,publishdate,commentcount这几列,分别代表着新闻标题、新闻内容、发布时间和评论数,那么代码就可以这样写:
可以看到,我们把建表语句定义成了一个常量,然后在onCreate()方法中去执行了这条建表语句,news表也就创建成功了。这条建表语句虽然简单,但是里面还是包含了一些小的细节,我来解释一下。首先,根据数据库的范式要求,任何一张表都应该是有主键的,所以这里我们添加了一个自增长的id列,并把它设为主键。然后title列和content列都是字符串类型的,commentcount列是整型的,这都很好理解,但是publishdate列该怎么设计呢?由于SQLite中并不支持存储日期这种数据类型,因此我们需要将日期先转换成UTC时间(自号零点)的毫秒数,然后再存储到数据库中,因此publishdate列也应该是整型的。
现在,我们只需要获取到SQLiteDatabase的实例,数据库表就会自动创建了,如下所示:
感觉很简单很方便是吗?那你就太容易满足了,下面我们就来学习一下LitePal的基本用法,看一看使用这个框架是如何实现同样的功能的。
LitePal的基本用法
虽说LitePal宣称是近乎零配置,但也只是“近乎”而已,它还是需要进行一些简单配置才可以使用的,那么我们第一步就先快速学习一下LitePal的配置方法。
1. 引入Jar包或源码
首先我们需要将LitePal的jar包引入到项目当中,可以查看LitePal的最新版本,选择你需要的下载即可。下载好了jar包之后,把它复制到项目的libs目录中就算是引入成功了,如下图所示:
如果你不想用jar包的话,也可以把LitePal的源码下载下来,然后作为一个library库导入到Eclipse当中,再让我们的项目去引用这个library库就可以了。
2. 配置litepal.xml
接着在项目的assets目录下面新建一个litepal.xml文件,并将以下代码拷贝进去:
配置文件相当简单,&dbname&用于设定数据库的名字,&version&用于设定数据库的版本号,&list&用于设定所有的映射模型,我们稍后就会用到。
3. 配置LitePalApplication
由于操作数据库时需要用到Context,而我们显然不希望在每个接口中都去传一遍这个参数,那样操作数据库就显得太繁琐了。因此,LitePal使用了一个方法来简化掉Context这个参数,只需要在AndroidManifest.xml中配置一下LitePalApplication,所有的数据库操作就都不用再传Context了,如下所示:
当然,有些程序可能会有自己的Application,并在这里配置过了。比如说有一个MyApplication,如下所示:
没有关系,这时只需要修改一下MyApplication的继承结构,让它不要直接继承Application类,而是继承LitePalApplication类,就可以使用一切都能正常工作了,代码如下所示:
但是,有些程序可能会遇到一些更加极端的情况,比如说MyApplication需要继承另外一个AnotherApplication,并且这个AnotherApplication还是在jar包当中的,不能修改它的代码。这种情况应该算是比较少见了,但是如果你遇到了的话也不用急,仍然是有解释方案的。你可以把LitePal的源码下载下来,然后把src目录下的所有代码直接拷贝到你项目的src目录下面,接着打开LitePalApplication类,将它的继承结构改成继承自AnotherApplication,再让MyApplication继承自LitePalApplication,这样所有的Application就都可以在一起正常工作了。
仅仅三步,我们就将所有的配置工作全部完成了,并且这是一件一本万利的事情,自此以后,你就可以开心地体验LitePal提供的各种便利了,就让我们从建表开始吧。
前面在介绍的时候已经说了,LitePal采取的是对象关系映射(ORM)的模式,那么什么是对象关系映射呢?简单点说,我们使用的编程语言是面向对象语言,而我们使用的数据库则是关系型数据库,那么将面向对象的语言和面向关系的数据库之间建立一种映射关系,这就是对象关系映射了。
但是我们为什么要使用对象关系映射模式呢?这主要是因为大多数的程序员都很擅长面向对象编程,但其中只有少部分的人才比较精通关系型数据库。而且数据库的SQL语言晦涩难懂,就算你很精通它,恐怕也不喜欢经常在代码中去写它吧?而对象关系映射模式则很好地解决了这个问题,它允许我们使用面向对象的方式来操作数据库,从而可以从晦涩难懂的SQL语言中解脱出来。
那么接下来我们就看一看LitePal中是如何建表的吧。根据对象关系映射模式的理念,每一张表都应该对应一个模型(Model),也就是说,如果我们想要建一张news表,就应该有一个对应的News模型类。新建一个News类,如下所示:
然后,表中的每一列其实就是对应了模型类中的一个字段,比如news表中有id、title、content、publishdate、commentcount这几个列,那么在News类中就也应该有这几个字段,代码如下所示:
其中id这个字段可写可不写,因为即使不写这个字段,LitePal也会在表中自动生成一个id列,毕竟每张表都一定要有主键的嘛。
这里我要特别说明一下,LitePal的映射规则是非常轻量级的,不像一些其它的数据库框架,需要为每个模型类单独配置一个映射关系的XML,LitePal的所有映射都是自动完成的。根据LitePal的数据类型支持,可以进行对象关系映射的数据类型一共有8种,int、short、long、float、double、boolean、String和Date。只要是声明成这8种数据类型的字段都会被自动映射到数据库表中,并不需要进行任何额外的配置。
那么有的朋友可能会问了,既然是自动映射的话,如果News类中有一个字符串字段我并不想让它映射到数据库表中,这该怎么办呢?对此,LitePal同样采用了一种极为轻量的解决方案,只有声明成private修饰符的字段才会被映射到数据库表中,如果你有某一个字段不想映射的话,只需要将它改成public、protected或default修饰符就可以了。
现在模型类已经建好了,我们还差最后一步,就是将它配置到映射列表当中。编辑assets目录下的litepal.xml文件,在&list&标签中加入News模型类的声明:
注意这里一定要填入News类的完整类名。
OK,这样所有的工作就都已经完成了,现在只要你对数据库有任何的操作,news表就会被自动创建出来。比如说LitePal提供了一个便捷的方法来获取到SQLiteDatabase的实例,如下所示:
调用一下上述代码,news表就应该已经创建成功了。我们使用在上一篇文章中学到的SQLite命令来查看一下,打开demo.db数据库,输入.table命令,结果如下图所示:
可以看到,news表已经存在了。另外两张android_metadata和table_schema表是自动生成的,我们不用理。接下来我们还可以再查询一下news表的建表语句,如下图所示:
这就是LitePal根据News类中的字段自动帮我们生成的建表语句,由此也说明,建表操作已经成功完成了。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:2979次
排名:千里之外
转载:12篇Android数据库ORM框架用法、源码和性能比较分析 - 简书
<div class="fixed-btn note-fixed-download" data-toggle="popover" data-placement="left" data-html="true" data-trigger="hover" data-content=''>
写了57045字,被92人关注,获得了241个喜欢
Android数据库ORM框架用法、源码和性能比较分析
LitePal是一款开源的Android数据库框架,它采用了对象关系映射(ORM)的模式,LitePal很“轻”,jar包只有100k不到,使用起来也比较简单,源码地址为。
首先需要引入lib,可以通过gradle引入也可以将下载的litepal.jar包直接放入libs目录下。然后需要在assets目录下新建一个litepal.xml文件,文件名称不能随意更改,代码如下:
&?xml version="1.0" encoding="utf-8"?&
&dbname value="demo" &&/dbname&
&version value="1" &&/version&
&mapping class="com.example.databasetest.model.News"&&/mapping&
&/litepal&
&dbname&用于设定数据库的名字,&version&用于设定数据库的版本号,&list&用于设定所有的映射模型,&mapping&用于存放具体的Model类,必须是完整的类名。
然后还需要配置LitePalApplication,由于操作数据库时需要用到Context,而我们显然不希望在每个接口中都去传一遍这个参数,那样操作数据库就显得太繁琐了。因此,LitePal使用了一个方法来简化掉Context这个参数,只需要在AndroidManifest.xml中配置一下LitePalApplication,所有的数据库操作就都不用再传Context了。如果需要自定义application文件,只需继承LitePalApplication即可。
接下来需要创建Model类
public class News extends DataSupport {
private Date publishD
private int commentC
// 自动生成get、set方法
继承了DataSupport类之后,这些实体类就拥有了进行CRUD操作的能力
News news = new News();
news.setTitle("这是一条新闻标题");
news.setContent("这是一条新闻内容");
news.setPublishDate(new Date());
news.save();
List&News& newsList = DataSupport.select("title", "content")
.where("commentcount & ?", "0")
.order("publishdate desc").find(News.class);
LitePal还提供了直接用sql原句实现查询的api方法,扩展性也比较好。
AFinal是一个Android的orm、ioc快速开发框架,里面包含了四大功能:控件的id绑定和事件绑定功能;网络图片的显示功能(里面包含了强大的缓存框架);数据库sqlite的操作功能;http数据的读取功能(支持ajax方式读取),可从获取源码。数据库FinalDb是其中的一个组件,使用比较简单。
首先需要创建model类,承担对象与数据库表的映射功能。
@Table(name="table_user")
public class User {
// getter and setter不能省略
声明@Table注解,表示表名称为table_user;@id表示id作为该表自动增长的主键,接下来就可以直接使用了。
FinalDb db = FinalDb.create(this, "afinal_db");
User user = new User();
user.setEmail("");
user.setName("探索者");
user.setBirth(new Date());
db.save(user);
String name = "探索者";
List&User& userList = db.findAllByWhere(User.class, "name="' + name + "'" );//查询用户名为探索者的用户
if(userList.size() & 0){
User other = userList.get(0);
other.setEmail("");
db.update(other);
以上就是AFinal中关于数据库的简单用法,不需要额外的配置,api接口也比较简单易用。
greenDAO与上述两种ORM框架不同,其原理不是根据反射进行数据库的各项操作,而是一开始就人工生成业务需要的Model和DAO文件,业务中可以直接调用相应的DAO文件进行数据库操作,从而避免了因反射带来的性能损耗和效率低下。但是由于需要人工生成model和DAO文件,所以greenDAO的配置就略显复杂。
首先需要新建一个java工程来生成DAO类文件,该工程需要导入greendao-generator.jar和freemarker.jar文件到项目中,github官方源码中已经提供了该工程。
public class ExampleDaoGenerator
public static void main(String[] args) throws Exception
Schema schema = new Schema(3, "de.greenrobot.daoexample");
addNote(schema);
addCustomerOrder(schema);
new DaoGenerator().generateAll(schema, "../DaoExample/src-gen");
private static void addNote(Schema schema)
Entity note = schema.addEntity("Note");
note.addIdProperty();
note.addStringProperty("text").notNull();
note.addStringProperty("comment");
note.addDateProperty("date");
private static void addCustomerOrder(Schema schema)
Entity customer = schema.addEntity("Customer");
customer.addIdProperty();
customer.addStringProperty("name").notNull();
Entity order = schema.addEntity("Order");
order.setTableName("ORDERS"); // "ORDER" is a reserved keyword
order.addIdProperty();
Property orderDate = order.addDateProperty("date").getProperty();
Property customerId = order.addLongProperty("customerId").notNull().getProperty();
order.addToOne(customer, customerId);
ToMany customerToOrders = customer.addToMany(order, customerId);
customerToOrders.setName("orders");
customerToOrders.orderAsc(orderDate);
在main方法中,
Schema schema = new Schema(3, "de.greenrobot.daoexample");
该方法第一个参数用来更新数据库版本号,第二个参数为要生成的DAO类所在包路径。然后进行建表和设置要生成DAO文件的目标工程的项目路径。
addNote(schema);
addCustomerOrder(schema);
new DaoGenerator().generateAll(schema, "../DaoExample/src-gen");
其中src-gen这个目录名需要在运行前手动创建,否则会报错。运行后出现以下的提示说明DAO文件自动生成成功了,刷新一下DaoExample项目即可看到。
Written /Users/duanyangyang/Documents/Android/greenDAO/DaoExample/src/main/java/de/greenrobot/daoexample/NoteDao.java
Written /Users/duanyangyang/Documents/Android/greenDAO/DaoExample/src/main/java/de/greenrobot/daoexample/Note.java
Written /Users/duanyangyang/Documents/Android/greenDAO/DaoExample/src/main/java/de/greenrobot/daoexample/CustomerDao.java
Written /Users/duanyangyang/Documents/Android/greenDAO/DaoExample/src/main/java/de/greenrobot/daoexample/Customer.java
Written /Users/duanyangyang/Documents/Android/greenDAO/DaoExample/src/main/java/de/greenrobot/daoexample/OrderDao.java
Written /Users/duanyangyang/Documents/Android/greenDAO/DaoExample/src/main/java/de/greenrobot/daoexample/Order.java
Written /Users/duanyangyang/Documents/Android/greenDAO/DaoExample/src/main/java/de/greenrobot/daoexample/DaoMaster.java
Written /Users/duanyangyang/Documents/Android/greenDAO/DaoExample/src/main/java/de/greenrobot/daoexample/DaoSession.java
Processed 3 entities in 268ms
然后具体的使用就比较简单了
DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "notes-db", null);
db = helper.getWritableDatabase();
daoMaster = new DaoMaster(db);
daoSession = daoMaster.newSession();
noteDao = daoSession.getNoteDao();
String textColumn = NoteDao.Properties.Text.columnN
String orderBy = textColumn + " COLLATE LOCALIZED ASC";
cursor = db.query(noteDao.getTablename(), noteDao.getAllColumns(), null, null, null, null, orderBy);
String[] from = { textColumn, ment.columnName };
int[] to = { android.R.id.text1, android.R.id.text2 };
SimpleCursorAdapter adapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_2, cursor, from,
setListAdapter(adapter);
三种数据库框架性能比较
为了比较三种数据库框架的性能,首先选择同一款手机华为Mate7,然后从以下几个方面分析比较:
循环插入10000次,每次插入一条数据,三种框架用时为:
批量插入10000条数据,三种框架用时为:
循环更新10000次,每次更新一条数据,三种框架用时为:
批量更新10000条数据,三种框架用时为:
循环查询10000条数据,每次查询一条数据,三种框架用时为:
批量查询10000条数据,三种框架用时为:
根据以上数据可以得出以下几个结论:
不管是批量插入、更新、查询,greenDAO都是用时最短,执行速度最快的;
大部分数据库操作的情况下,LitePal都是用时最长的,只有在循环查询时表现比greenDAO好
AFinal对于很多批量操作没有提供相应的api方法
不管对于哪个框架,批量操作比循环操作用时都要短很多
下面是以greenDAO为例的测试源码
private void testInsertQueryTime(final int count){
noteList1 = new ArrayList&Note&();
for (int i = 0; i & i++){
Note note = new Note(null, "title", "comment", new Date());
noteList1.add(note);
noteList2 = new ArrayList&Note&();
for (int i = 0; i & i++){
Note note = new Note(null, "title", "comment", new Date());
noteList2.add(note);
new Thread(){
public void run() {
super.run();
long time1 = System.currentTimeMillis();
for(Note note : noteList1){
noteDao.insert(note);
// 循环插入10000次,每次插入一条数据
long time = System.currentTimeMillis() - time1;
Log.d("NoteActivity", "greedDAO one by one insert " + noteList1.size() + " data, use time " + time + "ms");
// 批量插入10000条数据
long time2 = System.currentTimeMillis();
noteDao.insertInTx((Note[])noteList2.toArray(new Note[noteList2.size()]));
long time3 = System.currentTimeMillis() - time2;
Log.d("NoteActivity", "greedDAO batch insert " + noteList2.size() + " data, use time " + time3 + "ms");
// 循环查询10000条数据,每次查询一条数据
long time4 = System.currentTimeMillis();
for(int i = 0; i & i++){
noteDao.queryBuilder().limit(1).list();
long time5 = System.currentTimeMillis() - time4;
Log.d("NoteActivity", "greedDAO one by one query " + count + " data, use time " + time5 + "ms");
// 批量查询10000条数据
long time6 = System.currentTimeMillis();
List&Note& list2 = noteDao.queryBuilder().limit(10000).offset(-1).list();
long time7 = System.currentTimeMillis() - time6;
Log.d("NoteActivity", "greedDAO batch query " + list2.size() + " data, use time " + time7 + "ms");
// 循环更新10000次,每次更新一条数据
long time8 = System.currentTimeMillis();
for (Note note : noteList1){
note.setText("update_title");
note.setComment("update_comment");
noteDao.update(note);
// 批量更新10000条数据
long time9 = System.currentTimeMillis() - time8;
Log.d("NoteActivity", "greedDAO one by one update " + count + " data, use time " + time9 + "ms");
for (Note note : noteList2){
note.setText("update_title");
note.setComment("update_comment");
long time10 = System.currentTimeMillis();
noteDao.updateInTx(noteList2);
long time11 = System.currentTimeMillis() - time10;
Log.d("NoteActivity", "greedDAO batch update " + count + " data, use time " + time11 + "ms");
}.start();
三种数据库框架的原理和源码分析
LitePal通过LitePal.xml文件获取数据库的名称、版本号以及表,然后创建数据库和表,要执行增删改查操作时,就会根据数据model进行参数拼装,最后调用系统原生的数据库操作。解析litepal.xml文件方法源码如下:
private InputStream getConfigInputStream() throws IOException {
AssetManager assetManager = LitePalApplication.getContext().getAssets();
String[] fileNames = assetManager.list("");
if (fileNames != null && fileNames.length & 0) {
for (String fileName : fileNames) {
if (Const.LitePal.CONFIGURATION_FILE_NAME.equalsIgnoreCase(fileName)) {
return assetManager.open(fileName, AssetManager.ACCESS_BUFFER);
throw new ParseConfigurationFileException(
ParseConfigurationFileException.CAN_NOT_FIND_LITEPAL_FILE);
void usePullParse() {
LitePalAttr litePalAttr = LitePalAttr.getInstance();
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
XmlPullParser xmlPullParser = factory.newPullParser();
xmlPullParser.setInput(getConfigInputStream(), "UTF-8");
int eventType = xmlPullParser.getEventType();
while (eventType != XmlPullParser.END_DOCUMENT) {
String nodeName = xmlPullParser.getName();
switch (eventType) {
case XmlPullParser.START_TAG: {
if (NODE_DB_NAME.equals(nodeName)) {
String dbName = xmlPullParser.getAttributeValue("", ATTR_VALUE);
litePalAttr.setDbName(dbName);
} else if (NODE_VERSION.equals(nodeName)) {
String version = xmlPullParser.getAttributeValue("", ATTR_VALUE);
litePalAttr.setVersion(Integer.parseInt(version));
} else if (NODE_MAPPING.equals(nodeName)) {
String className = xmlPullParser.getAttributeValue("", ATTR_CLASS);
litePalAttr.addClassName(className);
} else if (NODE_CASES.equals(nodeName)) {
String cases = xmlPullParser.getAttributeValue("", ATTR_VALUE);
litePalAttr.setCases(cases);
eventType = xmlPullParser.next();
} catch (XmlPullParserException e) {
throw new ParseConfigurationFileException(
ParseConfigurationFileException.FILE_FORMAT_IS_NOT_CORRECT);
} catch (IOException e) {
throw new ParseConfigurationFileException(ParseConfigurationFileException.IO_EXCEPTION);
LitePal框架会根据model自动创建好相应的数据表,以及表数据类型和非空约束等。
protected String generateCreateTableSQL(String tableName, List&ColumnModel& columnModels,
boolean autoIncrementId) {
StringBuilder createTableSQL = new StringBuilder("create table ");
createTableSQL.append(tableName).append(" (");
if (autoIncrementId) {
createTableSQL.append("id integer primary key autoincrement,");
if (columnModels.size() == 0) {
createTableSQL.deleteCharAt(createTableSQL.length() - 1);
boolean needSeparator =
for (ColumnModel columnModel : columnModels) {
if (columnModel.isIdColumn()) {
if (needSeparator) {
createTableSQL.append(", ");
needSeparator =
createTableSQL.append(columnModel.getColumnName()).append(" ").append(columnModel.getColumnType());
if (!columnModel.isNullable()) {
createTableSQL.append(" not null");
if (columnModel.isUnique()) {
createTableSQL.append(" unique");
String defaultValue = columnModel.getDefaultValue();
if (!TextUtils.isEmpty(defaultValue)) {
createTableSQL.append(" default ").append(defaultValue);
createTableSQL.append(")");
LogUtil.d(TAG, "create table sql is && " + createTableSQL);
return createTableSQL.toString();
要执行增删改查操作的数据model都会继承DataSupport,以查询方法findAll()为例,DataSupport会先调用QueryHandler.onFindAll()方法,然后最后会执行到QueryHandler.query方法,该方法传入的参数有类名、列名称、查询条件、排序等等,经过处理后调用SDLiteDatabase.query方法,最后将查询得到的数据转换成List并返回,源码如下:
protected &T& List&T& query(Class&T& modelClass, String[] columns, String selection,
String[] selectionArgs, String groupBy, String having, String orderBy, String limit,
List&AssociationsInfo& foreignKeyAssociations) {
List&T& dataList = new ArrayList&T&();
Cursor cursor =
List&Field& supportedFields = getSupportedFields(modelClass.getName());
String tableName = getTableName(modelClass);
String[] customizedColumns = getCustomizedColumns(columns, foreignKeyAssociations);
cursor = mDatabase.query(tableName, customizedColumns, selection, selectionArgs,
groupBy, having, orderBy, limit);
if (cursor.moveToFirst()) {
SparseArray&QueryInfoCache& queryInfoCacheSparseArray = new SparseArray&QueryInfoCache&();
T modelInstance = (T) createInstanceFromClass(modelClass);
giveBaseObjIdValue((DataSupport) modelInstance,
cursor.getLong(cursor.getColumnIndexOrThrow("id")));
setValueToModel(modelInstance, supportedFields, foreignKeyAssociations, cursor, queryInfoCacheSparseArray);
if (foreignKeyAssociations != null) {
setAssociatedModel((DataSupport) modelInstance);
dataList.add(modelInstance);
} while (cursor.moveToNext());
queryInfoCacheSparseArray.clear();
return dataL
} catch (Exception e) {
e.printStackTrace();
throw new DataSupportException(e.getMessage());
} finally {
if (cursor != null) {
cursor.close();
可以看到LitePal不管是创建数据库、表还是执行增删改查都是根据Model的类名和属性名,每次都需要进行反射拼装然后调用Android原生的数据库操作或者直接执行sql语句。
AFinal本质上也是利用java的反射原理实现对象与数据表的映射的,实现上和LitePal有很多不同。AFinal并未提前创建数据库和表,而是在第一次执行增删改查方法时,先判断数据库和表是否存在,如果不存在的话就根据model执行sql语句进行创建,创建完成后再拼装具体的操作sql语句,完成相应的增删改查操作。相关源码如下:
public void save(Object entity) {
checkTableExist(entity.getClass());
exeSqlInfo(SqlBuilder.buildInsertSql(entity));
private void checkTableExist(Class&?& clazz) {
if (!tableIsExist(TableInfo.get(clazz))) {
String sql = SqlBuilder.getCreatTableSQL(clazz);
debugSql(sql);
db.execSQL(sql);
public static String getCreatTableSQL(Class&?& clazz) {
TableInfo table = TableInfo.get(clazz);
Id id = table.getId();
StringBuffer strSQL = new StringBuffer();
strSQL.append("CREATE TABLE IF NOT EXISTS ");
strSQL.append(table.getTableName());
strSQL.append(" ( ");
Class&?& primaryClazz = id.getDataType();
if (primaryClazz == int.class || primaryClazz == Integer.class
|| primaryClazz == long.class || primaryClazz == Long.class) {
strSQL.append(id.getColumn()).append(" INTEGER PRIMARY KEY AUTOINCREMENT,");
strSQL.append(id.getColumn()).append(" TEXT PRIMARY KEY,");
Collection&Property& propertys = table.propertyMap.values();
for (Property property : propertys) {
strSQL.append(property.getColumn());
Class&?& dataType = property.getDataType();
if (dataType == int.class || dataType == Integer.class
|| dataType == long.class || dataType == Long.class) {
strSQL.append(" INTEGER");
} else if (dataType == float.class || dataType == Float.class
|| dataType == double.class || dataType == Double.class) {
strSQL.append(" REAL");
} else if (dataType == boolean.class || dataType == Boolean.class) {
strSQL.append(" NUMERIC");
strSQL.append(",");
Collection&ManyToOne& manyToOnes = table.manyToOneMap.values();
for (ManyToOne manyToOne : manyToOnes) {
strSQL.append(manyToOne.getColumn())
.append(" INTEGER")
.append(",");
strSQL.deleteCharAt(strSQL.length() - 1);
strSQL.append(" )");
return strSQL.toString();
greenDAO与上述两种ORM框架不同,其原理不是根据反射进行数据库的各项操作,而是一开始就人工生成业务需要的Model和DAO文件,业务中可以直接调用相应的DAO文件进行数据库的增删改查操作,从而避免了因反射带来的性能损耗和效率低下。以查询为例,其代码如下:
DevOpenHelper helper = new DaoMaster.DevOpenHelper(this, "notes-db", null);
db = helper.getWritableDatabase();
daoMaster = new DaoMaster(db);
daoSession = daoMaster.newSession();
noteDao = daoSession.getNoteDao();
cursor = db.query(noteDao.getTablename(), noteDao.getAllColumns(), null, null, null, null, orderBy);
首先先创建数据库,然后在SQLiteOpenHelper.onCreate方法中根据已生成的model创建所有的表,而db.query其实就是Android原生的查询操作,只不过参数是经过DAO文件处理过的,无需手动匹配。其他数据库操作与查询雷同。
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
被以下专题收入,发现更多相似内容:
如果你是程序员,或者有一颗喜欢写程序的心,喜欢分享技术干货、项目经验、程序员日常囧事等等,欢迎投稿《程序员》专题。
专题主编:小...
· 263605人关注
玩转简书的第一步,从这个专题开始。
想上首页热门榜么?好内容想被更多人看到么?来投稿吧!如果被拒也不要灰心哦~入选文章会进一个队...
· 147755人关注
分享Android开发的知识,教程,解析,前沿信息,都可以,欢迎大家投稿~
内容可搞笑,可逗比,另外欢迎申请管理员
· 24957人关注
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
选择支付方式:

我要回帖

更多关于 铁路12306app下载 的文章

 

随机推荐