/* * Copyright (c) 2010-2011, The MiCode Open Source Community (www.micode.net) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ //管理数据的创建和版本更新 更新笔记内容 版本更新 package net.micode.notes.data;//表示一个Java包(Package) 表示这个类在data包中 //net.micode.notes.data是包的名称,它通常按照反向域名的方式命名,以确保唯一性和可读性。在这个包中,net是顶级域名的一部分,micode可能是小米,notes.data则是具体的子包结构,用于存放与数据相关的类。 import android.content.ContentValues;//表示导入了Android框架中的 ContentValues 类。这是Android提供的一个用于存储数据库表中的键值对数据的类。 import android.content.Context;//导入了Android框架中的 Context 类。在Android开发中,Context 类是一个核心类,它提供了应用程序的全局信息的访问权限,以及对应用程序环境的基本操作方法 import android.database.sqlite.SQLiteDatabase;//导入了Android框架中的 SQLiteDatabase 类。这是Android中用于操作 SQLite 数据库的关键类之一。 import android.database.sqlite.SQLiteOpenHelper;//导入了Android框架中的 SQLiteOpenHelper 类。这是Android中用于管理 SQLite 数据库的一个重要类。 import android.util.Log;//导入了Android框架中的 Log 类。Log 类是Android中用于输出日志消息的类,它提供了一种在应用程序中记录信息、调试和监视应用程序行为的简单方式。 //导入data包中notes类里的DataColumns、DataConstants、NoteColumns import net.micode.notes.data.Notes.DataColumns; import net.micode.notes.data.Notes.DataConstants; import net.micode.notes.data.Notes.NoteColumns; //数据库操作 public class NotesDatabaseHelper extends SQLiteOpenHelper {//NotesDatabaseHelper继承了SQLiteOpenHelper类 //SQLiteOpenHelper是SQLiteDatabse的一个帮助类,用来管理数据的创建和版本更新 //一般是定义一个类继承SQLiteOpenHelper,并实现两个回调方法,OnCreat()和onUpgrade()用来创建和更新数据库,前一个在出洗手池数据库时才会被调用,后一个在数据库版本发生变化时才会被调用 private static final String DB_NAME = "note.db"; private static final int DB_VERSION = 4; 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; 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 ''" + ")"; 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 *当将笔记移动到文件夹时,增加文件夹中的笔记数量 */ 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 *当从一个文件夹中移动笔记时,减少该文件夹中的笔记数量 */ 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 *当插入新笔记到文件夹时,增加文件夹中的笔记数量 */ 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 *当从文件夹删除文件时,减少文件夹中笔记的数量 */ 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} *插入数据并且数据类型为 DataConstants#NOTE 时,要更新笔记的内容 *{@link DataConstants#NOTE}: 它指向名为 DataConstants 的类中的 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 *当数据类型为DataConstants#NOTE改变的时候,更新笔记内容 */ 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 *当数据类型为DataConstants#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); } private void createSystemFolder(SQLiteDatabase db) { ContentValues values = new ContentValues(); /** * call record foler for call notes *为通话记录创建文件夹 */ 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.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; boolean skipV2 = false; // 如果旧版本为1,则执行从版本1升级到版本2的操作 if (oldVersion == 1) { upgradeToV2(db); skipV2 = true; // this upgrade including the upgrade from v2 to v3 此升级包括从v2到v3的升级 oldVersion++; } // 如果旧版本为2且不跳过v2,则执行从版本2升级到版本3的操作 if (oldVersion == 2 && !skipV2) { upgradeToV3(db); reCreateTriggers = true; oldVersion++; } // 如果旧版本为3,则执行从版本3升级到版本4的操作 if (oldVersion == 3) { upgradeToV4(db); oldVersion++; } // 如果需要重新创建触发器,则重新创建笔记表和数据表的触发器 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); } 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 为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); } private void upgradeToV4(SQLiteDatabase db) { db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0"); } }