You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
MiNotes/doc/成员代码分析/jhw/NotesDatabaseHelper.java

284 lines
17 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

//数据库操作SQLOpenhelper,对一些note和文件进行数据库的操作。比如删除文件后将文件里的note也相应删除
package net.micode.notes.data;
//保存一些数据信息,这些数据可以被数据库操作
import android.content.ContentValues;
//加载和访问资源
import android.content.Context;
//主要提供了对应于添加、删除、更新、查询的操作
import android.database.sqlite.SQLiteDatabase;
//数据库的更新和创建
import android.database.sqlite.SQLiteOpenHelper;
//安卓日志类接口
import android.util.Log;
//导入Notes.java中的DataColumns, NoteColumns接口和类DataConstants
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.DataConstants;
import net.micode.notes.data.Notes.NoteColumns;
//继承于SQLiteOpenHelper的类NotesDatabaseHelper用于实现对便签或者 文件的数据库操作,例如删除便签
public class NotesDatabaseHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "note.db";
private static final int DB_VERSION = 4;
public interface TABLE {
//接口分成note和data在后面的程序里分别使用过
public static final String NOTE = "note";
public static final String DATA = "data";
}
//创建一个表格用来储存标签编号
private static final String TAG = "NotesDatabaseHelper";
//实例化一个NoteDatabaseHelper
private static NotesDatabaseHelper mInstance;
/**
* 当创建一个新的便签,就产生了各类关于便签的信息,
* 比如ID父便签ID背景颜色创建日期等
* 我们需要把这些信息放入数据库,这就是数据库的表头。
* 我们在下面定义的涉及操作的字符串,
* 全都是为了在之后执行db.execSQL("字符串")。
*/
private static final String CREATE_NOTE_TABLE_SQL = "CREATE TABLE " + TABLE.NOTE + "(" + NoteColumns.ID + " INTEGER PRIMARY KEY," + NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," + NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," + NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," + NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" + ")";
//大体同上,这里储存的是便签内容的信息,
// 用这些信息作为数据库对便签内容存储的表头
private static final String CREATE_DATA_TABLE_SQL = "CREATE TABLE " + TABLE.DATA + "(" + DataColumns.ID + " INTEGER PRIMARY KEY," + DataColumns.MIME_TYPE + " TEXT NOT NULL," + DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 0," + NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," + DataColumns.CONTENT + " TEXT NOT NULL DEFAULT ''," + DataColumns.DATA1 + " INTEGER," + DataColumns.DATA2 + " INTEGER," + DataColumns.DATA3 + " TEXT NOT NULL DEFAULT ''," + DataColumns.DATA4 + " TEXT NOT NULL DEFAULT ''," + DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" + ")";
//创建索引名称为note_id_index在TABLE.DATA表格的DataCloumns.NOTE_ID列
private static final String CREATE_DATA_NOTE_ID_INDEX_SQL = "CREATE INDEX IF NOT EXISTS note_id_index ON " + TABLE.DATA + "(" + DataColumns.NOTE_ID + ");";//存储便签编号的一个数据表格
/**
* Increase folder's note count when move note to the folder
* 增加文件夹便签数量,当移动一个便签进入该文件夹后,
* 之后在db.execSQL(字符串)中用到,
* 启动自定义的数据库update触发器有相关的一系列数据库操作。
*/
private static final String NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER = "CREATE TRIGGER increase_folder_count_on_update " + " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE + " BEGIN " + " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + " END";
/**
* Decrease folder's note count when move note from folder
* 同上从文件夹移除便签文件夹便签数量减1
* 以后在db.execSQL(字符串)中用到,
* 启动自定义的数据库updata触发器附带相关的一系列操作
*/
private static final String NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER = "CREATE TRIGGER decrease_folder_count_on_update " + " AFTER UPDATE OF " + NoteColumns.PARENT_ID + " ON " + TABLE.NOTE + " BEGIN " + " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + " AND " + NoteColumns.NOTES_COUNT + ">0" + ";" + " END";
/**
* Increase folder's note count when insert new note to the folder
* 文件夹中创建新便签,文件夹便签数量+1
* 启动自定义的数据库insert触发器附带相关的一系列操作
*/
private static final String NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER = "CREATE TRIGGER increase_folder_count_on_insert " + " AFTER INSERT ON " + TABLE.NOTE + " BEGIN " + " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + " + 1" + " WHERE " + NoteColumns.ID + "=new." + NoteColumns.PARENT_ID + ";" + " END";
/**
* Decrease folder's note count when delete note from the folder
* 在文件夹中删除note时更新文件夹的note数量
*/
private static final String NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER = "CREATE TRIGGER decrease_folder_count_on_delete " + " AFTER DELETE ON " + TABLE.NOTE + " BEGIN " + " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.NOTES_COUNT + "=" + NoteColumns.NOTES_COUNT + "-1" + " WHERE " + NoteColumns.ID + "=old." + NoteColumns.PARENT_ID + " AND " + NoteColumns.NOTES_COUNT + ">0;" + " END";
/**
* Update note's content when insert data with type {@link DataConstants#NOTE}
* 当Note插入新的数据时更新note的内容并更改表格
*/
private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER = "CREATE TRIGGER update_note_content_on_insert " + " AFTER INSERT ON " + TABLE.DATA + " WHEN new." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + " BEGIN" + " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + " END";
/**
* Update note's content when data with {@link DataConstants#NOTE} type has changed
* 构建一条SQL语句用于实现在note中改变data后进行当前状态的更新
*/
private static final String DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER = "CREATE TRIGGER update_note_content_on_update " + " AFTER UPDATE ON " + TABLE.DATA + " WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + " BEGIN" + " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.SNIPPET + "=new." + DataColumns.CONTENT + " WHERE " + NoteColumns.ID + "=new." + DataColumns.NOTE_ID + ";" + " END";
/**
* Update note's content when data with {@link DataConstants#NOTE} type has deleted
* 当note的内容被删除时更新表格
*/
private static final String DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER = "CREATE TRIGGER update_note_content_on_delete " + " AFTER delete ON " + TABLE.DATA + " WHEN old." + DataColumns.MIME_TYPE + "='" + DataConstants.NOTE + "'" + " BEGIN" + " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.SNIPPET + "=''" + " WHERE " + NoteColumns.ID + "=old." + DataColumns.NOTE_ID + ";" + " END";
/**
* Delete datas belong to note which has been deleted
* 删除数据库中的数据,当便签中的数据被删除时删除相应数据库
*/
private static final String NOTE_DELETE_DATA_ON_DELETE_TRIGGER = "CREATE TRIGGER delete_data_on_delete " + " AFTER DELETE ON " + TABLE.NOTE + " BEGIN" + " DELETE FROM " + TABLE.DATA + " WHERE " + DataColumns.NOTE_ID + "=old." + NoteColumns.ID + ";" + " END";
/**
* Delete notes belong to folder which has been deleted
* 删除属于已删除的文件夹中的便签的数据
*/
private static final String FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER = "CREATE TRIGGER folder_delete_notes_on_delete " + " AFTER DELETE ON " + TABLE.NOTE + " BEGIN" + " DELETE FROM " + TABLE.NOTE + " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + " END";
/**
* Move notes belong to folder which has been moved to trash folder
* 还原垃圾桶中便签后需要更改的数据的表格。
*/
private static final String FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER = "CREATE TRIGGER folder_move_notes_on_trash " + " AFTER UPDATE ON " + TABLE.NOTE + " WHEN new." + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + " BEGIN" + " UPDATE " + TABLE.NOTE + " SET " + NoteColumns.PARENT_ID + "=" + Notes.ID_TRASH_FOLER + " WHERE " + NoteColumns.PARENT_ID + "=old." + NoteColumns.ID + ";" + " END";
public NotesDatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
//构造函数,传入数据库的名称和版本
public void createNoteTable(SQLiteDatabase db) {
db.execSQL(CREATE_NOTE_TABLE_SQL);
reCreateNoteTableTriggers(db);
createSystemFolder(db);
Log.d(TAG, "note table has been created");
}
//创建表格(用来存储标签属性)
private void reCreateNoteTableTriggers(SQLiteDatabase db) {
db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_update");
db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_update");
db.execSQL("DROP TRIGGER IF EXISTS decrease_folder_count_on_delete");
db.execSQL("DROP TRIGGER IF EXISTS delete_data_on_delete");
db.execSQL("DROP TRIGGER IF EXISTS increase_folder_count_on_insert");
db.execSQL("DROP TRIGGER IF EXISTS folder_delete_notes_on_delete");
db.execSQL("DROP TRIGGER IF EXISTS folder_move_notes_on_trash");
db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER);
db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER);
db.execSQL(NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER);
db.execSQL(NOTE_DELETE_DATA_ON_DELETE_TRIGGER);
db.execSQL(NOTE_INCREASE_FOLDER_COUNT_ON_INSERT_TRIGGER);
db.execSQL(FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER);
db.execSQL(FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER);
}
//execSQL是数据库操作的API主要是更改行为的SQL语句。
//在这里主要是用来重新创建上述定义的表格用的,先删除原来有的数据库的触发器再重新创建新的数据库
private void createSystemFolder(SQLiteDatabase db) {
ContentValues values = new ContentValues();
/**
* call record foler for call notes
* 初始化ContenValues实例然后存入相应的通话记录文件夹类型形成映射
*/
values.put(NoteColumns.ID, Notes.ID_CALL_RECORD_FOLDER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
/**
* root folder which is default folder
* 对根文件夹修改先将values实例的内容清空然后存入values再插入对象
*/
values.clear();
values.put(NoteColumns.ID, Notes.ID_ROOT_FOLDER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
/**
* temporary folder which is used for moving note
* 设置临时文件夹作为文件夹移动的有效目标
*/
values.clear();
values.put(NoteColumns.ID, Notes.ID_TEMPARAY_FOLDER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
/**
* create trash folder
* 创建垃圾文件夹
*/
values.clear();
values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
}
//创建几个系统文件夹
public void createDataTable(SQLiteDatabase db) {
db.execSQL(CREATE_DATA_TABLE_SQL);
reCreateDataTableTriggers(db);
db.execSQL(CREATE_DATA_NOTE_ID_INDEX_SQL);
Log.d(TAG, "data table has been created");
}//创建表格(用来存储标签内容)
private void reCreateDataTableTriggers(SQLiteDatabase db) {
db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_insert");
db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_update");
db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_delete");
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER);
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER);
db.execSQL(DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER);
}//创建用于表格初始化,删除触发器,然后更新触发器
static synchronized NotesDatabaseHelper getInstance(Context context) {
if (mInstance == null) {
mInstance = new NotesDatabaseHelper(context);
}
return mInstance;
}
//上网查是为解决同一时刻只能有一个线程执行.
//在写程序库代码时,有时有一个类需要被所有的其它类使用,
//但又要求这个类只能被实例化一次,是个服务类,定义一次,其它类使用同一个这个类的实例
@Override
public void onCreate(SQLiteDatabase db) {
createNoteTable(db);
createDataTable(db);
}//实现两个表格(上面创建的两个表格)
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//是否重建的信号
boolean reCreateTriggers = false;
//是否从V2升级到V3
boolean skipV2 = false;
//判断旧版本是不是V1如果是就升级版本到V2
if (oldVersion == 1) {
upgradeToV2(db);
skipV2 = true; // this upgrade including the upgrade from v2 to v3
oldVersion++;
}
//判断旧版本是V2且未跳过V2版本就升级版本到V3
if (oldVersion == 2 && !skipV2) {
upgradeToV3(db);
reCreateTriggers = true;
oldVersion++;
}
//如果旧版本是V3就升级版本到V4
if (oldVersion == 3) {
upgradeToV4(db);
oldVersion++;
}
//若重构触发器的值为真,那么,
// 要把便签note和数据data表单的数据库触发器重构调用以上的定义
if (reCreateTriggers) {
reCreateNoteTableTriggers(db);
reCreateDataTableTriggers(db);
}
//旧版本与最新版本不一致,抛出异常
if (oldVersion != newVersion) {
throw new IllegalStateException("Upgrade notes database to version " + newVersion + "fails");
}
}
//数据库版本的更新(数据库内容的更改)
private void upgradeToV2(SQLiteDatabase db) {
db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE);
db.execSQL("DROP TABLE IF EXISTS " + TABLE.DATA);
createNoteTable(db);
createDataTable(db);
}
//更新到V2版本,删除note和data表然后新建表
private void upgradeToV3(SQLiteDatabase db) {
// drop unused triggers
db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_insert");
db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_delete");
db.execSQL("DROP TRIGGER IF EXISTS update_note_modified_date_on_update");
// add a column for gtask id
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''");
// add a trash system folder
ContentValues values = new ContentValues();
values.put(NoteColumns.ID, Notes.ID_TRASH_FOLER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
}
//更新到V3版本删除触发器新增gtask和trash行然后在表中增添表头
private void upgradeToV4(SQLiteDatabase db) {
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0");
}//更新到V4版本,但是不知道V2、V3、V4是什么意思
}