Litepal【开源数据库ORM框架】
版权声明:本文为HaiyuKing原创文章,转载请注明出处!
前言
好用的数据库框架。
效果图
代码分析
本篇主要是整理Litepal的引入和增删改查的简单操作,具体使用请阅读参考资料。
使用步骤
一、项目组织结构图
注意事项:
1、 导入类文件后需要change包名以及重新import R文件路径
2、 Values目录下的文件(strings.xml、dimens.xml、colors.xml等),如果项目中存在,则复制里面的内容,不要整个覆盖
二、导入步骤
(1)引入Litepal框架(在APP的bundle.gradle文件中添加标记的代码)
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion "25.0.3"
defaultConfig {
applicationId "com.why.project.litepaldemo"
minSdkVersion 15
targetSdkVersion 22
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
exclude group: 'com.android.support', module: 'support-annotations'
})
compile 'com.android.support:appcompat-v7:25.3.1'
testCompile 'junit:junit:4.12'
//Litepal数据库
compile 'org.litepal.android:core:1.6.1'
}
(2)配置litepal.xml(在项目的assets目录中创建litepal.xml文件,并添加以下代码(或者复制Demo中的litepal.xml文件到项目中))
<?xml version="1.0" encoding="utf-8"?> <litepal> <!-- <dbname>用于设定数据库的名字 --> <dbname value="why" ></dbname> <!-- <version>用于设定数据库的版本号 --> <version value="1" ></version> <!-- <list>用于设定所有的映射模型 --> <list> <!-- model类,例子如下: --> <!-- <mapping class="com.why.model.ClassName"></mapping> --> </list> <!-- 在开发阶段调试的时候,将数据库文件存放在SD卡/sdcard/Android/data/<package name>/files/databases目录下 --> <!-- 注意,此功能尽量只在调试的时候使用,把数据库文件存放在SD卡真的很不安全。 --> <!-- 在litepal-1.3.2上支持,需要添加权限【实现将数据库保存到默认位置】 --> <storage value="external"></storage> <!-- 在litepal-1.6.0上支持,需要添加权限、申请运行时权限【实现将数据库保存到SD卡指定位置】 --> <!--<storage value="guolin/database" />--> </litepal>
备注:多数据库功能请阅读参考资料。
(3)配置LitePalApplication
一般项目中都会自定义一个MyApplication,只需要在原来的基础上添加标记的代码即可。
package com.why.project.litepaldemo; import android.app.Application; import android.database.sqlite.SQLiteDatabase; import org.litepal.LitePal; /** * Created by HaiyuKing * Used */ public class MyApplication extends Application{ @Override public void onCreate() { super.onCreate(); /*=================litepal数据库=====================*/ LitePal.initialize(this); //获取到SQLiteDatabase的实例,创建数据库表 SQLiteDatabase db = LitePal.getDatabase(); } }
在AndroidManifest.xml文件中声明权限以及MyApplication【如果想要实现将数据库保存到SD卡指定位置,那么需要申请这些权限,否则不需要申请权限,一般情况下不需要】
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.why.project.litepaldemo"> <!-- =================Litepal用到的权限========================== --> <!-- 允许程序读取外部存储文件 --> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <!-- 允许程序写入外部存储,如SD卡上写文件 --> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"></uses-permission> <!-- 在SD卡中创建与删除文件权限 --> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> <application android:name=".MyApplication" android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> </manifest>
(4)添加运行时权限的处理(本demo中采用的是修改targetSDKVersion=22)【如果想要实现将数据库保存到SD卡指定位置,那么需要申请这些权限,否则不需要申请权限,一般情况下不需要】
三、使用方法
(1)创建表
- 新建model类并继承DataSupport(拥有了进行CRUD操作的能力)
package com.why.project.litepaldemo.model; import org.litepal.annotation.Column; import org.litepal.crud.DataSupport; /** * Created by HaiyuKing * Used 登录账号数据库表 */ public class LoginUserModel extends DataSupport{ @Column(nullable = false) private String userName;//不能为空 @Column(nullable = false) private String passWord; @Column(unique = true) private String userId;//不可重复 private String tel; public String getPassWord() { return passWord; } public void setPassWord(String passWord) { this.passWord = passWord; } public String getTel() { return tel; } public void setTel(String tel) { this.tel = tel; } public String getUserId() { return userId; } public void setUserId(String userId) { this.userId = userId; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } }
备注:
一、字段命名应避免数据库关键字:比如id、index、text等
二、
@Column(nullable = false) :不能为空
@Column(unique = true) : 不可重复
@Column(ignore = true) : 不映射到数据库表中
三、主键ID自动生成;
四、支持存储的数据类型有:int、long、short、float、double、boolean、char、String、Date九种,1.3.1版本中引入了第十种数据类型:byte[]。
五、从1.4.0版本开始支持集数数据的存储了。除了支持List<String>集合之外,还有List<Integer>、List<Boolean>、List<Long>、List<Float>、List<Double>、List<Character>这几种类型的集合也是支持的。
六、不论字段名大小写,数据库表中的字段均为小写。
- 将该model类配置到映射列表(litepal.xml)当中
<?xml version="1.0" encoding="utf-8"?> <litepal> <!-- <dbname>用于设定数据库的名字 --> <dbname value="why" ></dbname> <!-- <version>用于设定数据库的版本号 --> <version value="1" ></version> <!-- <list>用于设定所有的映射模型 --> <list> <!-- model类,例子如下: --> <!-- <mapping class="com.why.model.ClassName"></mapping> --> <mapping class="com.why.project.litepaldemo.model.LoginUserModel"></mapping> </list> <!-- 在开发阶段调试的时候,将数据库文件存放在SD卡/sdcard/Android/data/<package name>/files/databases目录下 --> <!-- 注意,此功能尽量只在调试的时候使用,把数据库文件存放在SD卡真的很不安全。 --> <!-- 在litepal-1.3.2上支持,需要添加权限【实现将数据库保存到默认位置】 --> <storage value="external"></storage> <!-- 在litepal-1.6.0上支持,需要添加权限、申请运行时权限【实现将数据库保存到SD卡指定位置】 --> <!--<storage value="guolin/database" />--> </litepal>
- 执行SQLiteDatabase db = Connector.getDatabase();(只要你对数据库有任何的操作,news表就会被自动创建出来)
因为写在MyApplication中了,也就是说APP启动的时候就执行创建表的操作了。当然了,可以根据实际需求写在任何一个位置。
数据库表在SD卡中
(2)查看数据库表
使用sqlitebrowser软件查看数据库表
下载地址:链接:http://pan.baidu.com/s/1dER1Kat 密码:64ww
使用方法:
(3)升级表
如果已有的表model类中新增、减少、修改字段或者新建表的model类,都需要升级表。
- 新建model类并继承DataSupport
如果升级的是已有表,则添加、删除、修改已有表的字段。
- 在映射列表中新增model类,并将版本号+1【如果升级的是已有表,则只将版本号+1】
<version value="2" ></version>
- 执行SQLiteDatabase db = Connector.getDatabase();
(4)建立表关联
http://blog.csdn.net/guolin_blog/article/details/39207945
(5)存储数据
- save()
LoginUserModel model = new LoginUserModel(); model.setUserId("00001"); model.setUserName("用户名1"); model.setPassWord("密码1"); model.setTel("18600001"); model.save();
- saveAsync()
异步保存。
LoginUserModel model = new LoginUserModel(); model.setUserId("00001"); model.setUserName("用户名1"); model.setPassWord("密码1"); model.setTel("18600001"); model.saveAsync().listen(new SaveCallback() { @Override public void onFinish(boolean success) { } });
- saveThrows()
如果希望存储失败的话就抛出异常,而不是返回一个false,那就可以使用saveThrows()方法来代替。使用saveThrows()方法来存储数据,一旦存储失败就会抛出一个DataSupportException异常,我们可以通过对这个异常进行捕获来处理存储失败的情况。
LoginUserModel model = new LoginUserModel(); model.setUserId("00001"); model.setUserName("用户名1"); model.setPassWord("密码1"); model.setTel("18600001"); model.saveThrows();
- saveOrUpdate
处理不存在就存储,已存在就更新的需求
LoginUserModel model = new LoginUserModel(); model.setUserId("00001"); model.setUserName("用户名1_"); model.setPassWord("密码1_"); model.setTel("18600001"); model.saveOrUpdate("userid=?",model.getUserId());
- saveOrUpdateAsync
异步处理不存在就存储,已存在就更新的需求
LoginUserModel model = new LoginUserModel(); model.setUserId("00001"); model.setUserName("用户名1_"); model.setPassWord("密码1_"); model.setTel("18600001"); model.saveOrUpdateAsync("userid=?",model.getUserId()) .listen(new SaveCallback() { @Override public void onFinish(boolean success) { } });
- saveAll
专门用于存储集合数据的。
LoginUserModel model2 = new LoginUserModel(); model2.setUserId("00002"); model2.setUserName("用户名2"); model2.setPassWord("密码2"); model2.setTel("18600002"); LoginUserModel model3 = new LoginUserModel(); model3.setUserId("00003"); model3.setUserName("用户名3"); model3.setPassWord("密码3"); model3.setTel("18600003"); List<LoginUserModel> loginList = new ArrayList<LoginUserModel>(); loginList.add(model2); loginList.add(model3); DataSupport.saveAll(loginList);
- saveAllAsync
专门用于异步存储集合数据的。
LoginUserModel model2 = new LoginUserModel(); model2.setUserId("00002"); model2.setUserName("用户名2"); model2.setPassWord("密码2"); model2.setTel("18600002"); LoginUserModel model3 = new LoginUserModel(); model3.setUserId("00003"); model3.setUserName("用户名3"); model3.setPassWord("密码3"); model3.setTel("18600003"); List<LoginUserModel> loginList = new ArrayList<LoginUserModel>(); loginList.add(model2); loginList.add(model3); DataSupport.saveAllAsync(loginList).listen(new SaveCallback() { @Override public void onFinish(boolean success) { } });
(6)修改数据
- update()
根据主键id值(litepal数据库自动生成的ID值,从1开始)修改数据。
ContentValues values = new ContentValues(); values.put("username","用户名2_"); int updateNum = DataSupport.update(LoginUserModel.class,values,2);//修改id值等于2的那一行数据 Log.w(TAG,"{btn_update}updateNum="+updateNum);
- updateAll()
根据某个查询条件进行修改数据。
ContentValues values = new ContentValues(); values.put("username","用户名3_"); int updateAllNum = DataSupport.updateAll(LoginUserModel.class,values,"userid=?","00003");//修改userid=00003的那一行数据 Log.w(TAG,"{btn_update}updateAllNum="+updateAllNum);
(7)查询数据
普通查询
- findFirst()
取出表中的第一条数据。
LoginUserModel firstModel = DataSupport.findFirst(LoginUserModel.class); Log.w(TAG,"userId = " + firstModel.getUserId());
- findLast()
取出表中的最后一条数据。
LoginUserModel lastModel = DataSupport.findLast(LoginUserModel.class); Log.w(TAG,"userId = " + lastModel.getUserId());
- findAll()
查询所有数据。
List<LoginUserModel> findAllList = DataSupport.findAll(LoginUserModel.class); if(findAllList.size() > 0){ for(LoginUserModel model : findAllList){ Log.w(TAG,"model.getUserId()" + model.getUserId()); } }
连缀查询
- where()
List<LoginUserModel> findWhereList = DataSupport.where("userid=?","00003").find(LoginUserModel.class); if(findWhereList.size() > 0){ for(LoginUserModel model : findWhereList){ Log.w(TAG,"model.getUserId()" + model.getUserId()); } }
- select()
List<LoginUserModel> findSelectList = DataSupport.select("userid","username").where("userid=?","00003").find(LoginUserModel.class); if(findSelectList.size() > 0){ for(LoginUserModel model : findSelectList){ Log.w(TAG,"model.getUserId()" + model.getUserId()); } }
- order()
order()方法中接收一个字符串参数,用于指定查询出的结果按照哪一列进行排序,asc表示正序排序,desc表示倒序排序。
List<LoginUserModel> findOrderList = DataSupport.select("userid","username") .where("userid=?","00003") .order("userid desc") .find(LoginUserModel.class); if(findOrderList.size() > 0){ for(LoginUserModel model : findOrderList){ Log.w(TAG,"model.getUserId()" + model.getUserId()); } }
- limit()
这个方法接收一个整型参数,用于指定查询前几条数据。
List<LoginUserModel> findlimitList = DataSupport.select("userid","username") .where("userid=?","00003") .limit(10) .find(LoginUserModel.class); if(findlimitList.size() > 0){ for(LoginUserModel model : findlimitList){ Log.w(TAG,"model.getUserId()" + model.getUserId()); } }
- offset()
用于指定查询结果的偏移量。
List<LoginUserModel> findoffsetList = DataSupport.select("userid","username") .where("userid=?","00003") .limit(10) .offset(10) .find(LoginUserModel.class); if(findoffsetList.size() > 0){ for(LoginUserModel model : findoffsetList){ Log.w(TAG,"model.getUserId()" + model.getUserId()); } }
- findFirst()【连缀查询中查询结果的第一行数据】
LoginUserModel findWhereFisrt = DataSupport.where("userid=?","00003").findFirst(LoginUserModel.class); Log.w(TAG,"findWhereFisrt.getUserId()" + findWhereFisrt.getUserId());
- findLast()【连缀查询中查询结果的最后一行数据】
LoginUserModel findWhereLast = DataSupport.where("userid=?","00003").findLast(LoginUserModel.class); Log.w(TAG,"findWhereFisrt.getUserId()" + findWhereLast.getUserId());
- isExist()
boolean isExist = DataSupport.isExist(LoginUserModel.class,"userid=?","00003"); Log.w(TAG,"isExist=" + isExist);
激进查询
http://blog.csdn.net/guolin_blog/article/details/40153833
原生查询
http://blog.csdn.net/guolin_blog/article/details/40153833
(8)删除数据
- delete()
需要注意的是,这不仅仅会将news表中的记录删除,同时还会将其它表中以这条记录作为外键的数据一起删除掉,因为外键既然不存在了,那么这么数据也就没有保留的意义了。
int DelNum = DataSupport.delete(LoginUserModel.class,1);//删除ID值等于1的那一行数据 Log.w(TAG,"DelNum=" + DelNum);
- deleteAll()
int delAllNum = DataSupport.deleteAll(LoginUserModel.class,"userid=?","00002"); Log.w(TAG,"delAllNum=" + delAllNum);
在不指定约束条件的情况下,deleteAll()方法就会删除表中所有的数据了。
int delAllNum = DataSupport.deleteAll(LoginUserModel.class); Log.w(TAG,"delAllNum=" + delAllNum);
(9)聚合函数
http://blog.csdn.net/guolin_blog/article/details/40614197
(10)加密功能
https://mp.weixin.qq.com/s/TSp36cnKLxUmAHjT86UCrQ
混淆配置
#=====================litpal框架混淆=====================
-dontwarn org.litepal.*
-keep class org.litepal.**{*;}
-keep enum org.litepal.**
-keep interface org.litepal.**{*;}
-keep public class * extends org.litepal.**
-keepattributes *Annotation*
-keepclassmembers enum * {
public static **[] values();
public static ** valueOf(java.lang.String);
}
-keepclassmembers class * extends org.litepal.crud.DataSupport{*;}
参考资料
Android数据库高手秘籍(二)——创建表和LitePal的基本用法
LitePal 1.6.0版本来袭,数据加解密功能保障你的应用数据安全