大家的项目中不可避免的使用到SQLite,为此我们要花费心思编写一个增删改查框架。而一个好的ORM框架则能够给我们带来极大的方便,今天给大家讲解一个非常火热的ORM-GreenDao。
基本概念
GreenDao官网地址:http://greenrobot.org/greendao/
官网对GreenDao的介绍:
greenDAO is an open source library for Android providing an easy-to-use interface to SQLite to help developers handle data efficiently – relieving developers from dealing with low-level database stuff and saving development time. SQLite is an awesome embedded relational database. Still, writing SQL and parsing query results are quite tedious and time-consuming tasks. greenDAO frees you from these by mapping Java objects to database tables (often called ORM). This way you can store, update, delete, and query for Java objects using a simple object oriented API.
简单的说就是:greenDAO 是一个将对象映射到 SQLite 数据库中的轻量且快速的 ORM 解决方案。
greenDAO 设计的主要目标
- 一个精简的库
- 性能最大化
- 内存开销最小化
- 易于使用的 APIs
- 对 Android 进行高度优化
greenDAO 设计的主要特点
- greenDAO 性能远远高于同类的 ORMLite,具体测试结果可见官网
- greenDAO 支持 protocol buffer(protobuf) 协议数据的直接存储,如果你通过 protobuf
协议与服务器交互,将不需要任何的映射。 - 与 ORMLite 等使用注解方式的 ORM 框架不同,greenDAO 使用「Code
generation」的方式,这也是其性能能大幅提升的原因。
Dao项目代码生成
DaoMaster:一看名字就知道它是Dao中的最大的官了。它保存了sqlitedatebase对象以及操作DAO classes(注意:不是对象)。其提供了一些创建和删除table的静态方法,其内部类OpenHelper和DevOpenHelper实现了SQLiteOpenHelper并创建数据库的框架。
DaoSession:会话层。操作具体的DAO对象(注意:是对象),比如各种getter方法。
XXXDao:实际生成的某某DAO类,通常对应具体的java类,比如NoteDao等。其有更多的权限和方法来操作数据库元素。
XXXEntity:持久的实体对象。通常代表了一个数据库row的标准java properties。
了解了基本概念后我们开始动手完成一个增删改查的项目案例。
实现过程
1.在 Android 工程中配置「greenDao Generator」模块
在 .src/main 目录下新建一个与 java 同层级的「java-gen」目录,用于存放由 greenDAO 生成的 Bean、DAO、DaoMaster、DaoSession 等类。
配置 Android 工程(app)的 build.gradle,如图分别添加 sourceSets 与 dependencies
1 sourceSets { 2 main { 3 java.srcDirs = ['src/main/java', 'src/main/java-gen'] 4 } 5 }
1 compile 'de.greenrobot:greendao:1.3.7'
2.新建「greenDAO Generator」模块 (纯 Java 工程)
通过 File -> New -> New Module -> Java Library -> 填写相应的包名与类名 -> Finish
配置 castielgreendaolb 工程的 build.gradle,添加 dependencie
注意主句话,配置输出路径
1 def outputDir = "../app/src/main/java-gen"
接着,编写 CastielGreenDao类,注意: 我们的 Java 工程只有一个类,它的内容决定了「GreenDao Generator」的输出,你可以在这个类中通过对象、关系等创建数据库结构,下面我将以注释的形式详细讲解代码内容。
1 package com.castiel.dao; 2 3 import de.greenrobot.daogenerator.DaoGenerator; 4 import de.greenrobot.daogenerator.Entity; 5 import de.greenrobot.daogenerator.Schema; 6 7 public class CastielGreenDao { 8 public static void main(String args[]) throws Exception { 9 // 创建了一个用于添加实体(Entity)的模式(Schema)对象。 10 // 两个参数分别代表:数据库版本号与自动生成代码的包路径。 11 Schema schema = new Schema(1, "greendao"); 12 schema.setDefaultJavaPackageDao("com.castiel.dao"); 13 14 // 一旦你拥有了一个 Schema 对象后,你便可以使用它添加实体(Entities)了。 15 addNote(schema); 16 17 // 最后我们将使用 DAOGenerator 类的 generateAll() 方法自动生成代码,此处你需要根据自己的情况更改输出目录(既之前创建的 java-gen)。 18 new DaoGenerator().generateAll(schema, args[0]); 19 } 20 21 /** * @param schema */ 22 private static void addNote(Schema schema) { 23 // 一个实体(类)就关联到数据库中的一张表,此处表名为「Student」(既类名) 24 Entity note = schema.addEntity("Student"); 25 // 你也可以重新给表命名 26 // note.setTableName("Student2"); 27 28 // greenDAO 会自动根据实体类的属性值来创建表字段,并赋予默认值 29 // 接下来你便可以设置表中的字段: 30 // 与在 Java 中使用驼峰命名法不同,默认数据库中的命名是使用大写和下划线来分割单词的。 31 note.addIdProperty(); 32 note.addStringProperty("sName").notNull(); 33 note.addStringProperty("sAge"); 34 note.addStringProperty("sSex"); 35 note.addStringProperty("sClass"); 36 } 37 }
3.生成 DAO 文件(数据库)
执行 generator 工程,如一切正常,你将会在控制台看到如下日志,并且在主工程「java-gen」下会发现生成了DaoMaster、DaoSession、StudentDao、Student共4个类文件。
1 greenDAO Generator 2 Copyright 2011-2013 Markus Junginger, greenrobot.de. Licensed under GPL V3. 3 This program comes with ABSOLUTELY NO WARRANTY 4 Processing schema version 1... 5 Written C:\Users\huangshuai\AndroidStudioProjects\CastielGreenDao\app\src\main\java-gen\com\castiel\dao\StudentDao.java 6 Written C:\Users\huangshuai\AndroidStudioProjects\CastielGreenDao\app\src\main\java-gen\greendao\Student.java 7 Written C:\Users\huangshuai\AndroidStudioProjects\CastielGreenDao\app\src\main\java-gen\com\castiel\dao\DaoMaster.java 8 Written C:\Users\huangshuai\AndroidStudioProjects\CastielGreenDao\app\src\main\java-gen\com\castiel\dao\DaoSession.java 9 Processed 1 entities in 153ms 10 11 BUILD SUCCESSFUL
构建Android项目实现增删改查
先来张项目结构全景图
再来张项目效果图
在官网中,提供了一段核心初始化代码,推荐将该段代码放在Application中
1 helper = new DaoMaster.DevOpenHelper( this, "notes-db", null); 2 db = helper.getWritableDatabase(); 3 daoMaster = new DaoMaster(db); 4 daoSession = daoMaster.newSession(); 5 noteDao = daoSession.getNoteDao();
即:在自己的Application中先创建了一个SQLiteOpenHelper并创建连接到一个具体数据库;再根据具体的datebase创建一个master对象用于;最后通过master创建一个数据库的会话操作。
1 package com.castiel.dao; 2 3 import android.app.Application; 4 import android.database.sqlite.SQLiteDatabase; 5 6 /** * Created by huangshuai on 2016/5/11. * Email:[email protected] */ 7 public class BaseApplication extends Application { 8 public DaoSession daoSession; 9 public SQLiteDatabase db; 10 public DaoMaster.DevOpenHelper helper; 11 public DaoMaster daoMaster; 12 13 @Override 14 public void onCreate() { 15 super.onCreate(); 16 setupDatabase(); 17 } 18 19 private void setupDatabase() { 20 // 通过 DaoMaster 的内部类 DevOpenHelper,你可以得到一个便利的 SQLiteOpenHelper 对象。 21 // 可能你已经注意到了,你并不需要去编写「CREATE TABLE」这样的 SQL 语句,因为 greenDAO 已经帮你做了。 22 // 注意:默认的 DaoMaster.DevOpenHelper 会在数据库升级时,删除所有的表,意味着这将导致数据的丢失。 23 // 所以,在正式的项目中,你还应该做一层封装,来实现数据库的安全升级。 24 helper = new DaoMaster.DevOpenHelper(this, "student", null); 25 db = helper.getWritableDatabase(); 26 // 注意:该数据库连接属于 DaoMaster,所以多个 Session 指的是相同的数据库连接。 27 daoMaster = new DaoMaster(db); 28 daoSession = daoMaster.newSession(); 29 } 30 31 public DaoSession getDaoSession() { 32 return daoSession; 33 } 34 35 public SQLiteDatabase getDb() { 36 return db; 37 } 38 39 }
Activity具体实现
1 package com.castiel.dao; 2 3 import android.app.Activity; 4 import android.app.Dialog; 5 import android.database.sqlite.SQLiteDatabase; 6 import android.os.Bundle; 7 import android.text.TextUtils; 8 import android.view.LayoutInflater; 9 import android.view.View; 10 import android.widget.Button; 11 import android.widget.EditText; 12 import android.widget.ListView; 13 import android.widget.Toast; 14 15 import java.util.List; 16 17 import de.greenrobot.dao.query.Query; 18 import greendao.Student; 19 20 /** * Created by huangshuai on 2016/5/11. * Email:[email protected] * GreenDao增删改查实例 */ 21 public class CastielActivity extends Activity implements StudentAdapter.AdapterEnterCallBack{ 22 // 初始化组件 23 public static final String TAG = "WY"; 24 private ListlistStudent; 25 private ListView list; 26 private EditText etQureyName; 27 StudentAdapter studentAdapter; 28 private Button btnAdd,btnQurey; 29 @Override 30 public void onCreate(Bundle savedInstanceState) { 31 super.onCreate(savedInstanceState); 32 setContentView(R.layout.main_dao); 33 list = (ListView) findViewById(R.id.dao_list); 34 btnAdd = (Button) findViewById(R.id.btn_add); 35 btnQurey = (Button) findViewById(R.id.btn_query); 36 etQureyName = (EditText) findViewById(R.id.edit_query); 37 listStudent = getStudentDao().loadAll();// 查询全部数据操作 38 studentAdapter = new StudentAdapter(CastielActivity.this,listStudent); 39 40 list.setAdapter(studentAdapter); 41 studentAdapter.setCallback(this); 42 43 btnAdd.setOnClickListener(new View.OnClickListener() { 44 @Override 45 public void onClick(View v) { 46 dialogAdd(); 47 } 48 }); 49 50 btnQurey.setOnClickListener(new View.OnClickListener() { 51 @Override 52 public void onClick(View v) { 53 String curCondition = etQureyName.getText().toString().trim(); 54 if (TextUtils.isEmpty(curCondition)) { 55 Toast.makeText(CastielActivity.this,"查询条件不能为空",Toast.LENGTH_SHORT).show(); 56 } else { 57 // Query 类代表了一个可以被重复执行的查询 58 Query query = getStudentDao().queryBuilder() 59 .where(StudentDao.Properties.SName.eq(curCondition)) 60 .build(); 61 // 查询结果以 List 返回 62 List students = query.list(); 63 Toast.makeText(CastielActivity.this,"有" + students.size() + "个条件符合",Toast.LENGTH_SHORT).show(); 64 } 65 etQureyName.setText("");// 查询后重置条件 66 } 67 }); 68 } 69 70 /** * 通过 BaseApplication 类提供的 getDaoSession() 获取具体 Dao * @return */ 71 private StudentDao getStudentDao() { 72 return ((BaseApplication) this.getApplicationContext()).getDaoSession().getStudentDao(); 73 } 74 75 /** * 通过 BaseApplication 类提供的 getDb() 获取具体 db * @return */ 76 private SQLiteDatabase getDb() { 77 return ((BaseApplication) this.getApplicationContext()).getDb(); 78 } 79 80 /** * 添加操作弹窗 */ 81 protected void dialogAdd() { 82 final Dialog dataDialog = new Dialog(CastielActivity.this,R.style.myDialogTheme); 83 LayoutInflater curInfnfalater = LayoutInflater.from(this); 84 View view = curInfnfalater.inflate(R.layout.my_dialog, null); 85 Button b_ok,b_cancle; 86 final EditText etName,etSex,etClass,etAge; 87 etName = (EditText) view.findViewById(R.id.edit_name); 88 etSex = (EditText) view.findViewById(R.id.edit_sex); 89 etClass = (EditText) view.findViewById(R.id.edit_class); 90 etAge = (EditText) view.findViewById(R.id.edit_age); 91 92 93 b_ok = (Button) view.findViewById(R.id.btn_ok); 94 b_ok.setOnClickListener(new Button.OnClickListener() { 95 public void onClick(View v) { 96 Student ss = new Student(null,etName.getText().toString().trim(),etAge.getText().toString().trim(),etSex.getText().toString().trim(),etClass.getText().toString().trim()); 97 getStudentDao().insert(ss); 98 studentAdapter.addData(ss); 99 dataDialog.dismiss(); 100 } 101 }); 102 b_cancle = (Button) view.findViewById(R.id.btn_cancel); 103 b_cancle.setOnClickListener(new Button.OnClickListener() { 104 public void onClick(View v) { 105 dataDialog.dismiss(); 106 } 107 }); 108 109 110 dataDialog.setContentView(view); 111 dataDialog.show(); 112 } 113 114 /** * 修改操作弹窗 */ 115 protected void dialogModify(final Student curBean) { 116 final Dialog dataDialog = new Dialog(CastielActivity.this,R.style.myDialogTheme); 117 LayoutInflater curInfnfalater = LayoutInflater.from(this); 118 View view = curInfnfalater.inflate(R.layout.my_dialog, null); 119 Button b_ok,b_cancle; 120 final EditText etName,etSex,etClass,etAge; 121 etName = (EditText) view.findViewById(R.id.edit_name); 122 etSex = (EditText) view.findViewById(R.id.edit_sex); 123 etClass = (EditText) view.findViewById(R.id.edit_class); 124 etAge = (EditText) view.findViewById(R.id.edit_age); 125 etName.setText(curBean.getSName()); 126 etSex.setText(curBean.getSSex()); 127 etClass.setText(curBean.getSClass()); 128 etAge.setText(curBean.getSAge()); 129 130 b_ok = (Button) view.findViewById(R.id.btn_ok); 131 b_ok.setOnClickListener(new Button.OnClickListener() { 132 public void onClick(View v) { 133 Student ss = new Student(curBean.getId(),etName.getText().toString().trim(),etAge.getText().toString().trim(),etSex.getText().toString().trim(),etClass.getText().toString().trim()); 134 getStudentDao().deleteByKey(curBean.getId()); 135 getStudentDao().insert(ss); 136 studentAdapter.setData(getStudentDao().loadAll()); 137 dataDialog.dismiss(); 138 } 139 }); 140 b_cancle = (Button) view.findViewById(R.id.btn_cancel); 141 b_cancle.setOnClickListener(new Button.OnClickListener() { 142 public void onClick(View v) { 143 dataDialog.dismiss(); 144 } 145 }); 146 147 148 dataDialog.setContentView(view); 149 dataDialog.show(); 150 } 151 152 /**菜单弹窗 */ 153 protected void dialogMenu(final Student curBean) { 154 final Dialog dataDialog = new Dialog(CastielActivity.this,R.style.myDialogTheme); 155 LayoutInflater curInfnfalater = LayoutInflater.from(this); 156 View view = curInfnfalater.inflate(R.layout.item_dialog, null); 157 Button b_modify,b_del; 158 159 b_modify = (Button) view.findViewById(R.id.btn_modify); 160 b_modify.setOnClickListener(new Button.OnClickListener() { 161 public void onClick(View v) { 162 dialogModify(curBean); 163 dataDialog.dismiss(); 164 } 165 }); 166 b_del = (Button) view.findViewById(R.id.btn_del); 167 b_del.setOnClickListener(new Button.OnClickListener() { 168 public void onClick(View v) { 169 // 根据Id删除对应数据 170 getStudentDao().deleteByKey(curBean.getId()); 171 studentAdapter.setData(getStudentDao().loadAll()); 172 dataDialog.dismiss(); 173 } 174 }); 175 176 177 dataDialog.setContentView(view); 178 dataDialog.show(); 179 } 180 181 @Override 182 public void onEnterClick(Student bean) { 183 dialogMenu(bean); 184 } 185 }
列表相关Adapter
1 package com.castiel.dao; 2 3 import android.content.Context; 4 import android.view.LayoutInflater; 5 import android.view.View; 6 import android.view.ViewGroup; 7 import android.widget.BaseAdapter; 8 import android.widget.LinearLayout; 9 import android.widget.TextView; 10 11 import java.util.List; 12 13 import greendao.Student; 14 15 /** * Created by huangshuai on 2016/5/11. * Email:[email protected] * Student列表的Adapter */ 16 public class StudentAdapter extends BaseAdapter { 17 private AdapterEnterCallBack callback; 18 private LayoutInflater inflater; 19 private Listlist_student; 20 21 public StudentAdapter(Context context, List list_student) { 22 this.inflater = LayoutInflater.from(context); 23 this.list_student = list_student; 24 } 25 26 @Override 27 public int getCount() { 28 return list_student.size(); 29 } 30 31 @Override 32 public Object getItem(int position) { 33 return list_student.get(position); 34 } 35 36 @Override 37 public long getItemId(int position) { 38 return position; 39 } 40 41 @Override 42 public View getView(final int position, View convertView, ViewGroup parent) { 43 StudentViewHodler sv; 44 if (convertView == null) { 45 sv = new StudentViewHodler(); 46 convertView = inflater.inflate(R.layout.list_item, null); 47 sv.uAge = (TextView) convertView.findViewById(R.id.tv_age); 48 sv.uName = (TextView) convertView.findViewById(R.id.tv_name); 49 sv.uSex = (TextView) convertView.findViewById(R.id.tv_sex); 50 sv.uClass = (TextView) convertView.findViewById(R.id.tv_class); 51 sv.litem = (LinearLayout) convertView.findViewById(R.id.ll_item); 52 53 convertView.setTag(sv); 54 } else { 55 sv = (StudentViewHodler) convertView.getTag(); 56 } 57 58 sv.uSex.setText(list_student.get(position).getSSex()); 59 sv.uName.setText(list_student.get(position).getSName()); 60 sv.uAge.setText(list_student.get(position).getSAge()); 61 sv.uClass.setText(list_student.get(position).getSClass()); 62 sv.litem.setOnClickListener(new View.OnClickListener() { 63 @Override 64 public void onClick(View v) { 65 if (null != callback) { 66 callback.onEnterClick(list_student.get(position)); 67 } 68 } 69 }); 70 return convertView; 71 } 72 73 public void addData(Student data) { 74 if (data != null) { 75 this.list_student.add(data); 76 notifyDataSetChanged(); 77 } 78 } 79 80 public void setData(List data) { 81 if (data != null) { 82 list_student.clear(); 83 list_student.addAll(data); 84 notifyDataSetChanged(); 85 } 86 } 87 88 public class StudentViewHodler { 89 TextView uName; 90 TextView uSex; 91 TextView uAge; 92 TextView uClass; 93 LinearLayout litem; 94 } 95 96 public interface AdapterEnterCallBack { 97 void onEnterClick(Student bean); 98 } 99 100 public void setCallback(AdapterEnterCallBack callback) { 101 this.callback = callback; 102 } 103 104 }
布局文件实现
item_dialog.xml
1 23 4 5 6 7
list_item.xml
1 23 4 5 6 7 8 9 10 11 12
main_dao.xml
1 23 4 5 6 7 8 9 10 12 1311 14 15 24 25 2616 17 18 19 20 21 22 23 27
my_dialog.xml
1 23 4 5 6 41 427 8 22 239 10 14 1511 12 13 16 17 2118 19 20 24 25 39 4026 27 31 3228 29 30 33 34 3835 36 37 43 44 45 46 47 48
运行程序,执行增删改查
项目源码链接:http://download.csdn.net/detail/mynameishuangshuai/9518322
参考链接:http://itangqi.me/2015/07/26/orm-greendao-summary/
via: http://blog.csdn.net/mynameishuangshuai/article/details/51386402