别问为啥,就是任性,想学习下GreenDao的使用。。。。。。。
简单粗暴,先看下效果:(增删改查全都有)
(小提示:运行Demo的时候,请填写正确类型,eg不要在填写age时候的填写中文等,避免程序崩溃(因为是demo,仅供参考,可能没有做太全面的防护,请理解))
GreenDao 介绍:
greenDAO是一个对象关系映射(ORM)的框架,能够提供一个接口通过操作对象的方式去操作关系型数据库,它能够让你操作数据库时更简单、更方便。如下图所示:
官网地址:http://greenrobot.org/greendao/
Github地址:https://github.com/greenrobot/greenDAO
GreenDao 优点:
1.性能高,号称Android最快的关系型数据库
2.内存占用小
3.库文件比较小,小于100K,编译时间低,而且可以避免65K方法限制
4.支持数据库加密 greendao支持SQLCipher进行数据库加密 有关SQLCipher可以参考这篇博客Android数据存储之SQLCipher数据库加密
5.简洁易用的API
GreenDao使用前准备工作:
首先在project的gradle文件中引入greenDAO插件,引入之后如下:
buildscript { repositories { google() jcenter() } dependencies { classpath 'com.android.tools.build:gradle:3.1.0' classpath 'org.greenrobot:greendao-gradle-plugin:3.2.1' } }
然后在module的gradle文件中添加greenDAO的插件,并引入相关类库,修改之后如下:
apply plugin: 'com.android.application' android { compileSdkVersion 26 defaultConfig { ...... } buildTypes { ...... } apply plugin: 'org.greenrobot.greendao' } dependencies { ... implementation 'org.greenrobot:greendao:3.2.0' implementation 'org.greenrobot:greendao-generator:3.2.0' ..... } greendao { /** * 数据库版本 */ schemaVersion 1 /** * greenDao输出到Dao数据库实体操作类文件目录 */ daoPackage 'greendao' /** * GreenDao实体类dao文件目录 */ targetGenDir 'src/main/java' }
schemaVersion: 数据库schema版本,也可以理解为数据库版本号
daoPackage:设置DaoMaster、DaoSession、Dao包名
targetGenDir:设置DaoMaster、DaoSession、Dao目录
targetGenDirTest:设置生成单元测试目录
generateTests:设置自动生成单元测试用例
GreenDao3.2的使用步骤:
1.创建实体类(GreenDao的出现就是操作对象的方式操作数据库)
数据库引入成功后,在使用之前,我们还得先来创建一个实体类:
在实体类 上方 写 上 @Entity 即可!
/** * Created by zhangqun on 18-4-8. */ @Entity public class Student { @Id private Long id;// private String name; private String sex; private int age; private float score; private boolean isSelected; @Generated(hash = 66442372) public Student(Long id, String name, String sex, int age, float score, boolean isSelected) { this.id = id; this.name = name; this.sex = sex; this.age = age; this.score = score; this.isSelected = isSelected; } }而且不需要写set get 方法。他自动帮我们生成.. 是不是很牛逼哦?
然后运行项目即可!
对了,这里重点强调下:Long id(用于自增的主键key id必须是Long 而不是long,如果写错的话,对数据库的操作会因此报错)。
工程目录如下图:顺便补充下注解的知识,大致看下,可抽时间专门研究下:
1.)实体@Entity注解
schema:告知GreenDao当前实体属于哪个schema
active:标记一个实体处于活动状态,活动实体有更新、删除和刷新方法
nameInDb:在数据中使用的别名,默认使用的是实体的类名
indexes:定义索引,可以跨越多个列
createInDb:标记创建数据库表**
2.)基础属性注解
@Id :主键 Long型,可以通过@Id(autoincrement = true)设置自增长
@Property:设置一个非默认关系映射所对应的列名,默认是的使用字段名举例:@Property (nameInDb="name")
@NotNul:设置数据库表当前列不能为空
@Transient:添加次标记之后不会生成数据库表的列
3.)索引注解
@Index:使用@Index作为一个属性来创建一个索引,通过name设置索引别名,也可以通过unique给索引添加约束
@Unique:向数据库列添加了一个唯一的约束
4.)关系注解
@ToOne:定义与另一个实体(一个实体对象)的关系
@ToMany:定义与多个实体对象的关系
(一) @Entity 定义实体
@nameInDb 在数据库中的名字,如不写则为实体中类名
@indexes 索引
@createInDb 是否创建表,默认为true,false时不创建
@schema 指定架构名称为实体
@active 无论是更新生成都刷新
(二) @Id
(三) @NotNull 不为null
(四) @Unique 唯一约束
(五) @ToMany 一对多
(六) @OrderBy 排序
(七) @ToOne 一对一
(八) @Transient 不存储在数据库中
(九) @generated 由greendao产生的构造函数或方法
2.GreenDao的初始化(别瞎搞,最好就放在Application中)
/** * Created by zhangqun on 18-4-8. */ public class MyApplication extends Application { private static MyApplication application; private DaoMaster.DevOpenHelper mHelper; private SQLiteDatabase db; private DaoMaster mDaoMaster; private DaoSession mDaoSession; @Override public void onCreate() { super.onCreate(); application = this; setDatabase(); } public static MyApplication getApplication() { return application; } /** * 设置greenDao */ private void setDatabase() { // 通过DaoMaster 的内部类 DevOpenHelper,你可以得到一个便利的SQLiteOpenHelper 对象。 // 可能你已经注意到了,你并不需要去编写「CREATE TABLE」这样的 SQL 语句,因为greenDAO 已经帮你做了。 // 注意:默认的DaoMaster.DevOpenHelper 会在数据库升级时,删除所有的表,意味着这将导致数据的丢失。 // 所以,在正式的项目中,你还应该做一层封装,来实现数据库的安全升级。 mHelper = new DaoMaster.DevOpenHelper(this, "student-db", null); db = mHelper.getWritableDatabase(); // 注意:该数据库连接属于DaoMaster,所以多个 Session 指的是相同的数据库连接。 mDaoMaster = new DaoMaster(db); mDaoSession = mDaoMaster.newSession(); } public DaoSession getDaoSession() { return mDaoSession; } public SQLiteDatabase getDb() { return db; } }
3.GreenDao的增删改查操作
另外呢,我暂时把GreenDao的初始化以及增删改查操作我封装到一个工具类中,如下:/** * Created by zhangqun on 18-4-8. */ public class GreenDaoManager { private static final String TAG = "GreenDaoManager"; private static GreenDaoManager instance; private StudentDao dao; public static GreenDaoManager getInstance() { if (instance == null) { synchronized (GreenDaoManager.class) { if (instance == null) { instance = new GreenDaoManager(); } } } return instance; } private GreenDaoManager() { dao = MyApplication.getApplication().getDaoSession().getStudentDao(); } /** * 增加数据 * * @param student * @return */ long insertData(Student student) { Log.d(TAG,"insert===>"+student); return dao.insert(student); } /** * 删除数据 * * @param id keyId */ public void deleteData(Long id) { Log.d(TAG,"delete===>id"+id); dao.deleteByKey(id); } /** * 更改数据 */ public void updateData(Student student) { Log.d(TAG,"update===>"+student); dao.update(student); } /** * 查寻所有数据 */ public List<Student> queryAllData() { return dao.loadAll(); } }顺便贴上MainActivity的代码:
public class MainActivity extends AppCompatActivity implements View.OnClickListener { private static final String TAG = "MainActivity"; private GreenDaoManager manager; private EditText etName; private EditText etSex; private EditText etAge; private EditText etScore; private Button btnInsert; private Button btnDelete; private Button btnUpdate; private Button btnQuery; private List<Student> list = new ArrayList<>(); private MyAdapter myAdapter; //用于更新界面数据 private int currentPosition = -1; //用于更新数据库数据 private long keyId = -1; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); initData(); initViews(); initListeners(); } private void initData() { manager = GreenDaoManager.getInstance(); } private void initViews() { etName = findViewById(R.id.et_name); etSex = findViewById(R.id.et_sex); etAge = findViewById(R.id.et_age); etScore = findViewById(R.id.et_score); btnInsert = findViewById(R.id.btn_insert); btnDelete = findViewById(R.id.btn_delete); btnUpdate = findViewById(R.id.btn_update); btnQuery = findViewById(R.id.btn_query); initRecyclerView(); } private void initRecyclerView() { RecyclerView recyclerView = findViewById(R.id.rv_show); LinearLayoutManager mLayoutManager = new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false); recyclerView.setLayoutManager(mLayoutManager); recyclerView.setHasFixedSize(true); myAdapter = new MyAdapter(list); myAdapter.setListener(new MyAdapter.onClickListener() { @Override public void clickItem(int position) { currentPosition = position; //选中的数据进行回显,并设置高亮显示 Student student = list.get(position); keyId = student.getId(); Log.d(TAG, "click the item::" + student); etName.setText(student.getName()); etSex.setText(student.getSex()); etAge.setText(student.getAge() + ""); etScore.setText(student.getScore() + ""); setSelected(position); } }); recyclerView.setAdapter(myAdapter); } private void initListeners() { btnInsert.setOnClickListener(this); btnDelete.setOnClickListener(this); btnUpdate.setOnClickListener(this); btnQuery.setOnClickListener(this); } @Override public void onClick(View v) { int age = 0; float score = (float) 0.0; String name = etName.getText().toString().trim(); String sex = etSex.getText().toString().trim(); String ageStr = etAge.getText().toString().trim(); String scoreStr = etScore.getText().toString().trim(); if (!TextUtils.isEmpty(ageStr)) { age = Integer.parseInt(ageStr); } if (!TextUtils.isEmpty(scoreStr)) { score = Float.parseFloat(scoreStr); } switch (v.getId()) { case R.id.btn_insert: if (TextUtils.isEmpty(name) && TextUtils.isEmpty(sex) && TextUtils.isEmpty(ageStr) && TextUtils.isEmpty(scoreStr)) { Toast.makeText(MainActivity.this, "the data can not be null!", Toast.LENGTH_SHORT).show(); return; } Student insertData = new Student(null, name, sex, age, score); long rowId = manager.insertData(insertData); Log.d(TAG, "insert rowId::" + rowId); if (rowId >= 0) {//插入成功,记录主键id list.add(insertData); List<Student> allData = manager.queryAllData(); Log.d(TAG, "000000insert::" + allData); } else { Log.e(TAG, "inset error"); } myAdapter.notifyDataSetChanged(); break; case R.id.btn_delete: if (currentPosition == -1) { showToast("请选择待删除项目"); return; } if (keyId == -1) { showToast("数据库中没有可供删除的数据"); return; } manager.deleteData(Long.valueOf(keyId)); list.remove(currentPosition); currentPosition = -1; myAdapter.notifyDataSetChanged(); break; case R.id.btn_update: if (currentPosition == -1) { showToast("请选择待更新项目"); return; } if (keyId == -1) { showToast("数据库中没有可供更新的数据"); return; } if (TextUtils.isEmpty(name) && TextUtils.isEmpty(sex) && TextUtils.isEmpty(ageStr) && TextUtils.isEmpty(scoreStr)) { showToast("待更新的数据不能为空"); return; } Student updateData = list.get(currentPosition); updateData.setName(name); updateData.setSex(sex); updateData.setAge(age); updateData.setScore(score); manager.updateData(updateData); list.set(currentPosition, updateData); myAdapter.notifyDataSetChanged(); break; case R.id.btn_query: if (!list.isEmpty()) { list.clear(); } List<Student> allData = manager.queryAllData(); Log.d(TAG, "query all data::" + allData); list.addAll(allData); myAdapter.notifyDataSetChanged(); break; default: break; } initEdit(); List<Student> allData = manager.queryAllData(); Log.d(TAG, "操作后的当前数据库数据" + allData); } @Override protected void onDestroy() { super.onDestroy(); currentPosition = -1; keyId = -1; for (Student student : list) { student.setSelected(false); } } /** * 设置选中的item,高亮显示 * * @param position */ private void setSelected(int position) { for (Student student : list) { student.setSelected(false); } list.get(position).setSelected(true); myAdapter.notifyDataSetChanged(); } //弹出toast private void showToast(String str) { Toast.makeText(MainActivity.this, str, Toast.LENGTH_SHORT).show(); } //初始化編輯框 private void initEdit() { etName.setText(""); etSex.setText(""); etAge.setText(""); etScore.setText(""); } }OK,主要的代码上面都已经贴出来了。
这是本人的第一篇博客,没啥经验,可能排版啥的还不够麻溜,相信以后会好起来的。
好了,有啥问题就留言吧,相互学习进步才是正道。
另外,关于GreenDao3.2数据库的升级,后续会专门写一篇博客。
源码下载:
https://download.csdn.net/download/zhangqunshuai/10409831
参考:
史上最牛逼的Android数据库 GreenDao3.1 详细使用教程(小白容易上手)
玩转Android之数据库框架greenDAO3.0使用指南