GreenDao与ReactiveX的完美搭配
作为Android开发者,一定不会对 GreenDao 和 ReactiveX 陌生。
GreenDao 号称Android最快的关系型数据库
ReactiveX Rx是一个编程模型,目标是提供一致的编程接口,帮助开发者更方便的处理异步数据流。
下面我们就通过一个实例,来讲解有无Rx支持的时候GreenDao应该怎么用,实现增删操作。
首先导入需要的库(本文针对的 GreenDao 是 3.x 版本, Rx 是 1.x 版本)
GreenDao导入需求库的说明: https://github.com/greenrobot/greenDAO/
在 build.gradle(Project:Xxx) 下,添加:
buildscript { repositories { ... mavenCentral() ... } dependencies { ... classpath 'org.greenrobot:greendao-gradle-plugin:3.2.2' ... } }
在 build.gradle(Module:Xxx) 下,添加:
... apply plugin: 'org.greenrobot.greendao' ... dependencies { ... compile 'org.greenrobot:greendao:3.2.2' ... }
Rx导入需求库的说明: https://github.com/ReactiveX/RxJava/tree/1.x
在 build.gradle(Module:Xxx) 下,添加:
dependencies { ... compile 'io.reactivex:rxjava:1.2.9' compile 'io.reactivex:rxandroid:1.2.1' ... }
需求库添加完之后就可以进入正题了
1.参考GreenDao官方文档,添加必要的类 Note 、 NotesAdapter 、 NoteType 、 NoteTypeConverter
Note :
/** * Entity mapped to table "NOTE". */ @Entity(indexes = { @Index(value = "text, date DESC", unique = true) }) public class Note { @Id private Long id; @NotNull private String text; private String comment; private java.util.Date date; @Convert(converter = NoteTypeConverter.class, columnType = String.class) private NoteType type; @Generated(hash = 1272611929) public Note() { } public Note(Long id) { this.id = id; } @Generated(hash = 1686394253) public Note(Long id, @NotNull String text, String comment, java.util.Date date, NoteType type) { this.id = id; this.text = text; this.comment = comment; this.date = date; this.type = type; } public Long getId() { return id; } public void setId(Long id) { this.id = id; } @NotNull public String getText() { return text; } /** * Not-null value; ensure this value is available before it is saved to the database. */ public void setText(@NotNull String text) { this.text = text; } public String getComment() { return comment; } public void setComment(String comment) { this.comment = comment; } public java.util.Date getDate() { return date; } public void setDate(java.util.Date date) { this.date = date; } public NoteType getType() { return type; } public void setType(NoteType type) { this.type = type; } }
NotesAdapter :
public class NotesAdapter extends RecyclerView.Adapter<NotesAdapter.NoteViewHolder> { private NoteClickListener clickListener; private List<Note> dataset; public interface NoteClickListener { void onNoteClick(int position); } static class NoteViewHolder extends RecyclerView.ViewHolder { public TextView text; public TextView comment; public NoteViewHolder(View itemView, final NoteClickListener clickListener) { super(itemView); text = (TextView) itemView.findViewById(R.id.textViewNoteText); comment = (TextView) itemView.findViewById(R.id.textViewNoteComment); itemView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { if (clickListener != null) { clickListener.onNoteClick(getAdapterPosition()); } } }); } } public NotesAdapter(NoteClickListener clickListener) { this.clickListener = clickListener; this.dataset = new ArrayList<Note>(); } public void setNotes(@NonNull List<Note> notes) { dataset = notes; notifyDataSetChanged(); } public Note getNote(int position) { return dataset.get(position); } @Override public NotesAdapter.NoteViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { View view = LayoutInflater.from(parent.getContext()) .inflate(R.layout.item_note, parent, false); return new NoteViewHolder(view, clickListener); } @Override public void onBindViewHolder(NotesAdapter.NoteViewHolder holder, int position) { Note note = dataset.get(position); holder.text.setText(note.getText()); holder.comment.setText(note.getComment()); } @Override public int getItemCount() { return dataset.size(); } }
NoteType :
public enum NoteType { TEXT, LIST, PICTURE }
NoteTypeConverter :
public class NoteTypeConverter implements PropertyConverter<NoteType, String> { @Override public NoteType convertToEntityProperty(String databaseValue) { return NoteType.valueOf(databaseValue); } @Override public String convertToDatabaseValue(NoteType entityProperty) { return entityProperty.name(); } }
必要的类添加之后,接下来就是重头戏:
用代码说话,横向比较 GreenDao 在有无 Rx 的支持下应该如何书写
1.初始化类
无 Rx 写法
private NoteDao noteDao; private Query<Note> notesQuery;
有 Rx 写法
private RxDao<Note, Long> noteDao; private RxQuery<Note> notesQuery;
2.将记录保存到DAO里
无 Rx 写法
DaoSession daoSession = ((BaseApplication) getApplication()).getDaoSession(); noteDao = daoSession.getNoteDao();
有 Rx 写法
DaoSession daoSession = ((BaseApplication) getApplication()).getDaoSession(); noteDao = daoSession.getNoteDao().rx();
3.查询所有记录,按A-Z分类
无 Rx 写法
notesQuery = noteDao.queryBuilder().orderAsc(NoteDao.Properties.Text).build();
有 Rx 写法
notesQuery = daoSession.getNoteDao().queryBuilder().orderAsc(NoteDao.Properties.Text).rx();
4.初始化View
无 Rx 写法
protected void setUpViews() { RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerViewNotes); //noinspection ConstantConditions recyclerView.setHasFixedSize(true); recyclerView.setLayoutManager(new LinearLayoutManager(this)); notesAdapter = new NotesAdapter(noteClickListener); recyclerView.setAdapter(notesAdapter); addNoteButton = findViewById(R.id.buttonAdd); //noinspection ConstantConditions addNoteButton.setEnabled(false); editText = (EditText) findViewById(R.id.editTextNote); editText.setOnEditorActionListener(new TextView.OnEditorActionListener() { @Override public boolean onEditorAction(TextView v, int actionId, KeyEvent event) { if (actionId == EditorInfo.IME_ACTION_DONE) { addNote(); return true; } return false; } }); editText.addTextChangedListener(new TextWatcher() { @Override public void onTextChanged(CharSequence s, int start, int before, int count) { boolean enable = s.length() != 0; addNoteButton.setEnabled(enable); } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void afterTextChanged(Editable s) { } }); }
有 Rx 写法
protected void setUpViews() { RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerViewNotes); //noinspection ConstantConditions recyclerView.setHasFixedSize(true); recyclerView.setLayoutManager(new LinearLayoutManager(this)); notesAdapter = new NotesAdapter(noteClickListener); recyclerView.setAdapter(notesAdapter); addNoteButton = findViewById(R.id.buttonAdd); editText = (EditText) findViewById(R.id.editTextNote); //noinspection ConstantConditions RxTextView.editorActions(editText).observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<Integer>() { @Override public void call(Integer actionId) { if (actionId == EditorInfo.IME_ACTION_DONE) { addNote(); } } }); RxTextView.afterTextChangeEvents(editText).observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<TextViewAfterTextChangeEvent>() { @Override public void call(TextViewAfterTextChangeEvent textViewAfterTextChangeEvent) { boolean enable = textViewAfterTextChangeEvent.editable().length() > 0; addNoteButton.setEnabled(enable); } }); }
5.更新记录
无 Rx 写法
private void updateNotes() { List<Note> notes = notesQuery.list(); notesAdapter.setNotes(notes); }
有 Rx 写法
private void updateNotes() { notesQuery.list() .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<List<Note>>() { @Override public void call(List<Note> notes) { notesAdapter.setNotes(notes); } }); }
6.添加记录
无 Rx 写法
private void addNote() { String noteText = editText.getText().toString(); editText.setText(""); final DateFormat df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM); String comment = "Added on " + df.format(new Date()); Note note = new Note(); note.setText(noteText); note.setComment(comment); note.setDate(new Date()); note.setType(NoteType.TEXT); noteDao.insert(note); Log.d("DaoExample", "Inserted new note, ID: " + note.getId()); updateNotes(); }
有 Rx 写法
private void addNote() { String noteText = editText.getText().toString(); editText.setText(""); final DateFormat df = DateFormat.getDateTimeInstance(DateFormat.MEDIUM, DateFormat.MEDIUM); String comment = "Added on " + df.format(new Date()); Note note = new Note(null, noteText, comment, new Date(), NoteType.TEXT); noteDao.insert(note) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<Note>() { @Override public void call(Note note) { Log.d("DaoExample", "Inserted new note, ID: " + note.getId()); updateNotes(); } }); }
7.删除记录
无 Rx 写法
NotesAdapter.NoteClickListener noteClickListener = new NotesAdapter.NoteClickListener() { @Override public void onNoteClick(int position) { Note note = notesAdapter.getNote(position); Long noteId = note.getId(); noteDao.deleteByKey(noteId); Log.d("DaoExample", "Deleted note, ID: " + noteId); updateNotes(); } };
有 Rx 写法
NotesAdapter.NoteClickListener noteClickListener = new NotesAdapter.NoteClickListener() { @Override public void onNoteClick(int position) { Note note = notesAdapter.getNote(position); final Long noteId = note.getId(); noteDao.deleteByKey(noteId) .observeOn(AndroidSchedulers.mainThread()) .subscribe(new Action1<Void>() { @Override public void call(Void aVoid) { Log.d("DaoExample", "Deleted note, ID: " + noteId); updateNotes(); } }); } };
最后别忘了新建一个Application类,并添加到Manifest中
public class BaseApplication extends Application { /** * A flag to show how easily you can switch from standard SQLite to the encrypted SQLCipher. */ public static final boolean ENCRYPTED = true; private DaoSession daoSession; @Override public void onCreate() { super.onCreate(); DaoMaster.DevOpenHelper helper = new DaoMaster.DevOpenHelper( this, ENCRYPTED ? "notes-db-encrypted" : "notes-db"); Database db = ENCRYPTED ? helper.getEncryptedWritableDb("super-secret") : helper.getWritableDb(); daoSession = new DaoMaster(db).newSession(); } public DaoSession getDaoSession() { return daoSession; } }
文中额外可能会用到的库
compile 'com.jakewharton.rxbinding:rxbinding:1.0.1' compile 'net.zetetic:android-database-sqlcipher:3.5.6'
关注我的新浪微博,获取更多Android开发资讯!关注科技评论家,领略科技、创新、教育以及最大化人类智慧与想象力!