项目中用到本地数据库存储数据,数据量以及类型比较多而且繁杂,于是乎,就用GreenDao插件来存储了。
先说一下配置情况:
1、工程build.gradle中添加如下:
说明:dependencies节点下添加
classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2'
说明:顶部最外层添加:
apply plugin: 'org.greenrobot.greendao'
android节点下添加:
greendao {
schemaVersion 1//数据库版本号,数据库升级会用到,如果不需要升级,一直为1就好
daoPackage 'com.thtj.demo.dao'//DaoMaster、DaoSession以及各种实体Dao的生成路径
targetGenDir 'src/main/java'
}
dependencies节点下添加:
compile 'org.greenrobot:greendao:3.2.2'
最后Aysnc一下就算完成了。
3、创建实体类表,比如:
import org.greenrobot.greendao.annotation.Entity;
import org.greenrobot.greendao.annotation.Id;
import org.greenrobot.greendao.annotation.Unique;
import org.greenrobot.greendao.annotation.Generated;
@Entity
public class Person {
@Id
private Long id;
@Unique
private String name;
private int age;
private String sex;
private int salary;
@Generated(hash = 72938267)
public Person(Long id, String name, int age, String sex, int salary) {
this.id = id;
this.name = name;
this.age = age;
this.sex = sex;
this.salary = salary;
}
@Generated(hash = 1024547259)
public Person() {
}
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 getSex() {
return this.sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public int getSalary() {
return this.salary;
}
public void setSalary(int salary) {
this.salary = salary;
}
}
声明完属性以后,rebuild一下工程,会自动生成上面的那些get、set等方法,对应的dao包路径下也会生成相应的Dao文件。这些都不需要手动添加,全是rebuild工程之后自动生成的,而且不建议修改。你只需要声明属性(也就是表中的字段)就好。
4、创建MyApplication:
public class MyApplication extends Application {
private MySQLiteOpenHelper mHelper;
public static MyApplication instance;
@Override
public void onCreate() {
super.onCreate();
instance = this;
setDatabase();
}
public static MyApplication getInstances() {
return instance;
}
private void setDatabase() {
// 注意:默认的 DaoMaster.DevOpenHelper 会在数据库升级时,删除所有的表,意味着这将导致数据的丢失。
// 在正式的项目中,还应该做一层封装,来实现数据库的安全升级。
mHelper = new MySQLiteOpenHelper(this, "notes-db", null);
}
public DaoSession getDaoSession() {
return new DaoMaster(mHelper.getWritableDatabase()).newSession();
}
}
里面有这么一句话:“在正式的项目中,还应该做一层封装,来实现数据库的安全升级”。网上的很多Demo是未封装的。如果你的数据库不需要升级的话,可以直接使用,但是如果你的数据库需要升级的话,显然就不可取了。
因为数据库版本升级的话,会默认先删除所有的表,再重新创建,意味着如果用户之前数据库里已经保存了数据,你这样不作处理,直接修改为schemaVersion2然后打包给用户安装的话,会导致用户之前手机数据库里存的数据全部丢失。下面DaoMater里那两行代码也意味着:删除、重建。
所以在升级的时候需要对用户已经保存的数据进行一下处理。
借助于:
compile 'com.github.yuweiguocn:GreenDaoUpgradeHelper:v2.0.1'
工程build.gradle中allprojects节点下的repositories下添加
maven { url "https://jitpack.io" }
github上搜一下就行,当然网上也有很多使用教程。
compile完成之后,创建一个MySQLiteOpenHelper,也就是上面MyApplication中用到的。
public class MySQLiteOpenHelper extends DaoMaster.OpenHelper {
public MySQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
super(context, name, factory);
}
@Override
public void onUpgrade(Database db, int oldVersion, int newVersion) {
MigrationHelper.migrate(db, new MigrationHelper.ReCreateAllTableListener() {
@Override
public void onCreateAllTables(Database db, boolean ifNotExists) {
DaoMaster.createAllTables(db, ifNotExists);
}
@Override
public void onDropAllTables(Database db, boolean ifExists) {
DaoMaster.dropAllTables(db, ifExists);
}
}, PersonDao.class);
}
}
重写了升级里面的方法,这样就保证了即使数据库添加字段升级了,数据也不会丢失。
上面的PersonDao就是Person这个表新增字段有改动的dao,可以添加多个,比如:
PersonDao.class,MoneyDao.class...
然后就可以使用了,Demo如下:
public class MainActivity extends Activity {
private TextView tv;
private String s = "";
private PersonDao dao = MyApplication.getInstances().getDaoSession().getPersonDao();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv = findViewById(R.id.tv);
List personList = dao.loadAll();
if (personList.size() == 0) {
for (int i = 0; i < 2; i++) {
Person p = new Person();
p.setName("挨踢" + i);
p.setAge(i);
p.setSex("男");
dao.insertOrReplace(p);
}
queryData();
} else {
queryData();
}
tv.setText(s.substring(0, s.length() - 1));
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Person p = dao.queryBuilder()
.where(PersonDao.Properties.Name.eq("挨踢0")).unique();
if (p != null) {
p.setSex("女");
dao.insertOrReplace(p);
// dao.update(p);//也可以这样,检测到存在都会更新
}
queryData();
tv.setText(s.substring(0, s.length() - 1));
}
});
}
public void queryData(){
s = "";
List pl = dao.loadAll();
if (pl != null && pl.size() > 0) {
for (Person p : pl) {
s += new GsonBuilder().serializeNulls().create().toJson(p) + ",";
}
}
}
}
插入一条数据常用方法:insert或者insertOrReplace,后者也起到了更新的功能,跟update功能一样,只不过在数据库里的顺序会改变,直接update更新的话,顺序不会改变。关于查询和删除的方法就不多说了,网上很多。
flutter借助插件sqflite: ^1.1.6+3来实现。
以模拟创建简单的用户表为例:
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';
final String tableName = "user"; //表名
final String columnId = "id"; //主键
final String columnUserId = "userId"; //用户唯一标识
final String columnName = "name"; //用户名
final String columnAge = "age"; //年龄
final String columnSex = "sex"; //version:2 新增的性别字段
class User {
int id;
int userId;
String name;
int age;
String sex; //version:2 新增的性别字段
User();
Map toMap() {
return {
columnId: id,
columnUserId: userId,
columnName: name,
columnAge: age,
columnSex: sex, //version:2 新增的性别字段
};
}
User.fromMap(Map map) {
id = map[columnId];
userId = map[columnUserId];
name = map[columnName];
age = map[columnAge];
sex = map[columnSex]; //version:2 新增的性别字段
}
@override
String toString() {
return 'User{id: $id, userId: $userId, name: $name, age: $age, sex: $sex}';
}
}
class SqlLite {
Database db;
///创建数据库
openSqlLite() async {
var databasesPath = await getDatabasesPath();
String path = join(databasesPath, "test.db");
db = await openDatabase(
path,
version: 2,
onCreate: _onCreate,
onUpgrade: _onUpgrade,
);
}
void _onCreate(db, version) async {
var batch = db.batch();
_createTableUser(batch); //可在此创建多个表
await batch.commit();
}
///创建用户表
void _createTableUser(batch) {
batch.execute('''
create table $tableName (
$columnId integer primary key,
$columnUserId integer,
$columnName text,
$columnAge integer )
''');
}
///升级
void _onUpgrade(db, oldVersion, newVersion) async {
print("升级");
var batch = db.batch();
if (oldVersion == 1) {
_updateTableUser(batch); //升级过程中也可以在此创建新表
}
await batch.commit();
}
///user表增加性别字段
void _updateTableUser(batch) {
batch.execute('alter table $tableName add $columnSex text');
}
/// 插入数据
Future insert(user) async {
return await db.insert(tableName, user.toMap());
}
/// 查询所有数据
Future> queryAll() async {
List
测试用例:
import 'package:flutter/material.dart';
import 'bean/User.dart';
import 'header.dart';
class Home extends StatefulWidget {
@override
_HomeState createState() => _HomeState();
}
class _HomeState extends State with TickerProviderStateMixin {
SqlLite sqlLite = SqlLite();
TextEditingController controller = TextEditingController();
@override
Widget build(BuildContext context) {
return Scaffold(
backgroundColor: Colors.white,
appBar: Header(
title: "首页",
backgroundColor: Colors.grey,
),
body: ListView(
children: [
RaisedButton(
onPressed: _insertData,
child: Text("增加数据"),
),
RaisedButton(
onPressed: _deleteData,
child: Text("删除数据"),
),
RaisedButton(
onPressed: _queryData,
child: Text("修改数据"),
),
RaisedButton(
onPressed: _queryAll,
child: Text("查询数据"),
),
],
),
);
}
///插入数据
void _insertData() async {
await sqlLite.openSqlLite();
User u1 = User();
u1.userId = 101;
u1.name = "镜花水月1";
u1.age = 31;
await sqlLite.insert(u1);
User u2 = User();
u2.userId = 102;
u2.name = "镜花水月2";
u2.age = 32;
await sqlLite.insert(u2);
await sqlLite.close();
}
///删除数据
void _deleteData() async {
await sqlLite.openSqlLite();
await sqlLite.delete(102);
await sqlLite.close();
}
///修改数据
Future _queryData() async {
await sqlLite.openSqlLite();
User user = await sqlLite.getUser(101);
if (user != null) {
user.name = "flutter";
await sqlLite.update(user);
}
await sqlLite.close();
}
///查询数据
void _queryAll() async {
await sqlLite.openSqlLite();
List users = await sqlLite.queryAll();
if (users != null) {
print(users);
}
await sqlLite.close();
}
}