话不多说先安利:https://github.com/ddwhan0123/Useful-Open-Source-Android 一直在加新东西,你值得拥有
这几天忙的1B,这里跑那里跑,写的Demo就是没时间发帖,昨天10来点到家然后 弄鱼 弄麦麦啥的再敲敲代码就1点了,早上起来困的1B。。。。
OK,先来说下为什么写这篇文章。
上周面试,一个面试官问了一堆,答得还不错,然后聊到数据库,我说我之前用sql直接写,然后他一脸闷B说了句好吧。。。然后我应该去学个第三方的ORM,所以就写了这个Demo,这篇博文
greenDAO是什么我就不多罗嗦了,google/莆田(百度) 都有一堆,这里给出几个比较好的给大家
http://www.jianshu.com/p/c4e9288d2ce6
http://greenrobot.org/greendao/
来看下我们的项目结构
用到的库如下:
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
testCompile 'junit:junit:4.12'
compile 'com.android.support:appcompat-v7:23.4.0'
compile 'com.android.support:recyclerview-v7:23.4.0'
apt 'com.jakewharton:butterknife-compiler:8.1.0'
compile 'org.greenrobot:greendao:2.2.1'
compile 'com.jakewharton:butterknife:8.1.0'
compile 'com.apkfuns.logutils:library:1.4.2'
compile 'io.reactivex:rxjava:1.1.5'
compile 'io.reactivex:rxandroid:1.2.0'
}
因为这部分和其他开源库 还是有点使用的小区别,我这边还是照搬下如何构建项目(隔壁搬来的)
1.首先开个项目
2.然后在.src/main下java目录同级的地方新建个目录叫java-gen
3.开完之后在build.gradle的sourceSets节点复制以下内容
main {
java.srcDirs = ['src/main/java', 'src/main/java-gen']
}
当然记得把前面那一堆依赖里 greenDAO相关的先build下不然 不能成
4.接下来再建我们的依赖java Module(用于创建对象和DAO代码)
5.然后在那个项目里加上generator所需的依赖,像这样
dependencies {
compile fileTree(dir: 'libs', include: ['*.jar'])
compile 'org.greenrobot:greendao-generator:2.2.0'
}
6.然后在这个JAVA 项目里创建一个类,叫什么随你,喜欢就好。
这里贴下具体的代码
public class DemoClass {
public static void main(String[] asa) {
Schema schema = new Schema(1, "com.example");
addPerson(schema);
try {
new DaoGenerator().generateAll(schema, "/Users/jiajiewang/Desktop/SQLDemo/app/src/main/java-gen");
} catch (Exception e) {
e.printStackTrace();
}
}
public static void addPerson(Schema schema) {
Entity entity = schema.addEntity("Person");
entity.addIdProperty();
entity.addStringProperty("Name").notNull();
entity.addStringProperty("Age").notNull();
entity.addStringProperty("Address");
}
}
这里有一个Main方法,一个addPerson
这里我们先声明了一个模式对象,传入2个参数 1个是数据库版本号,1个是生成代码的路径,这个路径就是前面我们java-gen的路径(可能在运行前并没有这个路径,但是运行后就自动生成了)
然后我们再给这个模式对象构建实体,这个实体其实就是我们数据库字段所对应的对象实体。(greenDAO的一系列操作就是在操作对象)
设置完了构建完了,OK我们就“创造”代码,传入模式对象和输出路径就OK了!!
右键 run main就成了我们最上面那个包截图的样子了
里面都是些啥我这里不做过多解释,上面传送门有介绍,我们来看看具体如何使用
官方比较推荐把一系列的初始化行为放在Applicatin里,省的每个业务类都要做初始化的一些操作。
public class MyApplication extends Application {
public DaoSession daoSession;
public SQLiteDatabase db;
public DaoMaster.DevOpenHelper helper;
public DaoMaster daoMaster;
@Override
public void onCreate() {
super.onCreate();
helper = new DaoMaster.DevOpenHelper(this, "person", null);
db = helper.getWritableDatabase();
daoMaster = new DaoMaster(db);
daoSession = daoMaster.newSession();
}
public DaoSession getDaoSession() {
return daoSession;
}
public SQLiteDatabase getDb() {
return db;
}
}
这里主要是给予业务类获取DAO实例什么的用。
贴下运行效果(Log也可以看下不然不太好理解)
增
查
改(先添加了数据,然后再改)
年纪改到了 100
删 id为2的那一条数据
删完了 就剩一条了
接下来就是具体的增删查改了,因为数据库都是大消耗操作,所以这里用了 RX(强行按进去的RX 其实这里用不用无所谓了)
package com.wjj.demo;
public class MainActivity extends AppCompatActivity {
@BindView(R.id.delete_id_tv)
EditText deleteIdTv;
private List list;
private Cursor cursor;
private PersonAdapter adapter;
@BindView(R.id.add)
Button add;
@BindView(R.id.delete)
Button delete;
@BindView(R.id.edit)
Button edit;
@BindView(R.id.query)
Button query;
@BindView(R.id.recyclerView)
RecyclerView recyclerView;
@BindView(R.id.input_name)
EditText inputName;
@BindView(R.id.input_address)
EditText inputAddress;
@BindView(R.id.input_age)
EditText inputAge;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
//初始化游标
cursor = getDb().query(getPersonDao().getTablename(), getPersonDao().getAllColumns(), null, null, null, null, null);
list = new ArrayList<>();
adapter = new PersonAdapter(MainActivity.this, list);
recyclerView.setAdapter(adapter);
recyclerView.setLayoutManager(new LinearLayoutManager(this));
}
//返回Dao对象
private PersonDao getPersonDao() {
return ((MyApplication) this.getApplicationContext()).getDaoSession().getPersonDao();
}
//返回数据库对象
private SQLiteDatabase getDb() {
// 通过 BaseApplication 类提供的 getDb() 获取具体 db
return ((MyApplication) this.getApplicationContext()).getDb();
}
@OnClick({R.id.add, R.id.delete, R.id.edit, R.id.query})
public void onClick(View view) {
switch (view.getId()) {
case R.id.add:
addPerson();
break;
case R.id.delete:
String v = deleteIdTv.getText().toString().trim();
if (v.length() > 0) {
deletePerson(Long.parseLong(v));
} else {
LogUtils.e( "---> 删除所需的TextView值为空");
}
break;
case R.id.edit:
String age = inputAge.getText().toString().trim();
editPerson(age);
inputAge.setText("");
break;
case R.id.query:
list.clear();
queryPerson();
break;
}
}
//增
private void addPerson() {
Observable.create(new Observable.OnSubscribe() {
@Override
public void call(Subscriber super Person> subscriber) {
Person person = null;
String age = inputAge.getText().toString().trim();
String name = inputName.getText().toString().trim();
String address = inputAddress.getText().toString().trim();
//判断不为空
if (address.length() > 0 && name.length() > 0 && age.length() > 0) {
person = new Person(null, name, age, address);
getPersonDao().insert(person);
cursor.requery();
} else {
LogUtils.d("---> 有一个/多个输入框里没东西");
}
if (person != null) {
subscriber.onNext(person);
} else {
Observable.error(new NullPointerException("person为空"));
}
LogUtils.d("---> add 新线程" + Thread.currentThread().getId());
}
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber() {
@Override
public void onCompleted() {
}
@Override
public void onError(Throwable e) {
LogUtils.e(e);
}
@Override
public void onNext(Person person) {
inputAddress.setText("");
inputAge.setText("");
inputName.setText("");
}
});
}
//查
private void queryPerson() {
Observable.create(new Observable.OnSubscribe() {
@Override
public void call(Subscriber super String> subscriber) {
String age = inputAge.getText().toString().trim();
String name = inputName.getText().toString().trim();
String address = inputAddress.getText().toString().trim();
//判断是否有东西
if (name.length() > 0) {
queryLogic(name, 1);
subscriber.onNext(name);
} else if (age.length() > 0) {
queryLogic(age, 3);
subscriber.onNext(age);
} else if (address.length() > 0) {
subscriber.onNext(address);
queryLogic(address, 2); // Query 类代表了一个可以被重复执行的查询
} else {
LogUtils.d("有一个/多个输入框里没东西");
}
subscriber.onCompleted();
}
}).subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new Subscriber() {
@Override
public void onCompleted() {
adapter.notifyDataSetChanged();
}
@Override
public void onError(Throwable e) {
LogUtils.e(e);
}
@Override
public void onNext(String s) {
inputAge.setText("");
inputAddress.setText("");
inputName.setText("");
}
});
}
private void queryLogic(String value, int type) {
Query query = null;
switch (type) {
case 1:
// Query 类代表了一个可以被重复执行的查询
query = getQuery(value, PersonDao.Properties.Name);
break;
case 2:
query = getQuery(value, PersonDao.Properties.Address);
break;
case 3:
query = getQuery(value, PersonDao.Properties.Age);
break;
}
if (query != null) {
// 查询结果以 List 返回
List queryList = (List) query.list();
list.addAll(queryList);
LogUtils.d("--->有" + queryList.size() + "个值");
}
}
private Query getQuery(String value, Property p) {
Query query = null;
query = getPersonDao().queryBuilder()
//逻辑
.where(p.eq(value))
//排序
.orderAsc(PersonDao.Properties.Id)
.build();
return query;
}
//删
private void deletePerson(long value) {
Observable.just(value).subscribeOn(Schedulers.io()).map(new Func1() {
@Override
public Long call(Long aLong) {
getPersonDao().deleteByKey(aLong);
return aLong;
}
}).observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1() {
@Override
public void call(Long aLong) {
deleteIdTv.setText("");
}
});
}
//改
private void editPerson(String age) {
Observable.just(age).subscribeOn(Schedulers.io()).map(new Func1() {
@Override
public Person call(String s) {
Person person = new Person();
person.setAddress("suzhou");
person.setAge(s);
person.setName("kobe");
person.setId(3l);
getPersonDao().update(person);
return person;
}
}).observeOn(AndroidSchedulers.mainThread()).subscribe(new Action1() {
@Override
public void call(Person person) {
LogUtils.d(person);
}
});
}
}
上面这些业务代码比较简单,这里不做太多介绍,这里讲一下这些sql操作的方法哪来的
我们这些 数据库操作的方法来自多个类,但是实现类是我们一直在get的PersonDao
而
PersonDao extends AbstractDao<Person, Long>
所以其实这些sql方法都来源于 public abstract class AbstractDao
一看到抽象类就懂了,给我们拿来使的。 里面有一大堆 public protected的方法,这个大家自己去看就行。
总结:
我对greenDAO内部实现不是太清楚,但是大量的测评和使用好评率让我们可以放心食用,接下来一段时间还会继续啃ORM,会不会对这部分最 2 3 4期的分析看情况吧。
如果英文好的可以看http://greenrobot.org/greendao/documentation/how-to-get-started/ 学创建流程。
源码地址:https://github.com/ddwhan0123/GreenDaoDemo
下载地址:https://github.com/ddwhan0123/GreenDaoDemo/archive/master.zip