离线开发

开发工具: androidStudio ,SQLite3

使用开源库:GreenDao 3.2.2

离线已实现:

1.  增、删、改、查

2. 新增表,字段,更改字段,升级数据迁移

3. 从服务器下载数据,并更新到本地数据表,避免重复添加

4. 代码封装

集成:

1. 项目根目录添加环境

buildscript {...dependencies {classpath 'com.android.tools.build:gradle:3.6.0'classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' // 添加 GreenDao 插件}
}
allprojects {repositories {google()jcenter()maven { url 'https://jitpack.io' } // 添加}
}

2. app 下添加依赖

// 与 application 同级
apply plugin: 'com.android.application'
apply plugin: 'org.greenrobot.greendao'// android 节点中,rootProject.ext.publish.versionCode 文尾介绍
greendao {// 数据库升级视为 App 重大升级,跟随 versionCode ,方便记忆schemaVersion rootProject.ext.publish.versionCode
}// dependencies 节点中
implementation 'org.greenrobot:greendao:3.2.2' // 添加 

3. 对象,也就是表

@Entity(nameInDb = "Users")
public class UserBean {@Id(autoincrement = true)@Index(unique = true)//设置唯一性@Property(nameInDb = "F_id")private Long F_id;@Property(nameInDb = "F_byyx")private String F_byyx;@Property(nameInDb = "F_csrq")private String F_csrq;...
}

4. 普通的增删改查

UserBeanDao userBeanDao = DaoManager.getInstance().getDaoSession().getUserBeanDao();// 增
userBeanDao.insert(new UserBean(100L, "王大锤", "女"));// 删
userBeanDao.deleteByKey(100L);// 改
UserBean bean = mUserBeanDao.load(32L);
bean.setF_csrq("改改");
userBeanDao.update(bean);// 查
StringBuilder sb = new StringBuilder();
List<UserBean> userBeans = mUserBeanDao.loadAll();
for (UserBean userBean : userBeans) {sb.append("id:").append(userBean.getId()).append("f_id:").append(userBean.getF_id()).append("F_byyx:").append(userBean.getF_byyx()).append("F_csrq:").append(userBean.getF_csrq()).append("\n");
}
Log.i(TAG, "showDataList: "+sb.toString();

5. 新增表,字段,更改字段,升级时数据迁移,最后全部代码介绍

// 这里升级最好是将所有的表都写上,工具类会自动进行数据迁移MigrationHelper.migrate(db,StuffBeanDao.class,DepartmentBeanDao.class);

6. 从服务器下载数据,并更新到本地数据表,业务上会一次下载多张表,所以我统一放到了一个子线程中处理(真正实现过程使用的 IntentService ,其内部就是子线程,用完后,会自动销毁)

// 模拟网络数据
List<UserBean> list = new ArrayList<>();
list.add(new UserBean( 111L, "王大宝", "男"));
list.add(new UserBean( 112L, "王大宝", "男"));
list.add(new UserBean( 113L, "王大宝", "男"));
list.add(new UserBean( 114L, "王大宝", "男"));
list.add(new UserBean( 115L, "王大宝", "男"));
list.add(new UserBean( 116L, "王大宝", "男"));
list.add(new UserBean( 117L, "王大宝", "男"));// 更新或插入操作
for (int i = 0; i < list.size(); i++) {UserBean bean = list.get(i);// dao.hasKey(bean) 这句话只是说这个对象中是否存在主键,因为我设置了主键所以肯定存在// mUserBeanDao.load(bean.getF_id()) != null ,查询看看是否存在,存在则更新,不存在则插入if (mUserBeanDao.load(bean.getF_id()) != null) {mUserBeanDao.update(bean);} else {mUserBeanDao.insert(bean);}}

全部源码

// 常量
public interface DbConstants {String DB_NAME = "test.db";// 数据库名称}// 应用启动类
public class GreenDaoApplication extends Application {@Overridepublic void onCreate() {super.onCreate();initGreenDao();}/*** 初始化 GreenDao 数据库*/private void initGreenDao() {DaoManager.getInstance().init(this);DaoManager.getInstance().getDaoMaster();}
}// 数据迁移类
public final class MigrationHelper {private static final String TAG = "MigrationHelper";private static final String SQLITE_MASTER = "sqlite_master";private static final String SQLITE_TEMP_MASTER = "sqlite_temp_master";public static void migrate(SQLiteDatabase db, Class<? extends AbstractDao<?, ?>>... daoClasses) {LogUtil.d(TAG,"【The Old Database Version】" + db.getVersion());Database database = new StandardDatabase(db);migrate(database, daoClasses);}public static void migrate(Database database, Class<? extends AbstractDao<?, ?>>... daoClasses) {LogUtil.d(TAG,"【Generate temp table】start");generateTempTables(database, daoClasses);LogUtil.d(TAG,"【Generate temp table】complete");LogUtil.d(TAG,"【Drop all table and recreate all table】");for (int i = 0; i < daoClasses.length; i++) {DaoConfig daoConfig = new DaoConfig(database, daoClasses[i]);dropTable(database, true, daoConfig);createTable(database, false, daoConfig);}LogUtil.d(TAG,"【Restore data】start");restoreData(database, daoClasses);LogUtil.d(TAG,"【Restore data】complete");}private static void dropTable(Database database, boolean ifExists, DaoConfig daoConfig) {String sql = String.format("DROP TABLE %s\"%s\"", ifExists ? "IF EXISTS " : "", daoConfig.tablename);database.execSQL(sql);}private static void generateTempTables(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {for (int i = 0; i < daoClasses.length; i++) {String tempTableName = null;DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);String tableName = daoConfig.tablename;if (!isTableExists(db, false, tableName)) {LogUtil.d(TAG,"【New Table】" + tableName);continue;}try {tempTableName = daoConfig.tablename.concat("_TEMP");StringBuilder dropTableStringBuilder = new StringBuilder();dropTableStringBuilder.append("DROP TABLE IF EXISTS ").append(tempTableName).append(";");LogUtil.d(TAG,"【Generate temp table】 dropTableStringBuilder:" + dropTableStringBuilder);db.execSQL(dropTableStringBuilder.toString());StringBuilder insertTableStringBuilder = new StringBuilder();insertTableStringBuilder.append("CREATE TEMPORARY TABLE ").append(tempTableName);insertTableStringBuilder.append(" AS SELECT * FROM ").append(tableName).append(";");LogUtil.d(TAG,"【Generate temp table】 insertTableStringBuilder:" + insertTableStringBuilder);db.execSQL(insertTableStringBuilder.toString());LogUtil.d(TAG,"【Table】" + tableName +"\n ---Columns-->" + getColumnsStr(daoConfig));LogUtil.d(TAG,"【Generate temp table】" + tempTableName);} catch (SQLException e) {Log.e(TAG, "【Failed to generate temp table】" + tempTableName, e);}}}private static boolean isTableExists(Database db, boolean isTemp, String tableName) {if (db == null || TextUtils.isEmpty(tableName)) {return false;}String dbName = isTemp ? SQLITE_TEMP_MASTER : SQLITE_MASTER;String sql = "SELECT COUNT(*) FROM " + dbName + " WHERE type = ? AND name = ?";Cursor cursor=null;int count = 0;try {cursor = db.rawQuery(sql, new String[]{"table", tableName});if (cursor == null || !cursor.moveToFirst()) {return false;}count = cursor.getInt(0);} catch (Exception e) {e.printStackTrace();} finally {if (cursor != null)cursor.close();}return count > 0;}private static String getColumnsStr(DaoConfig daoConfig) {if (daoConfig == null) {return "no columns";}StringBuilder builder = new StringBuilder();for (int i = 0; i < daoConfig.allColumns.length; i++) {builder.append(daoConfig.allColumns[i]);builder.append(",");}if (builder.length() > 0) {builder.deleteCharAt(builder.length() - 1);}return builder.toString();}private static void restoreData(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {for (int i = 0; i < daoClasses.length; i++) {DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);String tableName = daoConfig.tablename;String tempTableName = daoConfig.tablename.concat("_TEMP");if (!isTableExists(db, true, tempTableName)) {continue;}try {// get all columns from tempTable, take careful to use the columns listList<String> columns = getColumns(db, tempTableName);ArrayList<String> properties = new ArrayList<>(columns.size());for (int j = 0; j < daoConfig.properties.length; j++) {String columnName = daoConfig.properties[j].columnName;if (columns.contains(columnName)) {properties.add(columnName);}}if (properties.size() > 0) {final String columnSQL = TextUtils.join(",", properties);StringBuilder insertTableStringBuilder = new StringBuilder();insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" (");insertTableStringBuilder.append(columnSQL);insertTableStringBuilder.append(") SELECT ");insertTableStringBuilder.append(columnSQL);insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";");LogUtil.d(TAG,"【Restore data】 db sql: " + insertTableStringBuilder);db.execSQL(insertTableStringBuilder.toString());LogUtil.d(TAG,"【Restore data】 to " + tableName);}StringBuilder dropTableStringBuilder = new StringBuilder();dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);db.execSQL(dropTableStringBuilder.toString());LogUtil.d(TAG,"【Drop temp table】" + tempTableName);} catch (SQLException e) {Log.e(TAG, "【Failed to restore data from temp table 】" + tempTableName, e);}}}private static List<String> getColumns(Database db, String tableName) {List<String> columns = null;Cursor cursor = null;try {cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 0", null);if (null != cursor && cursor.getColumnCount() > 0) {columns = Arrays.asList(cursor.getColumnNames());}} catch (Exception e) {e.printStackTrace();} finally {if (cursor != null)cursor.close();if (null == columns)columns = new ArrayList<>();}return columns;}public static void createTable(Database db, boolean ifNotExists, DaoConfig daoConfig) {String tableName = daoConfig.tablename;StringBuilder builder = new StringBuilder();builder.append("CREATE TABLE ");builder.append(ifNotExists ? "IF NOT EXISTS ": "");builder.append(tableName);builder.append(getColumnsSql(daoConfig));LogUtil.d(TAG,"【createTable】 sql:" + builder.toString());db.execSQL(builder.toString()); // 6: Description}private static String getColumnsSql(DaoConfig daoConfig) {if (daoConfig == null) {return "";}StringBuilder builder = new StringBuilder(" (");for (int i = 0; i < daoConfig.properties.length; i++) {builder.append(String.format("\"%s\" %s,", daoConfig.properties[i].columnName,getPropertyType(daoConfig.properties[i].type)));}if (daoConfig.properties.length > 0 && builder.length() > 0) {builder.deleteCharAt(builder.length() - 1);}builder.append("); ");return builder.toString();}/*** 根据字段类型返回对应的数据库字段语句* @param type* @return*/private static String getPropertyType(Class<?> type) {if (type.equals(byte[].class)) {return "BLOB";} else if (type.equals(String.class)) {return "TEXT DEFAULT ''";} else if (type.equals(boolean.class) || type.equals(Boolean.class)|| type.equals(int.class) || type.equals(Integer.class)|| type.equals(long.class) || type.equals(Long.class)|| type.equals(Date.class) || type.equals(Byte.class)) {return "INTEGER DEFAULT (0)";} else if (type.equals(float.class) || type.equals(Float.class)|| type.equals(double.class) || type.equals(Double.class)){return "REAL DEFAULT (0)";}return "TEXT DEFAULT ''";}}// 数据库管理类,封装
public class DaoManager {private Context mContext;//创建数据库的名字private static final String DB_NAME = DbConstants.DB_NAME;//多线程中要被共享的使用volatile关键字修饰  GreenDao管理类private volatile static DaoManager mInstance;//它里边实际上是保存数据库的对象private static DaoMaster mDaoMaster;//创建数据库的工具private static DbOpenHelper mHelper;//管理gen里生成的所有的Dao对象里边带有基本的增删改查的方法private static DaoSession mDaoSession;private DaoManager() {}/*** 单例模式获得操作数据库对象** @return*/public static DaoManager getInstance() {if (mInstance == null) {synchronized (DaoManager.class) {if (mInstance == null) {mInstance = new DaoManager();}}}return mInstance;}/*** 初始化上下文创建数据库的时候使用*/public void init(Context context) {this.mContext = context;}/*** 判断是否有存在数据库,如果没有则创建** @return*/public DaoMaster getDaoMaster() {if (mDaoMaster == null) {mHelper = new DbOpenHelper(mContext,DB_NAME);mDaoMaster = new DaoMaster(mHelper.getWritableDatabase());}return mDaoMaster;}/*** 完成对数据库的添加、删除、修改、查询操作,** @return*/public DaoSession getDaoSession() {if (mDaoSession == null) {if (mDaoMaster == null) {mDaoMaster = getDaoMaster();}mDaoSession = mDaoMaster.newSession(IdentityScopeType.None);}return mDaoSession;}/*** 关闭所有的操作,数据库开启后,使用完毕要关闭*/public void closeConnection() {closeHelper();closeDaoSession();}public void closeHelper() {if (mHelper != null) {mHelper.close();mHelper = null;}}public void closeDaoSession() {if (mDaoSession != null) {mDaoSession.clear();mDaoSession = null;}}
}// 升级时需要的类public class DbOpenHelper extends DaoMaster.OpenHelper {public DbOpenHelper(Context context, String name) {super(context, name);}@Overridepublic void onCreate(Database db) {super.onCreate(db);startMigrate(db);}@Overridepublic void onUpgrade(Database db, int oldVersion, int newVersion) {super.onUpgrade(db, oldVersion, newVersion);startMigrate(db);}private void startMigrate(Database db) {// 这里升级最好是将所有的表都写上,关键是数据库一定要更新,版本 和 app 同步,MigrationHelper.migrate(db,StuffBeanDao.class,DepartmentBeanDao.class);}}

文章结尾:

解释:schemaVersion rootProject.ext.publish.versionCode ,就是全局配置,如果依赖库多了方便管理

步骤1:在项目根目录新建 config.gradle 文件

ext {android = [compileSdkVersion: 29,buildToolsVersion: "28.0.0",minSdkVersion    : 19,targetSdkVersion : 28,supportLibVersion: "28.0.0"]publish = [applicationId: "com.test.test",versionCode  : 1,versionName  : "1.0"]
}

步骤2:在项目根目录 build.gradle 文件顶部引入

apply from: "config.gradle"

步骤3:在 App build.gradle 文件中使用

greendao {// 跟随 versionCode todo 数据库升级视为 App 重大升级,直接升级 VersionCode & VersionNameschemaVersion rootProject.ext.publish.versionCode
}

Android GreenDao相关推荐

  1. Android GreenDao数据库框架

    ## Android GreenDao数据库框架 GreenDao简介 Android平台的对象关系映射工具(ORM) 为关系型数据库提供面向对象的接口 简化数据库操作 ORM框架 所谓ORM框架,即 ...

  2. Android GreenDao框架使用 基础篇

    参考 官方文档 Github 一.准备工作 在工程的build.gradle文件中添加 repositories {...mavenCentral()}dependencies {...classpa ...

  3. Android浏览历史sqlite功能,[Android]greendao实现搜索历史功能

    使用greendao实现搜索历史功能 ezgif-1-378e749b52.gif device-2017-08-31-103330.png 之前封装sqlite实现过这功能,不过原生封装使用sql语 ...

  4. Android GreenDao简单使用

    现在市面上主流的框架有 OrmLite.SugarORM.Active Android.Realm 与 GreenDAO. 官网上的介绍,greenDAO 是一个将对象映射到 SQLite 数据库中的 ...

  5. android多条件查询数据,Android GreenDao 条件查询问题

    使用GreenDao保存了全国城市的属性(名字,代码,省份等等),保存可以成功,无条件查询全部数据时可以成功: private List queryCitiesInfo(){ List cityInf ...

  6. Android GreenDAO 3.0 不修改版本号的情况下增加、删除表、添加字段

    最近项目中使用了GreenDAO的3.0以上的版本,出现需要增加删除表的需求,刚开始用,发现官方对增加和删除的方法是每次去修改数据库版本号,版本一旦升级,那么原来数据库中的表会全部删除再重建.太麻烦, ...

  7. android bean对象,Android GreenDao 保存 JavaBean 或者List JavaBean类型数据

    GreenDao 简介 数据库存储数据基本上每个APP都有用到,GreenDAO 是一个将对象映射到 SQLite 数据库中的轻量且快速的 ORM 解决方案,至于用法这里不再多少,网上有很资料,这里主 ...

  8. 《Android 开源库》 GreenDAO 用法详解(译文)

    简介 greenDAO是一个开源的Android ORM,使SQLite数据库的开发再次变得有趣. 它减轻了开发人员处理底层的数据库需求,同时节省开发时间. SQLite是一个很不错的关系型数据库. ...

  9. 使用ORM数据库:greenDao

    1. 添加依赖: // 在总的 build.gradle 中 buildscript {     repositories {         jcenter()         mavenCentr ...

最新文章

  1. Citrix通用打印服务器配置
  2. UVa 11168 Airport , 凸包
  3. php 表单提交及验证 tp,ThinkPHP表单自动提交验证实例教程
  4. 攻破Win7~Win10 PatchGuard(KPP DSE)【支持Win10 TH1/TH2/RS1/RS2】【WIN64内核越狱】
  5. 信息学奥赛一本通 1064:奥运奖牌计数 | OpenJudge NOI 1.5 07
  6. python写一个类方法_python中如何写类
  7. Python的PyDBG调试器的用法
  8. ASP.net2.0调试JavaScript脚本
  9. 贪心----汽车加油问题
  10. (三)线程同步工具集_1---控制线程并发访问一个资源
  11. 什么的SIT测试?什么是UAT测试?
  12. matlab 距平,[转载]基于Matlab软件进行EOF分解、回归趋势分析,并
  13. 无法打开html5,IE浏览器无法打开怎么办
  14. win7美化_桌面美化,无敌的dock软件,桌面便捷工具、桌面整理、更新鼠标美化...
  15. 黑马程序员_银行调度系统
  16. python常用单词
  17. 小程序源码:全新实用工具证件照制作-多玩法安装简单
  18. 彩虹秒赞7.8源码破解版(去域名授权) 彩虹云任务系统无任何限制
  19. SAP系统接口对接历险记
  20. 各种OOM代码样例及解决方法

热门文章

  1. RGB与16进制值互相转换
  2. 探索AI视觉技术新应用,夸克扫描王首推“离线模式”端侧AI算法提升隐私安全
  3. 内网渗透-内网代理穿透和内网横向移动
  4. linux打开终端的快捷键放大,linux打开终端的快捷键是什么?
  5. OSError: Could not find kaggle.json. Make sure it‘s located in /Users/peco/.kaggle
  6. 手绘图解:从零维到十维空间
  7. Android穿山甲SDK接入,已封装直接使用
  8. s17王者服务器维护几点,王者荣耀S17赛季更新维护几点开始?王者荣耀四周年更新多久...
  9. safari浏览网页打开速度很慢怎样解决
  10. 微软的学术可视化搜索