关于GreenDao的优点已经不用再说了,关于第三方数据库框架有很多,相对于Android系统本身的SQLite以及其它第三方而言,我感觉GreenDao使用更方便,体积小、速度更快。网上大多是关于GreenDao之前版本的介绍,关于3.0+新版的介绍不多。GreenDao新版改动还是挺大的,之前版本使用起来比较复杂,需要新建项目,然后再项目中配置各个实体的字段等相关属性,然后生成实体以及DAO操作相关的一些类。而GreenDao3.0及其以后是通过注解的方式定义实体类,并且是通过插件来生成相应代码。
数据库应用的场景也非常多,比如:电商类app中最常见的就是搜索的历史记录等等,使用数据库进行增删改查就相对方便多了,并且GreenDao提供了数据库加密设置,更加安全。
先来张效果图
再看下我们通过@Entity设置的实体类中的字段在数据库中对应的字段以及相应的存储数据
这里说明一下:此demo演示的场景是,有网时,联网请求数据,请求成功后将数据保存到GreenDao数据库,没网时,则从数据库中取数据。访问数据接口采用的是Volley框架,当然了你还可以使用OkHttp等,采用Gson解析方式,或者采用阿里的FastJson,两种解析方式差不多,在设计实体类的时候要注意下,字段什么的要跟服务端给你的json串中字段相同,从而操作更加简单。其中请求接口返回三条数据,这里解释下为什么第二条数据没有图片,这不是Bug。。。这是因为第二条数据压根就没给图片,就是这么任性,所以说有时间还是要学学后端的,这样就可以自己写服务端了,测试起来也方便。由于接口返回数据比较多,这里主要是演示GreenDao3.0X数据库保存数据,这里我只是解析了部分字段,保存的时候也只是保存了两文本字段,图片相对麻烦就没有保存,正式开发的话是保存到缓存中的。
下面还是说下怎么使用新版GreenDao3.X 吧,先给出官网github地址:https://github.com/greenrobot/greenDAO
首先我们需要在Gradle中添加如下配置
//首先在project的gradle文件中引入greenDAO插件
buildscript {
repositories {
mavenCentral()
}
dependencies {
classpath 'org.greenrobot:greendao-gradle-plugin:3.0.0'
}
}
//然后在module的gradle文件中添加greenDAO的插件,并引入相关类库
apply plugin: 'org.greenrobot.greendao'
dependencies {
compile 'org.greenrobot:greendao:3.0.0'
}
最新版本是3.2.0,这里说下为什么我没用3.2.0版本,因为使用此版本编译一直报可奇怪的错,这里选用3.0.0也一样,主要就是为了说明跟之前2.X版本的区别。其中,我们看到classpath ‘org.greenrobot:greendao-gradle-plugin:3.0.0’这是添加插件的,用插件生成我们的相应代码用的。
同时,我们还可以配置当插件根据我们所定义的实体类自动生成的DaoMaster、DaoSession以及实体类相对应的XXXDAO类文件的存放目录。
greendao {
schemaVersion 1
daoPackage 'com.example.testproject.greendao.gen'
targetGenDir 'src/main/java'
}
说明:schemaVersion:表示指定数据库schema版本号,如果需要数据库升级,可以在这里修改数据库最新版本号。 daoPackage:表示生成的这些类文件在哪个包下面(默认为你的entity所在的包名)。 targetGenDir:就是上面所说的制定这些类文件所在的目录,这里我们设置跟我们代码目录相同,都是在java目录中,方便查看。
我们接下来写我们的实体类(ProductBean),这些实体类中的字段是要写进数据库的,就相当于一张表(ProductBean表)。写完之后我们选择Build–>Make Project,剩下的就交给插件了,就会自动帮我们生成(每次修改字段啥的,不要忘记Build–>Make Project), 如下图所示:
/**
* 实体类,存储到数据库
*/
@Entity
public class ProductBean {
private Long id;
@Property(nameInDb = "url")
private String picUrl;
@Property(nameInDb = "title")
private String proTitle;
@Property(nameInDb = "info")
private String proInfo;
@Property(nameInDb = "proId")
@Id
private Long proId;
}
这里有几点需要注意:GreenDao3.X 要求主键必须是Long或者long类型的。这里由于接口请求的数据中含有一个id,所以我就用这个id作为主键,当然这个id是String类型的,需要转换下。@Id:表示作为主键 @Property(nameInDb = “url”):表示该字段在数据库中的字段名称,还有很多属性,大家可以到官网上去了解,最后别忘了在定义实体类上面要加上@Entity因为插件要根据它生成相应的DAO。定义的有些字段是没用到的,大家测试的时候也可以自行删除。
GreenDao3.X 配置完了,接下来就是撸代码了。官方推荐将DaoMaster 对象的方法放到 Application 层,这样将避免多次创建生成 Session 对象。下面看下我们的application
/**
* 自定义MyApplication
*/
public class MyApplication extends Application {
private static MyApplication myApplication;
public RequestQueue requestQueue;
private static DaoMaster daoMaster;
private static DaoSession daoSession;
@Override
public void onCreate() {
super.onCreate();
myApplication = this;
//创建队列
requestQueue = Volley.newRequestQueue(this);
}
public static DaoMaster getDaoMaster(Context context){
if(daoMaster == null){
DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper(context,"mydata-db",null);
daoMaster = new DaoMaster(helper.getWritableDatabase());
}
return daoMaster;
}
public static DaoSession getDaoSession(Context context){
if(daoSession == null){
if(daoMaster == null){
daoMaster = getDaoMaster(context);
}
daoSession = daoMaster.newSession();
}
return daoSession;
}
public static MyApplication getApplication() {
return myApplication;
}
}
关于增、删、改、查,这些就比较简单了。这里简单说下,首先,我们先获取DaoSession,从而来操作数据库。查看源代码可以看到,GreenDao的一些例如:增、删等操作内部已经封装处理了事务回滚等操作,我们使用起来更加方便。
ProductBeanDao dao = MyApplication.getDaoSession(MainActivity.this).getProductBeanDao();
1. 插入(批量添加时属于耗时操作,GreenDao提供的有异步操作方法runInTx()方法)
ProductBean productBean = new ProductBean(null,null,productData.getName(),productData.getInfo(),Long.parseLong(productData.getId()));
dao.insert(productBean);
//dao.insertOrReplace(productBean);
//批量添加的情况(注意try的位置)
final List<ProductBean> lists = new ArrayList<ProductBean>();
for(int i=0;i<20;i++){
ProductBean productBean = new ProductBean();
productBean.setProTitle(xxxx);
productBean.setProInfo(xxxx);
lists.add(productBean);
}
try {
MyApplication.getDaoSession(MainActivity.this).runInTx(new Runnable() {
@Override
public void run() {
for(ProductBean bean : lists){
MyApplication.getDaoSession(MainActivity.this).insertOrReplace(bean);
}
}
});
}catch (Exception e){
e.printStackTrace();
}
2. 删除(删之前要先查一下,删除的方法有很多,可以删单条数据,也可以全部删除等等)
ProductBean bean = dao.queryBuilder().where(ProductBeanDao.Properties.ProTitle.eq("中青年抗癌互助计划")).build().unique();
if(bean != null){
dao.delete(bean);
}
3. 修改
ProductBean bean = dao.queryBuilder().where(ProductBeanDao.Properties.ProTitle.eq("中青年抗癌互助计划")).build().unique();
if(bean != null){
bean.setProTitle("修改title");
dao.update(bean);
}
4. 查询(可以写多个查询条件where,可以设置升序(orderAsc)、降序排列,limit:限制用于显示查询数据的数量,这里只要求显示3条数据,list():表示查询结果为一个集合, 当然了,还可以查单条数据unique())
List<ProductBean> lists = dao.queryBuilder()
.where(ProductBeanDao.Properties.ProId.eq(3))
.where(.......)
.orderAsc(ProductBeanDao.Properties.ProId)
.limit(3)
.build().list();
最后看下MainActivity的全部代码(这里我没有采用id自增长的方式(不然数据会添加重复数据),而是用返回数据中的id作为主键,并且采用dao.insertOrReplace(productBean)的方式防止重复添加,不能使用dao.insert(),因为主键不可重复,这样当再次点击按钮添加重复的数据就会报错。仅是测试,情景不同,具体情况具体对待)
public class MainActivity extends AppCompatActivity {
private ListView listView;
private ProductAdapter adapter;
private List<ListProBean> lists;
private Button btnRequest;
private static final String url = "http://test.xinlechou.com/index.php?r=api/insuranceList";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//初始化控件
iniViews();
getRequestDatas();
}
private void iniViews() {
listView = (ListView) findViewById(R.id.listView);
btnRequest = (Button) findViewById(R.id.btn_request);
}
public void getRequestDatas() {
btnRequest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//数据库,获取DAO
final ProductBeanDao dao = MyApplication.getDaoSession(MainActivity.this).getProductBeanDao();
if(NetUtil.isNetConnected(MainActivity.this)){
//volley请求数据
StringRequest request = new StringRequest(url, new Response.Listener<String>() {
@Override
public void onResponse(String response) {
Gson gson = new Gson();
ListProBean bean = gson.fromJson(response,ListProBean.class);
if(bean.getError() == 0){
ArrayList<ProductData> datas = bean.getData();
adapter = new ProductAdapter(MainActivity.this,datas);
listView.setAdapter(adapter);
//将数据保存到greendao数据库
for(int i=0;i<datas.size();i++){
ProductData productData = datas.get(i);
ProductBean productBean = new ProductBean(null,null,productData.getName(),productData.getInfo(),Long.parseLong(productData.getId()));
//插入数据库
// boolean flag = dao.insert(productBean) != -1 ? true : false;
boolean flag = dao.insertOrReplace(productBean) != -1 ? true : false;
if(flag){
Log.i("TAG","插入成功:"+i);
}else{
Log.i("TAG","插入失败:"+i);
}
}
}
}
}, new Response.ErrorListener() {
@Override
public void onErrorResponse(VolleyError error) {
//打印错误信息
}
});
//将请求放到队列中
MyApplication.getApplication().requestQueue.add(request);
}else{
Toast.makeText(MainActivity.this,"没有联网哟",Toast.LENGTH_SHORT).show();
//查数据库
List<ProductBean> lists = dao.queryBuilder().build().list();
if(lists != null && lists.size() > 0){
Toast.makeText(MainActivity.this,"从数据库中读取数据",Toast.LENGTH_SHORT).show();
List<ProductData> productDatas = new ArrayList<ProductData>();
for(int i=0;i<lists.size();i++){
ProductBean productBean = lists.get(i);
String title = productBean.getProTitle();
String info = productBean.getProInfo();
ProductData productData = new ProductData();
productData.setName(title);
productData.setInfo(info);
productDatas.add(productData);
}
adapter = new ProductAdapter(MainActivity.this,productDatas);
listView.setAdapter(adapter);
}
}
}
});
}
}