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.
xiangmuyi/NotesDatabaseHelper.java

279 lines
16 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.

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;
import net.micode.notes.data.Notes.DataColumns;
import net.micode.notes.data.Notes.DataConstants;
import net.micode.notes.data.Notes.NoteColumns;
// NotesDatabaseHelper类继承自SQLiteOpenHelper用于管理与笔记相关的数据库的创建、升级等操作
// 它负责创建笔记表、数据表以及相关的触发器,处理数据库版本更新等功能
public class NotesDatabaseHelper extends SQLiteOpenHelper {
// 定义数据库文件名
private static final String DB_NAME = "note.db";
// 定义数据库版本号,用于数据库升级时的版本判断等操作
private static final int DB_VERSION = 4;
// 定义内部接口TABLE用于存放数据库中表的名称常量方便在代码中统一引用表名提高可读性和可维护性
public interface TABLE {
// 笔记表的名称常量
public static final String NOTE = "note";
// 数据表的名称常量,可能用于存储笔记相关的附加数据等
public static final String DATA = "data";
}
// 用于日志记录的标签,方便在查看日志时识别是该类输出的日志信息
private static final String TAG = "NotesDatabaseHelper";
// 采用单例模式,保存该类的唯一实例,确保整个应用中只有一个数据库帮助类实例在操作数据库
private static NotesDatabaseHelper mInstance;
// 创建笔记表TABLE.NOTE的SQL语句定义了表的各个列名、数据类型、默认值以及主键等信息
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" +
")";
// 创建数据表TABLE.DATA的SQL语句同样定义了表的各列信息用于存储与笔记相关的数据内容等
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 ''" +
")";
// 创建基于数据表TABLE.DATA中笔记IDDataColumns.NOTE_ID字段的索引的SQL语句用于提高根据笔记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 + ");";
/**
* 以下是一系列用于数据库操作的触发器Trigger相关的SQL语句定义触发器用于在特定数据库操作发生时自动执行一些额外的逻辑。
* 例如,在更新、插入、删除笔记或数据时,对相关的计数、关联数据等进行相应的调整。
*/
/**
* 当笔记移动到某个文件夹更新NoteColumns.PARENT_ID字段增加该文件夹的笔记数量的触发器SQL语句。
* 它在TABLE.NOTE表的NoteColumns.PARENT_ID字段更新后触发通过更新语句增加目标文件夹新的父文件夹的NoteColumns.NOTES_COUNT字段值。
*/
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";
/**
* 当笔记从某个文件夹移出更新NoteColumns.PARENT_ID字段减少该文件夹的笔记数量的触发器SQL语句。
* 在TABLE.NOTE表的NoteColumns.PARENT_ID字段更新后触发条件是原文件夹的NoteColumns.NOTES_COUNT大于0时减少其数量。
*/
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";
/**
* 当向某个文件夹插入新笔记后增加该文件夹的笔记数量的触发器SQL语句。
* 在TABLE.NOTE表插入新记录后触发通过更新语句增加新笔记所属文件夹根据NoteColumns.PARENT_ID确定的NoteColumns.NOTES_COUNT字段值。
*/
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";
/**
* 当从某个文件夹删除笔记后减少该文件夹的笔记数量的触发器SQL语句。
* 在TABLE.NOTE表删除记录后触发条件是原文件夹的NoteColumns.NOTES_COUNT大于0时减少其数量基于原笔记所属文件夹ID进行操作。
*/
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";
/**
* 当向数据表TABLE.DATA插入类型为{@link DataConstants#NOTE}的数据时更新对应笔记的内容NoteColumns.SNIPPET字段的触发器SQL语句。
* 在TABLE.DATA表插入记录后触发且插入的数据类型符合条件时将对应笔记的内容设置为新插入数据的内容DataColumns.CONTENT字段
*/
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";
/**
* 当数据表TABLE.DATA中类型为{@link DataConstants#NOTE}的数据发生更新时更新对应笔记的内容NoteColumns.SNIPPET字段的触发器SQL语句。
* 在TABLE.DATA表更新记录且符合数据类型条件时将对应笔记的内容更新为新的数据内容DataColumns.CONTENT字段
*/
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";
/**
* 当数据表TABLE.DATA中类型为{@link DataConstants#NOTE}的数据被删除时更新对应笔记的内容NoteColumns.SNIPPET字段为默认空值的触发器SQL语句。
* 在TABLE.DATA表删除记录且符合数据类型条件时将对应笔记的内容设置为空字符串。
*/
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";
/**
* 当笔记被删除后删除与之关联的数据表TABLE.DATA中属于该笔记的数据的触发器SQL语句。
* 在TABLE.NOTE表删除记录后触发通过删除语句从TABLE.DATA表中删除NoteColumns.ID与被删除笔记的ID匹配的数据记录。
*/
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";
/**
* 当文件夹被删除后删除该文件夹下所有笔记的触发器SQL语句。
* 在TABLE.NOTE表删除记录即文件夹记录被删除后触发通过删除语句从TABLE.NOTE表中删除NoteColumns.PARENT_ID与被删除文件夹的ID匹配的笔记记录。
*/
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";
/**
* 当文件夹被移动到回收站文件夹更新NoteColumns.PARENT_ID字段将该文件夹下所有笔记也移动到回收站文件夹的触发器SQL语句。
* 在TABLE.NOTE表更新记录且新的父文件夹ID为回收站文件夹IDNotes.ID_TRASH_FOLER时触发将对应笔记的父文件夹ID都更新为回收站文件夹ID。
*/
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";
// NotesDatabaseHelper构造函数调用父类SQLiteOpenHelper的构造函数传入上下文、数据库名、游标工厂这里为null和数据库版本号
public NotesDatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
// 创建笔记表的方法接收一个SQLiteDatabase实例通过执行CREATE_NOTE_TABLE_SQL语句创建表
// 然后重新创建笔记表相关的触发器,并创建系统文件夹,最后记录日志表示笔记表已创建成功
public void createNoteTable(SQLiteDatabase db) {
db.execSQL(CREATE_NOTE_TABLE_SQL);
reCreateNoteTableTriggers(db);
createSystemFolder(db);
Log.d(TAG, "note table has been created");
}
// 重新创建笔记表相关触发器的方法先删除已存在的同名触发器如果有然后再执行创建各触发器的SQL语句
// 这样可以确保触发器的定义是最新的,避免因数据库结构变化等原因导致的问题
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);
}
// 创建系统文件夹的方法通过向笔记表TABLE.NOTE插入不同类型的系统文件夹记录来实现
// 每个文件夹记录设置了相应的ID和类型Notes.TYPE_SYSTEM用于构建应用中的默认文件夹结构
private void createSystemFolder(SQLiteDatabase db) {
ContentValues values = new ContentValues();
/**
* 通话记录文件夹,用于存放通话相关的笔记(这里假设是相关功能用途)
*/
values.put(NoteColumns.ID, Notes.ID_CALL_RECORD_FOLDER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
/**
* 根文件夹,作为默认的顶级文件夹
*/
values.clear();
values.put(NoteColumns.ID, Notes.ID_ROOT_FOLDER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);
db.insert(TABLE.NOTE, null, values);
/**
* 临时文件夹,可能用于在笔记移动等操作过程中的临时存放
*/
values.clear();
values.put(NoteColumns.ID, Notes.ID_TEMPARAY_FOLDER);
values.put(NoteColumns.TYPE, Notes.TYPE_SYSTEM);