首先看一下效果圖:
項目結構如下圖所示:
第一步:在build中添加配置如下:
projet 目錄下的build.gradle
dependencies {
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.0'
}
moudle 下的build.gradle添加如下內容:
apply plugin: 'org.greenrobot.greendao'
dependencies {
.....................
compile 'org.greenrobot:greendao:3.2.0'
}
添加完成之后點擊sync一下工程
第二步:
首先在moudle下 build.gradle的根目錄下添加如下配置
greendao {
//數據庫的schema版本,也可以理解為數據庫版本號
schemaVersion 1
//設置DaoMaster、DaoSession、Dao包名,也就是要放置這些類的包的全路徑。
daoPackage 'com.koimy.greedaotest.dao'
//設置DaoMaster、DaoSession、Dao目錄
targetGenDir 'src/main/java'
}
在項目里面添加實體類Student如下所示:
@Entity
public class Student {
@Id
private Long id;
private String name;
private int age;
private String num;
}
此時項目目錄如下所示:
然后點擊 android studio 的 build-->make project
此時項目結構如下:
其中dao目錄下的文件是由greendao自動生成的,Student 類里面的內容發生了編號如下:
/**
* Created by hp on 2018/1/23.
*/
@Entity
public class Student {
@Id
private Long id;
private String name;
private int age;
private String num;
@Generated(hash = 1538557423)
public Student(Long id, String name, int age, String num) {
this.id = id;
this.name = name;
this.age = age;
this.num = num;
}
@Generated(hash = 1556870573)
public Student() {
}
public Long getId() {
return this.id;
}
public void setId(Long id) {
this.id = id;
}
public String getName() {
return this.name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return this.age;
}
public void setAge(int age) {
this.age = age;
}
public String getNum() {
return this.num;
}
public void setNum(String num) {
this.num = num;
}
GreenDao幫助我們自動生成了一些get和set方法,以及構造方法
第三步:為了方便使用我們添加了一個 db包
DbManager類如下:
package com.koimy.greedaotest.db;
/**
* Created by hp on 2018/1/23.
*/
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import com.koimy.greedaotest.dao.DaoMaster;
import com.koimy.greedaotest.dao.DaoSession;
public class DbManager {
// 是否加密
public static final boolean ENCRYPTED = true;
private static final String DB_NAME = "test.db";
private static DbManager mDbManager;
private static DaoMaster.DevOpenHelper mDevOpenHelper;
private static DaoMaster mDaoMaster;
private static DaoSession mDaoSession;
private Context mContext;
private DbManager(Context context) {
this.mContext = context;
// 初始化數據庫信息
mDevOpenHelper = new DaoMaster.DevOpenHelper(context, DB_NAME);
getDaoMaster(context);
getDaoSession(context);
}
public static DbManager getInstance(Context context) {
if (null == mDbManager) {
synchronized (DbManager.class) {
if (null == mDbManager) {
mDbManager = new DbManager(context);
}
}
}
return mDbManager;
}
/**
* 獲取可讀數據庫
*
* @param context
* @return
*/
public static SQLiteDatabase getReadableDatabase(Context context) {
if (null == mDevOpenHelper) {
getInstance(context);
}
return mDevOpenHelper.getReadableDatabase();
}
/**
* 獲取可寫數據庫
*
* @param context
* @return
*/
public static SQLiteDatabase getWritableDatabase(Context context) {
if (null == mDevOpenHelper) {
getInstance(context);
}
return mDevOpenHelper.getWritableDatabase();
}
/**
* 獲取DaoMaster
*
* @param context
* @return
*/
public static DaoMaster getDaoMaster(Context context) {
if (null == mDaoMaster) {
synchronized (DbManager.class) {
if (null == mDaoMaster) {
mDaoMaster = new DaoMaster(getWritableDatabase(context));
}
}
}
return mDaoMaster;
}
// /**
// * 獲取DaoMaster
// *
// * 判斷是否存在數據庫,如果沒有則創建數據庫
// * @param context
// * @return
// */
// public static DaoMaster getDaoMaster(Context context) {
// if (null == mDaoMaster) {
// synchronized (DbManager.class) {
// if (null == mDaoMaster) {
// MyOpenHelper helper = new MyOpenHelper(context,DB_NAME,null);
// mDaoMaster = new DaoMaster(helper.getWritableDatabase());
// }
// }
// }
// return mDaoMaster;
// }
/**
* 獲取DaoSession
*
* @param context
* @return
*/
public static DaoSession getDaoSession(Context context) {
if (null == mDaoSession) {
synchronized (DbManager.class) {
mDaoSession = getDaoMaster(context).newSession();
}
}
return mDaoSession;
}
}
SutdentDaoOpe類如下:
package com.koimy.greedaotest.db;
/**
* Created by hp on 2018/1/23.
*/
import android.content.Context;
import com.koimy.greedaotest.dao.StudentDao;
import com.koimy.greedaotest.entity.Student;
import org.greenrobot.greendao.query.QueryBuilder;
import java.util.List;
public class StudentDaoOpe {
/**
* 添加數據至數據庫
*
* @param context
* @param stu
*/
public static void insertData(Context context, Student stu) {
DbManager.getDaoSession(context).getStudentDao().insert(stu);
}
/**
* 將數據實體通過事務添加至數據庫
*
* @param context
* @param list
*/
public static void insertData(Context context, List<Student> list) {
if (null == list || list.size() <= 0) {
return;
}
DbManager.getDaoSession(context).getStudentDao().insertInTx(list);
}
/**
* 添加數據至數據庫,如果存在,將原來的數據覆蓋
* 內部代碼判斷了如果存在就update(entity);不存在就insert(entity);
*
* @param context
* @param student
*/
public static void saveData(Context context, Student student) {
DbManager.getDaoSession(context).getStudentDao().save(student);
}
/**
* 刪除數據至數據庫
*
* @param context
* @param student 刪除具體內容
*/
public static void deleteData(Context context, Student student) {
DbManager.getDaoSession(context).getStudentDao().delete(student);
}
/**
* 根據id刪除數據至數據庫
*
* @param context
* @param id 刪除具體內容
*/
public static void deleteByKeyData(Context context, long id) {
DbManager.getDaoSession(context).getStudentDao().deleteByKey(id);
}
/**
* 刪除全部數據
*
* @param context
*/
public static void deleteAllData(Context context) {
DbManager.getDaoSession(context).getStudentDao().deleteAll();
}
/**
* 更新數據庫
*
* @param context
* @param student
*/
public static void updateData(Context context, Student student) {
DbManager.getDaoSession(context).getStudentDao().update(student);
}
/**
* 查詢所有數據
*
* @param context
* @return
*/
public static List<Student> queryAll(Context context) {
QueryBuilder<Student> builder = DbManager.getDaoSession(context).getStudentDao().queryBuilder();
return builder.build().list();
}
/**
* 分頁加載
* @param context
* @param pageSize 當前第幾頁(程序中動態修改pageSize的值即可)
* @param pageNum 每頁顯示多少個
* @return
*/
public static List<Student> queryPaging( int pageSize, int pageNum,Context context){
StudentDao studentDao = DbManager.getDaoSession(context).getStudentDao();
List<Student> listMsg = studentDao.queryBuilder()
.offset(pageSize * pageNum).limit(pageNum).list();
return listMsg;
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.koimy.demo2.MainActivity">
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="增" />
<Button
android:id="@+id/button2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="刪" />
<Button
android:id="@+id/button3"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="改" />
<Button
android:id="@+id/button4"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="查" />
<LinearLayout
android:layout_marginTop="20dp"
android:gravity="center"
android:layout_gravity="center_vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<Button
android:id="@+id/btn_query_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="根據ID查詢(分頁查詢)" />
<Button
android:id="@+id/button5"
android:layout_width="107dp"
android:layout_height="wrap_content"
android:text="刪除全部" />
</LinearLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/tv_content"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</ScrollView>
</LinearLayout>
MainActivithy.java
package com.koimy.greedaotest;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;
import com.koimy.greedaotest.db.StudentDaoOpe;
import com.koimy.greedaotest.entity.Student;
import java.util.ArrayList;
import java.util.List;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;
public class MainActivity extends AppCompatActivity {
@BindView(R.id.button)
Button button;
@BindView(R.id.button2)
Button button2;
@BindView(R.id.button3)
Button button3;
@BindView(R.id.button4)
Button button4;
@BindView(R.id.btn_query_all)
Button btnQueryAll;
@BindView(R.id.button5)
Button button5;
@BindView(R.id.tv_content)
TextView tvContent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
initData();
}
private List<Student> studentList = new ArrayList<>();
/**
* 初始化數據
*/
private void initData() {
for (int i = 0; i < 100; i++) {
Student student = new Student((long) i, "huang" + i, 25,"666"+i);
studentList.add(student);
}
}
int page;
@OnClick({R.id.button, R.id.button2, R.id.button3, R.id.button4, R.id.button5, R.id.btn_query_all})
public void onViewClicked(View view) {
switch (view.getId()) {
case R.id.button:
StudentDaoOpe.insertData(this, studentList);
break;
case R.id.button2:
Student student = new Student((long) 5, "haung" + 5, 25,"123456");
/**
* 根據特定的對象刪除
*/
StudentDaoOpe.deleteData(this, student);
/**
* 根據主鍵刪除
*/
StudentDaoOpe.deleteByKeyData(this, 7);
StudentDaoOpe.deleteAllData(this);
break;
case R.id.button3:
student = new Student((long) 2, "caojin", 1314,"888888");
StudentDaoOpe.updateData(this, student);
break;
case R.id.button4:
List<Student> students = StudentDaoOpe.queryAll(this);
tvContent.setText(students.toString());
for (int i = 0; i < students.size(); i++) {
Log.i("Log", students.get(i).getName());
}
break;
case R.id.button5:
StudentDaoOpe.deleteAllData(this);
break;
case R.id.btn_query_all:
List<Student> students2 = StudentDaoOpe.queryPaging(page, 20, this);
if (students2.size() == 0) {
Toast.makeText(this, "沒有更多數據了", Toast.LENGTH_SHORT).show();
}
for (Student st : students2) {
Log.e("TAG", "onViewClicked: ==" + st);
Log.e("TAG", "onViewClicked: == num = " + st.getNum());
}
page++;
tvContent.setText(students2.toString());
break;
}
}
}
最終在/data/data/包名/databases/數據庫名/表名 生成的表結構如下所示:
下面講一下數據庫的升級:
首先新建一個helper包引入兩個類,內容如下:
MigrationHelper類:
package com.koimy.greedaotest.helper;
/**
* 數據庫更新輔助類
*
* 原理:創建臨時表-->刪除原表-->創建新表-->復制臨時表數據到新表並刪除臨時表;這樣數據庫表的更新就完成了
*/
import android.database.Cursor;
import android.text.TextUtils;
import android.util.Log;
import com.koimy.greedaotest.dao.DaoMaster;
import org.greenrobot.greendao.AbstractDao;
import org.greenrobot.greendao.database.Database;
import org.greenrobot.greendao.internal.DaoConfig;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class MigrationHelper {
private static final String CONVERSION_CLASS_NOT_FOUND_EXCEPTION = "MIGRATION HELPER - CLASS DOESN'T MATCH WITH THE CURRENT PARAMETERS";
private static MigrationHelper instance;
public static MigrationHelper getInstance() {
if (instance == null) {
instance = new MigrationHelper();
}
return instance;
}
public void migrate(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
generateTempTables(db, daoClasses);
DaoMaster.dropAllTables(db, true);
DaoMaster.createAllTables(db, false);
restoreData(db, daoClasses);
}
/**
* 生成臨時列表
*
* @param db
* @param daoClasses
*/
private void generateTempTables(Database db, Class<? extends AbstractDao<?, ?>>... daoClasses) {
for (int i = 0; i < daoClasses.length; i++) {
DaoConfig daoConfig = new DaoConfig(db, daoClasses[i]);
String divider = "";
String tableName = daoConfig.tablename;
String tempTableName = daoConfig.tablename.concat("_TEMP");
ArrayList<String> properties = new ArrayList<>();
StringBuilder createTableStringBuilder = new StringBuilder();
createTableStringBuilder.append("CREATE TABLE ").append(tempTableName).append(" (");
for (int j = 0; j < daoConfig.properties.length; j++) {
String columnName = daoConfig.properties[j].columnName;
if (getColumns(db, tableName).contains(columnName)) {
properties.add(columnName);
String type = null;
try {
type = getTypeByClass(daoConfig.properties[j].type);
} catch (Exception exception) {
exception.printStackTrace();
}
createTableStringBuilder.append(divider).append(columnName).append(" ").append(type);
if (daoConfig.properties[j].primaryKey) {
createTableStringBuilder.append(" PRIMARY KEY");
}
divider = ",";
}
}
createTableStringBuilder.append(");");
db.execSQL(createTableStringBuilder.toString());
StringBuilder insertTableStringBuilder = new StringBuilder();
insertTableStringBuilder.append("INSERT INTO ").append(tempTableName).append(" (");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(") SELECT ");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(" FROM ").append(tableName).append(";");
db.execSQL(insertTableStringBuilder.toString());
}
}
/**
* 存儲新的數據庫表 以及數據
*
* @param db
* @param daoClasses
*/
private 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");
ArrayList<String> properties = new ArrayList();
for (int j = 0; j < daoConfig.properties.length; j++) {
String columnName = daoConfig.properties[j].columnName;
if (getColumns(db, tempTableName).contains(columnName)) {
properties.add(columnName);
}
}
StringBuilder insertTableStringBuilder = new StringBuilder();
insertTableStringBuilder.append("INSERT INTO ").append(tableName).append(" (");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(") SELECT ");
insertTableStringBuilder.append(TextUtils.join(",", properties));
insertTableStringBuilder.append(" FROM ").append(tempTableName).append(";");
StringBuilder dropTableStringBuilder = new StringBuilder();
dropTableStringBuilder.append("DROP TABLE ").append(tempTableName);
db.execSQL(insertTableStringBuilder.toString());
db.execSQL(dropTableStringBuilder.toString());
}
}
private String getTypeByClass(Class<?> type) throws Exception {
if (type.equals(String.class)) {
return "TEXT";
}
if (type.equals(Long.class) || type.equals(Integer.class) || type.equals(long.class)) {
return "INTEGER";
}
if (type.equals(Boolean.class)) {
return "BOOLEAN";
}
Exception exception = new Exception(CONVERSION_CLASS_NOT_FOUND_EXCEPTION.concat(" - Class: ").concat(type.toString()));
exception.printStackTrace();
throw exception;
}
private List<String> getColumns(Database db, String tableName) {
List<String> columns = new ArrayList<>();
Cursor cursor = null;
try {
cursor = db.rawQuery("SELECT * FROM " + tableName + " limit 1", null);
if (cursor != null) {
columns = new ArrayList<>(Arrays.asList(cursor.getColumnNames()));
}
} catch (Exception e) {
Log.v(tableName, e.getMessage(), e);
e.printStackTrace();
} finally {
if (cursor != null)
cursor.close();
}
return columns;
}
}
MyOpenHelper類:
package com.koimy.greedaotest.helper;
/**
* Created by hp on 2018/1/23.
*/
import android.content.Context;
import android.database.sqlite.SQLiteDatabase;
import android.util.Log;
import com.koimy.greedaotest.dao.DaoMaster;
import com.koimy.greedaotest.dao.StudentDao;
import org.greenrobot.greendao.database.Database;
public class MyOpenHelper extends DaoMaster.OpenHelper {
public MyOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}
/**
* 數據庫升級
* @param db
* @param oldVersion
* @param newVersion
*/
@Override
public void onUpgrade(Database db, int oldVersion, int newVersion) {
//操作數據庫的更新 有幾個表升級都可以傳入到下面
Log.i("version", oldVersion + "---先前和更新之后的版本---" + newVersion);
if (oldVersion < newVersion) {
Log.i("version", oldVersion + "---先前和更新之后的版本---" + newVersion);
MigrationHelper.getInstance().migrate(db, StudentDao.class);
//更改過的實體類(新增的不用加) 更新UserDao文件 可以添加多個 XXDao.class 文件
// MigrationHelper.getInstance().migrate(db, UserDao.class,XXDao.class);
}
//MigrationHelper.getInstance().migrate(db,StudentDao.class);
}
}
然后將
/**
* 獲取DaoMaster
*
* @param context
* @return
*/
public static DaoMaster getDaoMaster(Context context) {
if (null == mDaoMaster) {
synchronized (DbManager.class) {
if (null == mDaoMaster) {
mDaoMaster = new DaoMaster(getWritableDatabase(context));
}
}
}
return mDaoMaster;
}
換成如下所示:
/**
* 獲取DaoMaster
*
* 判斷是否存在數據庫,如果沒有則創建數據庫
* @param context
* @return
*/
public static DaoMaster getDaoMaster(Context context) {
if (null == mDaoMaster) {
synchronized (DbManager.class) {
if (null == mDaoMaster) {
MyOpenHelper helper = new MyOpenHelper(context,DB_NAME,null);
mDaoMaster = new DaoMaster(helper.getWritableDatabase());
}
}
}
return mDaoMaster;
}
接下來:我們在Student類里面添加一個 屬性 grade屬性,然后將build.gradle里面schemaVersion改為 2
然后編譯,運行一下程序,然后我們再來看升級后的數據庫,如下圖所示成功添加了我么新增的字段,還保留了以前的數據