greendao关闭数据库 如果别人手机第一次安装数据库怎么升级

GreenDao 数据库简单使用及数据库升级更新
前面的基础使用先占坑,遇到更新的问题,这里先记录数据库更新的问题,有空再来更新前面的基础使用部分在进行数据库的更新时,大致步骤如下:编写更新后的数据库结构,并运行生成器,生成更新的代码 找到 DaoMaster (自动生成的文件)修改 SCHEMA_VERSION 的值为需要更新的版本号找到 onUpgrade()方法,注释掉其中的 dropAllTables() 和 onCreate() 方法,然后编写更新的 SQL 代码完成以上步骤,重新运行即可更新数据库下面通过例子来描述下具体操作步骤前提是现在已经存在数据表 MESSAGE,需求是新增字段 CONTENT,下面是具体执行步骤:更新数据库生成器在原有的生成器中新增字段,如下,表
Message 中的 content 字段是新增的字段
private static void addMsg(Schema schema) {
Entity msg = schema.addEntity("Message");
msg.addIdProperty().primaryKey().autoincrement();
msg.addIntProperty("msgId");
msg.addStringProperty("content");//新增字段
msg.addBooleanProperty("isRead");
msg.addDateProperty("createdAt");
}然后运行生成器,生成最新的代码,这个就不多说,跟建表是一样的操作修改版本号找到自动生成的 DaoMaster 文件,首先修改 SCHEMA_VERSION 的值,从名字上就能看到,这个是版本号,将它修改成更新后的版本号:public static final int SCHEMA_VERSION = 2;编写更新内容找到内部类 DevOpenHelper 类中的 onUpgrade() 方法:
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");
dropAllTables(db, true);
onCreate(db);
}修改为如下:
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");
// dropAllTables(db, true);
// onCreate(db);
if (oldVersion!=newVersion) {
db.execSQL("ALTER TABLE MESSAGE ADD /"CONTENT/" TEXT");
}可以看到,首先将 dropAllTables() 和 onCreate() 方法注释,然后执行一个增加表字段的 SQL 语句,SQL 语句的意思很简单,就是在 表 MESSAGE 中增加了字段 CONTENT接着再运行,就能顺利的更新数据库了
最新教程周点击榜
微信扫一扫GreenDao(2)
---- 数据库升级 onUpgrade - 简书
下载简书移动应用
写了10003字,被35人关注,获得了34个喜欢
GreenDao(2)
---- 数据库升级 onUpgrade
1APP开发期间的数据库改动(APP未上线)
直接上DaoMaster的代码
/** * WARNING: Drops all table on Upgrade! Use only during development. */
public static class DevOpenHelper extends OpenHelper {
public DevOpenHelper(Context context, String name, CursorFactory factory) {
super(context, name, factory);
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
Log.i("greenDAO", "Upgrading schema from version " + oldVersion + " to " + newVersion + " by dropping all tables");
dropAllTables(db, true);
onCreate(db);
注意看第一行注释:WARNING: Drops all table on Upgrade! Use only during development.
数据库升级的话,会删除所有表,然后重新创建。这种方式在开发期间,APP还没有上线之前是可以的。
当APP上线后,我们不能使用这种方式,因为这样会导致已经存在的数据会被删除。
2APP上线后,数据库升级
需要我们写一个类来实现OpenHelper
我们自己实现了onUpgrade方法来自定义升级过程。
2.当然升级过程中也要修改DaoMaster.SCHEMA_VERSION
3.当DaoMaster.SCHEMA_VERSION 跟你当前数据库的版本比较后,
会根据你当前数据库的版本,然后进行升级。
4.关键代码onUpgrade方法,会比较新数据库和旧数据库的版本,然后执行相应的sql升级:
public void onUpgrade(SQLiteDatabase sqLiteDatabase, int oldVersion, int newVersion) {
LogUtil.w(SQLiteOpenHelper.class.getSimpleName(), "Upgrade from" + oldVersion + "to" + newVersion);
SortedMap&Integer, Migration& migrations = ALL_MIGRATIONS.subMap(oldVersion, newVersion);
executeMigrations(sqLiteDatabase, migrations.keySet());
private void executeMigrations(final SQLiteDatabase paramSQLiteDatabase, final Set&Integer&
migrationVersions) {
for (final Integer version : migrationVersions) {
ALL_MIGRATIONS.get(version).migrate(paramSQLiteDatabase);
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
打开微信“扫一扫”,打开网页后点击屏幕右上角分享按钮
如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
选择支付方式:greenDao android开源框架数据库更新表的问题
greenDao android开源框架数据库更新表的问题
[摘要:比来应用greenDao当android运用进级数据库新删表或点窜表,发明数据被浑空的题目 查找材料也出有找到办理计划,末了检察代码发明须要本身点窜SQLiteOpenHelper 1.找到greenDao天生的DaoMa]
最近使用greenDao当android应用升级数据库新增表或者修改表,发现数据被清空的问题
查找资料也没有找到解决方案,最后查看代码发现需要自己修改SQLiteOpenHelper
1.找到greenDao生成的DaoMaster.java文件,里面有SQLiteOpenHelper实现
2.修改DevOpenHelper类里的& &public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) 方法
通过oldVersion&newVersion 来判断需要创建表或alter表
(原本以为greenDao生成的代码会自动来完成这一步)
感谢关注 Ithao123精品文库频道,是专门为互联网人打造的学习交流平台,全面满足互联网人工作与学习需求,更多互联网资讯尽在 IThao123!
Laravel是一套简洁、优雅的PHP Web开发框架(PHP Web Framework)。它可以让你从面条一样杂乱的代码中解脱出来;它可以帮你构建一个完美的网络APP,而且每行代码都可以简洁、富于表达力。
Hadoop是一个由Apache基金会所开发的分布式系统基础架构。
用户可以在不了解分布式底层细节的情况下,开发分布式程序。充分利用集群的威力进行高速运算和存储。
Hadoop实现了一个分布式文件系统(Hadoop Distributed File System),简称HDFS。HDFS有高容错性的特点,并且设计用来部署在低廉的(low-cost)硬件上;而且它提供高吞吐量(high throughput)来访问应用程序的数据,适合那些有着超大数据集(large data set)的应用程序。HDFS放宽了(relax)POSIX的要求,可以以流的形式访问(streaming access)文件系统中的数据。
Hadoop的框架最核心的设计就是:HDFS和MapReduce。HDFS为海量的数据提供了存储,则MapReduce为海量的数据提供了计算。
产品设计是互联网产品经理的核心能力,一个好的产品经理一定在产品设计方面有扎实的功底,本专题将从互联网产品设计的几个方面谈谈产品设计
随着国内互联网的发展,产品经理岗位需求大幅增加,在国内,从事产品工作的大部分岗位为产品经理,其实现实中,很多从事产品工作的岗位是不能称为产品经理,主要原因是对产品经理的职责不明确,那产品经理的职责有哪些,本专题将详细介绍产品经理的主要职责
IThao123周刊Android 关于greenDao的使用教程
关于greenDao的使用
第一篇How &to get started ?&
原文地址:/documentation/how-to-get-started/
该教程会带你浏览一个简单的greenDao示例工程。地址:/greenrobot/greenDAO,该工程包含两个子工程:
DaoExample和DaoExampleGenerator。你可以clone到本地,运行或者直接在github上直接浏览。
如果你从git仓储中检出了DaoExample,可以直接像Android应用一样运行它。正如你所看到的,它就是一个简单的笔记本。可以添加新的note,
或者点击已存在的note进行删除。
预生成代码和创建表
在src-gen目录下,你可以找到一些已经生成的文件
1)Note.java &一个包含一个Note所有数据的java类。
2)NoteDao.java 一个DAO类,是操作Note 对象的接口。
你可以通过DaoExampleGenerator工程再次生成Note和NoteDao。
使用DaoMaster类可以获得一个方便的SQLiteOpenHelper:
new DaoMaster.DevOpenHelper(this, "notes-db", null)
你不必编写“CREATE TABLE” SQL语句,greenDao会为你完成。
插入和删除Note对象
创建了Note表后,就可以存储一些note到数据库里了。这是在NoteActivity类里完成的。在onCreate方法里,我们准备了一个DAO对象:
DaoMaster(db);
daoSession
= daoMaster.newSession();
= daoSession.getNoteDao();
添加一个新的note到数据库中:
note = new
Note(null,
noteText, comment, new
noteDao.insert(note);
Log.d("DaoExample", "Inserted
new note, ID: "
+ note.getId());
该示例只是创建并插入了一个java对象。但insert方法返回的时候,数据库的ID已经分发到了刚插入的Note对象上了。在log中可以看到。
删除一条note:非常简单明,在onListItemClick方法中可以看到
noteDao.deleteByKey(id);
你也可以看一下其它的DAO方法:loadAll、update。
数据模型化和代码的生成
为了扩展note或者创建新的实体,你可以看一下DaoExampleGenerator工程。它包含了一个单例的类,该类中包含了数据模型的定义代码。
schema = new
Schema(1, "de.greenrobot.daoexample");
note= schema.addEntity("Note");
note.addIdProperty();
note.addStringProperty("text").notNull();
note.addStringProperty("comment");
note.addDateProperty("date");
DaoGenerator().generateAll("../DaoExample/src-gen",
正如你所看到的,你可以创建一个Schema对象,通过它你可以添加实体,一个实体连接了一张数据库表。
一个实体包含一些属性,它们可以被映射到数据库的columns。
一旦schema定义完成,你可以触发代码生成器,Note.java和NoteDao.java文件就是这样被创建的。
对greenDao有了初步的了解,你可以自己动手试试了。当然,请查看下文档/documentation/,
如果没有找到你想要的,可以使用support options
第二篇 介绍
GreenDao是一个用于Android开发的对象/关系映射(ORM)工具。它向SQLite数据库提供了一个对象导向的接口。像GreenDao这样的ORM工具不仅为你省去了很多的重复工作,而且提供了更简便的操作接口。
代码生成的工程结构图
为了在你的Android项目中使用GreenDao,你需要创建一个二级工程:“generator project”,它的任务就是为你的domain生成具体的代码。这个生成器工程就是一个普通的java工程。确保greenDao 的greenDao-generator.jar和 freemarker.jar 在classpath中。创建一个可执行的java类,构建你的实体模型并触发代码生成器,更多细节,可以参看&modelling文档。
一旦生成了指定的代码,就可以在你的android工程中使用greenDao了。别忘记在你的android工程中引入greenDao的核心jar包:greenDao.jar。以下是GreenDao的一些必要接口。
DaoMaster:
daomaster以一定的模式持有数据库对象(SQLiteDatabase)并管理一些DAO类(而不是对象)。
有一个静态的方法创建和drop数据库表。它的内部类OpenHelper和DevOpenHelper是SQLiteOpenHelper的实现类,用于创建SQLite数据库的模式。
DaoSession:
管理指定模式下所有可用的DAO对象,你可以通过某个get方法获取到。DaoSession提供一些通用的持久化方法,比如对实体进行插入,加载,更新,刷新和删除。最后DaoSession对象会跟踪identity scope,更多细节,可以参看&session文档。
DAOs(Data access objects):
数据访问对象,用于实体的持久化和查询。对于每一个实体,greenDao会生成一个DAO,相对于DaoSession它拥有更多持久化的方法,比如:加载全部,插入(insertInTx,语境不明了,暂且简单的翻译成插入)。
可持久化的对象。通常,实体可以被生成,不用手动去写。在数据库的行中,使用的都是标准的java对象的属性(比如POJO或者JavaBean)。
user.addIdProperty();
user.addStringProperty("name");
user.addStringProperty("password");
user.addIntProperty("yearOfBirth");
在示例中有一个Note实体,通过它的DAO,我们可以对指定的实体进行持久化的操作。
第三篇 实体的模型化
使用greenDao的第一步:创建一个代表持久化数据的实体模型。greenDao会依赖该模型为Dao生成java代码。
该模型本身是用java代码定义的,很简单:在DaoExampleGenerator工程的基础上创建一个java对象。具体你可以参看:
/documentation/how-to-get-started/
下面的插图描绘了元模型,展示了一些用于描述domain具体模型的类。
实体数据schema是你定义的第一个对象,通过schema的版本和缺省的java包调用构造器。
schema = new
Schema(1, "de.greenrobot.daoexample");
这个缺省的java包会在greenDao生成实体、DAOs、和JUnit测试的时候使用。如果那些缺省值是正确的,那么就完成了第一步。
如果你希望将DAO和测试类创建到不同的包中,可以重新定义schema的定义代码:
schema.setDefaultJavaPackageTest("de.greenrobot.daoexample.test");
schema.setDefaultJavaPackageDao("de.greenrobot.daoexample.dao");
对于实体,该schema也有两个缺省的标记,它们是可以被复写的。这些标记可以区分实体是否是激活状态,是否应该使用sections。这些特性在文档里并没有,你可以看一下发布源码中的测试工程。
schema2.enableKeepSectionsByDefault();
schema2.enableActiveEntitiesByDefault();
一旦你拥有了一个schema对象,你就可以使用它去添加实体了。
user = schema.addEntity("User");
一个实体有不同的可变更设置,更重要的是,你可以添加一些属性到实体。
user.addIdProperty();
user.addStringProperty("name");
user.addStringProperty("password");
user.addIntProperty("yearOfBirth");
除了实体,还可以添加,一对一和一对多的关系。
属性和主键
以上的实体部分展示了如何给一个实体添加属性,实体的addXXXProperty方法返回一个PropertyBuilder对象,可以用于配制属性,
例如,使用columnName去复写缺省的或者你提供的column name。在ProperyBuilder对象上调用getProperty方法去访问属性对象,
对于指数(indices )和关系的创建是有必要的。
创建主键的约束
现在实体必须拥有一个long或者Long类型的属性作为它们的主键,这是Android和SQLite推荐的实践方式。因为,在将来,greenDao要准备处理很多主键的脚本,但并不是每件事都能完全实现。为了解决这个问题,你可以使用一个long类型的键并且使用一个唯一的下标去处理这个预期的key属性。
greenDao会尝试以合理的缺省值进行工作,所以开发者不用单个的配置它们。比如,表和其列名是从实体和属性名中获取到的,而不是java中的驼峰。缺省的数据库名是大写的,单词间用下划线分隔开。比如:属性“creationDate”在数据库列中的映射为“CREATION_DATE”,
一对多和多对多的关系在/documentation/relations/中有注释。
继承、接口、序列化
实体可以从其他非实体类继承,其父类可以通过setSuperclass(String)方法指定,注意:它可能会有其它的实体作为父类(但这里没有多态查询)。
myEntity.setSuperclass("MyCommonBehavior");
通常,使用接口作为实体属性和行为的通用基类是比较好的。比如:一个实体A和B共享了一套属性,这些属性可以定义在C中。下面是一个序列化B的列子:
entityA.implementsInterface("C");
entityB.implementsInterface("C");
entityB.implementsSerializable();
触发生成器
一旦你的实体schema放置好了,你可以触发代码生成器进行处理。在generator工程中,你可以实例化DaGenerator并调用generateAll中的一个方法:
DaoGenerator
daoGenerator = new
DaoGenerator();
daoGenerator.generateAll(schema, "../MyProject/src-gen");
你所需要的就是schema对象和目标文件夹,通常该文件夹就是你android工程的资源文件夹。如果你想把这些测试类放到其他目录下,可以把目的文件夹作为第三个参数传入。
保持独立性(Keep sections 保持自定义的代码不会被覆盖)
实体类在每一次生成器运行的时候都会被覆盖。greenDao允许添加自定义的代码到实体,通过“keep” ,可以满足它们。在schema中使用enableKeepSectinsByDefault(),或者setHasKeepSections(true)在选中的实体中。一旦使用,3个独立的部分会在实体中生成:
现在,你可以在 KEEP [...] and KEEP [...] END.中写入你的代码。注意,不要修改KEEP注释。在该范围的代码会在代码重新生成的时候不被覆盖。对于备份或者提交代码时出现的意外错误,这是一个不错的选择解决方案。
第四篇 非技术类的常见问题
通常的疑问
为什么greenDao使用的是code generation,而不是注解?
对于greenDao,代码生成是非常合理的。在Android平台上,基于注解的解决方式是有缺陷的:它们不得不依赖于元数据的解析和反射。特别是反射,会显著降低ORM工具的性能。另一方面,greenDao会为Android生成优化过的代码。这些生成的代码完全避免了反射。这也是greenDao如此快的主要原因。另一个优势是大小。
greenDao的核心lib是非常小的(在100K以下,包括单元测试)。这是因为对于一些ORM的内部逻辑都在generator中,而不是在核心库中。
greenDao包含了:DaoCore,DaoGenerator和DaoTest。DaoCore是需要你加入到android项目中的,在Apache License 2版本以下是许可的。
DaoGenerator是java程序,负责实体的生成,DAO和其它的文件。DaoTest是单元测试用例额,确保了greenDao本身和其稳定性。
DaoGenerator 和DaoTest 在GPL V3以下是可用的。这些许可条款可以满足大部分的开发者使用。
第五篇 查询
查询会返回符合某些特定标准的实体。你可以使用原始的SQL定制查询语句,或者更好的方式:使用GreenDao的QueryBuilder API。该查询也支持lazy-loading的结果集。这样在操作大量结果集的时候可以节省内存和性能。
QueryBuilder
QueryBuilder可以帮助你构建自定义的查询语句,而不使用SQL的情况。并不是每个人都喜欢书写SQL语句,当然很容易就会出一些错,这些错误只有在运行的时候才会被发现。而QueryBuilder很容易使用,节省了你书写SQL语句的时间。当然,由于语法的检验是在编译时才执行,所以在查询语句中发现bug是很困难的。
QueryBuilder的编译时间会检验属性的引用,这样能够在greenDao后面,通过代码生成的方法发现bug。
比如:查找所有以“Joe”为first name 的用户,并以last name排序:
joes = userDao.queryBuilder()
.where(Properties.FirstName.eq("Joe"))
.orderAsc(Properties.LastName)
嵌套情况:
获取用户名字为“Joe”并且在1970年9月之后出生的用户
这里要说明下:user 的birthday对于year,month,和day是一个分离的属性。我们可以以一种更正常的方式表达这种条件:
First name is “Joe” AND (year of birth is greater than 1970 OR (year of birth is 1970 AND month of birth is equal to or greater than 10 (October).
QueryBuilder
qb = userDao.queryBuilder();
qb.where(Properties.FirstName.eq("Joe"),
qb.or(Properties.YearOfBirth.gt(1970),
qb.and(Properties.YearOfBirth.eq(1970),
Properties.MonthOfBirth.ge(10))));
youngJoes = qb.list();
Query 和 LazyList
Query类代表一个可以多次执行的查询。当你使用QueryBuilder之一的方法去获取结果的时候,QueryBuilder内部使用了Query 类。
如果你想运行更多相同的查询,你应该调用build()在QueryBuilder上,去创建Query,而不是执行它。
greenDao支持唯一的结果和结果列表。如果你想得到一个唯一的结果,可以调用Query或者QueryBuilder的unique()方法,这样在没有匹配条件的时候会返回一个唯一的结果,而不是null。如果你希望禁止用例中返回null,可以调用uniqueOrThrow(),该方法会保证返回一个非null的实体。否则就会抛出一个DaoException。
如果你期望一次性返回多个实体,可以使用以下方法:
list():所有的实体被加载到内存中。该结果通常是一个没有magic involved的ArrayList。使用起来最简单。
listLazy():实体按照需求加载进入内存。一旦列表中的一个元素被第一次访问,它将被加载同时缓存以便以后使用。必须close。
ListLasyUncached(): 一个“虚拟”的实体列表:任何对列表元素的访问都会导致从数据库中加载,必须close。
listIterator(): 遍历通过需要的时候加载(lazily)获得的结果,数据没有缓存,必须close。
listLazy, listLazyUncached 和 listIterator类使用了greenDao的LazyList类。为了根据需求加载数据,它持有了一个数据库cursor的引用。
这是做是为了确保关闭 lazy list和iterators(通常在try/finally 代码块中)。
一旦有的元素被访问或者遍历过,来自lsitLazy()的cache lazy list和来自listIterator()方法的lazy iterator将会自动关闭cursor。
然而,如果list的处理过早的完成了,你应该调用 close()手动关闭。
多次执行查询
一旦你使用QueryBuilder构建了一个query,该query对象以后可以被重复使用。这种方式比总是重复创建query对象要高效。
如果query的参数没有变更,你只需要再次调用list/unique方法即可。如果有参数变更,你就需要调用setParameter方法处理每一个变更的参数。
现在,个别参数由基于零的参数索引寻址。该下标基于你传递到querybuilder的参数。
使用query对象获取出生在1970年 并且 first name 为 joe 的用户:
query = userDao.queryBuilder().where(
Properties.FirstName.eq("Joe"),
Properties.YearOfBirth.eq(1970))
joesOf1970 = query.list();
使用query对象,可以查询
query.setParameter(0, "Maria");
query.setParameter(1,
mariasOf1977 = query.list();
在多个线程中执行查询
如果你在多线程中使用了查询,你必须调用query的 forCurrentThread()为当前的线程获得一个query实例。从greenDAO 1.3开始,
query的实例化被绑定到了那些创建query的线程身上。这样做保证了query对象设置参数时的安全性,避免其他线程的干扰。如果其他线程
试着在query对象上设置参数或者执行查询绑定到了其它线程,将会抛出异常。这样一来,你就不需要一个同步语句了。
事实上你应该避免使用lock,因为如果在并发的事务中使用了同一个query对象,可能会导致死锁。
为了完全避免那些潜在的死锁问题,greenDAO 1.3 引入了forCurrentThread方法,它会返回一个query对象的thread—local实例,该实例
在当前的线程中使用是安全的。当每一次调用 forCueerntThread()的时候,该参数会在builder构建query的时候,设置到初始化参数上。
原始的查询
这里有两种方式执行原始的SQL去获取实体。较好的一种方式是使用QueryBuilder 和 WhereCondition.StringCondition。
使用这个方法,你可以为 query builder 的 WHERE 子句传递任何SQL片段。
下面是一个笨拙的例子展示如果使用这种方式进行一个替代联合查询的子查询。
query = userDao.queryBuilder().where(
StringCondition("_ID
USER_ID FROM USER_MESSAGE WHERE READ_FLAG = 0)").build();
该示例中query Builder没有提供你需要的特性,你可以回到原始的queryRaw或者queryRawCreate方法。它们允许你传递原始的SQL字符串,这些字符串会被添加到SELECT 和实体列后面。这种方式,你可以拥有一个 WHERE 和 ORDER BY 语句查询实体。这种实体表可以通过别名“T”引用。
下面的例子展示了如何创建一个query:使用联合获取名为“admin”的group的users
query = userDao.queryRawCreate(& ",
GROUP G WHERE G.NAME=? AND T.GROUP_ID=G._ID", "admin");
你可以通过生成的常量引用表或者列名。这样建议是为了避免错别字,因为编译器会检验这些名字。在任何实体的DAO,你可以发现 TABLENAME 持有着数据库的名字和一个内部类“Properties”.它的所有属性都是常量。
批量删除不删除单独的实体,但所有的实体要匹配一些准则。为了执行批量删除,创建一个QueryBuilder,调用它的buildDelete方法,它会返回一个DeleteQuery。
这部分的API可能会在以后有所变化,比如添加一些更加便利的方法。记住,批量删除现在不会影响到identity scope中的实体。在它们被通过ID访问之前(load 方法)
如果它们被缓存了,你可以激活那些将要被删除的实体。如果导致了一些使用的问题。你可以考虑清除identity scope。
查询故障处理
如果你的query没有返回期望的结果,这里有两个静态的flag,可以开启QueryBuilder身上的SQL和参数的log。
QueryBuilder.LOG_SQL
QueryBuilder.LOG_VALUES
它们会在任何build方法调用的时候打印出SQL命令和传入的值。这样你可以对你的期望值进行对比,或许也能够帮助你复制SQL语句到某些
SQLite 数据库的查看器中,执行并获取结果,以便进行比较。
版权所有 爱编程 (C) Copyright 2012. . All Rights Reserved.
闽ICP备号-3
微信扫一扫关注爱编程,每天为您推送一篇经典技术文章。}

我要回帖

更多关于 greendao 数据库更新 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信