设计思路
笔记本与笔记是一对多的关系:
- 每条笔记属于一个笔记本
- 一个笔记本包含多条笔记
1. 数据库设计
首先,我们需要为笔记本创建新的表,将其命名为notebook。我们简单的将其设计为具有以下字段:
- id: 一个笔记本的唯一id
- name: 笔记本的名字
其次,我们要为笔记表(note)增加与笔记本表的关联。则在创建note表时增加一列notebookId,即某条笔记对应的笔记本的id
2. 数据库修改
打开前面章节中创建的NoteDAO类,找到其中的内部类NoteDbHelper,修改它的onCreate(),修改note表创建语句,在最后增加notebookId列,并添加创建notebook表的语句:
@Override
public void onCreate(SQLiteDatabase db) {
// 创建note表
db.execSQL("CREATE TABLE " + TABLE_NOTE + "(" +
COL_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
COL_TITLE + " TEXT, " +
COL_CONTENT + " TEXT, " +
COL_CREATE_TIME + " INTEGER, " +
COL_NOTEBOOK_ID + " INTEGER)");
// 创建notebook表
db.execSQL("CREATE TABLE " + TABLE_NOTEBOOK + "(" +
COL_ID + " INTEGER PRIMARY KEY AUTOINCREMENT, " +
COL_NOTEBOOK_NAME + " TEXT)");
}
出现了三个新的常量,分别是笔记本表的表名常量TABLE_NOTEBOOK,以及笔记本名字对应的列名常量COL_NOTEBOOK_NAME。打开与NoteDAO类同一包下的Constants类,在末尾添加这两个常量:
public class Constants {
...
public static final String COL_NOTEBOOK_ID = "notebookId";
public static final String TABLE_NOTEBOOK = "notebook";
public static final String COL_NOTEBOOK_NAME= "name";
}
另外,根据对笔记表的修改,我们应当相应的修改Note类,增加notebookId属性以及对应的访问方法。打开Note类,增加以下内容,其它旧有部分保持不变:
public class Note {
...
/**
* 所属的笔记本的id
*/
private long notebookId;
...
public Note(long id, String title, String content, long createTim, long notebookId) {
this.id = id;
this.title = title;
this.content = content;
this.createTime = createTime;
this.notebookId = notebookId;
}
...
public long getNotebookId() {
return notebookId;
}
public void setNotebookId(long noteId) {
notebookId = notebookId;
}
}
可以看到,我们还增加了一个构造方法,将notebookId的初始化包含进去。原来已有的构造方法保持不变。
运行代码之前,将原来版本的App从模拟器或者手机中删除。原因是,数据库结构变更并不会自动触发升级操作。而数据库升级操作相对复杂,此处我们先不考虑,只是简单的卸载后重新运行程序。这样做的弊端是,原来已有的数据全部丢失。但是对于目前阶段,我们的数据主要是测试数据,因此影响不大。
接下来,由于数据模型发生变化,我们的数据访问方法也要进行相应的修改。再次打开NoteDAO类,依次修改如下方法:
- insertNote()
- queryNoteById()
- queryAllNotes()
insertNote()
在向note表插入笔记时,增加代码以写入notebookId属性:
public Note insertNote(Note note) {
...
ContentValues values = new ContentValues();
values.put(COL_TITLE, note.getTitle());
values.put(COL_CONTENT, note.getContent());
values.put(COL_CREATE_TIME, note.getCreateTime());
// 将notebookId写入数据库
values.put(COL_NOTEBOOK_ID, note.getNotebookId());
...
}
queryNoteById()
public Note queryNoteById(long id) {
...
String title = cursor.getString(1);
String content = cursor.getString(2);
// 读取notebookId记录
long notebookId = cursor.getLong(4);
Note note = new Note(id, title, content, createTime, notebookId);
return note;
...
}
queryAllNotes()
public List<Note> queryAllNotes() {
...
long id = cursor.getLong(0);
String title = cursor.getString(1);
String content = cursor.getString(2);
long createTime = cursor.getLong(3);
// 读取notebookId
long notebookId = cursor.getLong(4);
Note note = new Note(id, title, content, createTime, notebookId);
notes.add(note);
...
}
运行代码,应用原有功能应当保持不变。
2. 创建笔记本列表页面
用ActionBar图标按钮来作为笔记本列表入口:

在点击右上角笔记本按钮后,打开一个新的activity,我们将其命名为NotebooksActivity。在这个activity中,完成以下功能:
- 展示全部笔记本
- 创建新的笔记本
- 选择笔记本,并向调用NotebooksActivity的上一级activity返回对应的笔记本ID
在我们的项目包名上右键选择“New -> Activity -> Empty Activity”,在弹出的对话框中填写名称并确认:

点击“Finish”,NotebooksActivity.java文件以及对应的布局文件自动创建完毕。
将NotebooksActivity的标题设置为“笔记本”(还记得怎么做吗?):
<activity
android:name=".NotebooksActivity"
android:label="@string/notebook"/>
现在打开全部笔记页面,添加ActionBar上的笔记本按钮。打开NoteListActivity类,添加菜单处理相关的两个方法:
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater = getMenuInflater();
menuInflater.inflate(R.menu.menu_note_list, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_item_notebook:
return true;
}
return super.onOptionsItemSelected(item);
}
此时,菜单资源文件menu_note_list.xml并不存在,menu_item_notebook菜单项必然也不存在,编辑界面会提示错误:

下面我们创建它们。在res目录下找到menu目录,里面已经有我们之前为新建笔记页面创建的菜单文件。我们现在新建一个名为menu_note_list.xml的新菜单文件,方法是右键单击menu文件夹,在弹出的菜单中选择“New -> Menu resource file”,在弹出的对话框中输入文件名:

点击OK完成,则创建好了空菜单文件:

打开编辑,为其中添加如下的菜单项:
<item
android:id="@+id/menu_item_notebook"
android:title="@string/notebook"
android:icon="@drawable/ic_notebook"
app:showAsAction="always"/>
其中:
- 菜单项id为menu_item_notebook
- 菜单项文字为“笔记本”字符串
- “app:showAsAction”属性表示将菜单项显示为图标按钮
- “android:icon”属性是对应的图标,设置为“@drawable/ic_notebook”

下载上面的图片,放到你的res/drawable-xxhdpi文件夹下即可。
现在我们实现笔记本按钮的操作,也就是启动我们刚才创建的笔记本列表页面。但是,这回不是简单的启动,而是要在笔记本列表中选择某个笔记本后将笔记本的id返回回来,于是,要用startActivityForResult()方法代替startActivity()方法来启动笔记本列表页面。
在onOptionsItemSelected()方法中编写代码如下:
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.menu_item_notebook:
// 添加如下代码:
Intent intent = new Intent(this, NotebooksActivity.class);
startActivityForResult(intent, 1);
return true;
}
return super.onOptionsItemSelected(item);
}
可以看到,startActivityForResult()多了一个参数“1”,这代表这次操作的请求码,据此在读取返回结果时判断来自哪个activity。至于如何处理返回结果,我们随后再讨论,现在简单的看一下启动笔记本列表页面的效果:

网友评论