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.
gitProject/other/06_190243114庞浩_代码标注/NotesDatabaseHelper.java

440 lines
23 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.

/*
* 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;
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。
* 在该类中定义了数据库名DB_NAME和数据库版本号DB_VERSION
* 并定义了一个内部接口TABLE该接口中定义了NOTE和DATA两个常量分别表示数据库中的两个表名。
* 其中SQLiteOpenHelper是Android提供的用于管理SQLite数据库的类
* 它提供了创建、更新、打开和关闭数据库的方法,同时它也能够在不同的版本之间管理数据库的迁移。
*/
public class NotesDatabaseHelper extends SQLiteOpenHelper {
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";//这一行代码定义了一个名为TAG的字符串常量用于在调试时作为日志标签。
/**
* 定义了一个静态变量mInstance类型是NotesDatabaseHelper并且标记为static
* 表示这个变量是属于类的而不是实例的。
* 在类被加载的时候这个变量会被创建。这个变量的作用是在整个应用中只创建一个NotesDatabaseHelper实例
* 这样可以避免在多个地方重复创建数据库连接和实例,提高应用的性能和效率。
*/
private static NotesDatabaseHelper mInstance;
/**
* 这段代码定义了两个字符串常量 CREATE_NOTE_TABLE_SQL 和 CREATE_DATA_TABLE_SQL
* 分别用于创建两个数据库表格note 和 data。
*/
private static final String CREATE_NOTE_TABLE_SQL =
"CREATE TABLE " + TABLE.NOTE + "(" +
NoteColumns.ID + " INTEGER PRIMARY KEY," +//笔记 ID整数类型作为主键
NoteColumns.PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +//父笔记 ID整数类型不为空默认为 0
NoteColumns.ALERTED_DATE + " INTEGER NOT NULL DEFAULT 0," +//提醒时间,整数类型,不为空,默认为 0
NoteColumns.BG_COLOR_ID + " INTEGER NOT NULL DEFAULT 0," +//背景颜色 ID整数类型不为空默认为 0
NoteColumns.CREATED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +//创建时间,整数类型,不为空,默认为当前时间
NoteColumns.HAS_ATTACHMENT + " INTEGER NOT NULL DEFAULT 0," +//是否有附件,整数类型,不为空,默认为 0
NoteColumns.MODIFIED_DATE + " INTEGER NOT NULL DEFAULT (strftime('%s','now') * 1000)," +//修改时间,整数类型,不为空,默认为当前时间
NoteColumns.NOTES_COUNT + " INTEGER NOT NULL DEFAULT 0," +//笔记数量,整数类型,不为空,默认为 0
NoteColumns.SNIPPET + " TEXT NOT NULL DEFAULT ''," +//笔记概要,文本类型,不为空,默认为空字符串
NoteColumns.TYPE + " INTEGER NOT NULL DEFAULT 0," +//笔记类型,整数类型,不为空,默认为 0
NoteColumns.WIDGET_ID + " INTEGER NOT NULL DEFAULT 0," +//小部件 ID整数类型不为空默认为 0
NoteColumns.WIDGET_TYPE + " INTEGER NOT NULL DEFAULT -1," +//小部件类型,整数类型,不为空,默认为 -1
NoteColumns.SYNC_ID + " INTEGER NOT NULL DEFAULT 0," +//同步 ID整数类型不为空默认为 0
NoteColumns.LOCAL_MODIFIED + " INTEGER NOT NULL DEFAULT 0," +//本地修改标识,整数类型,不为空,默认为 0
NoteColumns.ORIGIN_PARENT_ID + " INTEGER NOT NULL DEFAULT 0," +//原始父笔记 ID整数类型不为空默认为 0
NoteColumns.GTASK_ID + " TEXT NOT NULL DEFAULT ''," +//Google 任务 ID文本类型不为空默认为空字符串
NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" +//版本号,整数类型,不为空,默认为 0
")";
private static final String CREATE_DATA_TABLE_SQL =
"CREATE TABLE " + TABLE.DATA + "(" +
DataColumns.ID + " INTEGER PRIMARY KEY," +//数据 ID整数类型作为主键
DataColumns.MIME_TYPE + " TEXT NOT NULL," +//MIME 类型,文本类型,不为空
DataColumns.NOTE_ID + " INTEGER NOT NULL DEFAULT 0," +//笔记 ID整数类型不为空默认为 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 ''" +
")";
/**
* 这是一个用于创建数据库索引的SQL语句它将创建一个名为"note_id_index"的索引,
* 该索引将位于"TABLE.DATA"表上,并将使用"DataColumns.NOTE_ID"列作为索引键。
* 这个索引的目的是在查询该表时提高性能尤其是在根据笔记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 + ");";
//以下是各种 SQLite 数据库的触发器,用于更新数据库
/**
* 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类型的数据时更新笔记的内容
*/
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类型的数据发生更改时更新笔记的内容
*/
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类型的数据时更新笔记的内容
*/
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";
/**
* 这段代码是一个构造函数用于创建一个NotesDatabaseHelper对象。这个对象是用于管理SQLite数据库的帮助类可以用来创建、升级和管理数据库表格。
* 构造函数有四个参数,分别是:
* Context context上下文对象用于访问应用程序的资源和环境。
* String DB_NAME数据库的名称。
* CursorFactory factory用于创建游标对象的工厂类如果为null则使用默认工厂。
* int DB_VERSION数据库的版本号用于管理数据库的升级。
*/
public NotesDatabaseHelper(Context context) {
super(context, DB_NAME, null, DB_VERSION);
}
/**
* 该方法负责在数据库中创建笔记表。
* 它执行SQL语句CREATE_NOTE_TABLE_SQL来创建表然后调用reCreateNoteTableTriggers方法来重新创建与笔记表关联的触发器。
* 然后它通过调用createSystemFolder方法创建一个系统文件夹并使用Log.d方法记录一条消息以指示笔记表已经创建。
*/
public void createNoteTable(SQLiteDatabase db) {
db.execSQL(CREATE_NOTE_TABLE_SQL);
reCreateNoteTableTriggers(db);
createSystemFolder(db);
Log.d(TAG, "note table has been created");
}
/**
* 该方法用于重新创建笔记表相关的触发器。
* 它首先使用DROP TRIGGER语句删除所有已有的触发器然后使用CREATE TRIGGER语句重新创建它们。
* 这个方法是为了在升级数据库时使用,以便更新旧版本的触发器。
* @param db
*/
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);
}
/**
* 此方法在数据库中创建四个系统文件夹:通话记录文件夹、根文件夹、临时文件夹和废纸篓文件夹。
* 该方法创建一个ContentValues对象并为每个文件夹的ID和TYPE列添加值。
* 然后该方法使用SQLiteDatabase类的insert方法将值插入笔记表中。
* 系统文件夹的ID定义为Notes类中的常量。
* 通话记录文件夹用于通话笔记,根文件夹是默认文件夹,临时文件夹用于移动笔记,废纸篓文件夹是移动已删除笔记的地方。
*/
private void createSystemFolder(SQLiteDatabase db) {
ContentValues values = new ContentValues();
/**
* call record folder 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 foldermo
*/
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);
}
/**
* 此方法在数据库中创建数据表,并设置必要的触发器和索引。
* 它将SQLiteDatabase类的实例作为参数用于执行SQL语句以创建数据表、重新创建触发器和创建索引。
* CREATE_DATA_TABLE_SQL常量保存用于创建数据表的SQL语句该语句定义列及其数据类型。
* 调用recreatedatabletriggers方法来删除和重新创建与数据表关联的触发器这将确保触发器是最新的模式更改。
* CREATE_DATA_NOTE_ID_INDEX_SQL常量保存SQL语句用于在数据表的NOTE ID列上创建索引
* 这提高了在NOTE ID列上联接数据和NOTE表的查询的性能。最后打印一条日志消息指示数据表已经创建。
*/
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");
}
/**
* Recreatedatabletriggers方法用于删除用于在insert、update和delete上更新注释内容的现有触发器
* 然后使用最新定义重新创建它们。
* 以下是被删除的触发器update_note_content_on_insert_content_on_update_note_content_on_delete
* 这些是重新创建的触发器data_update_note_content_on_insert_trigger data_update_trigger data_update_note_content_on_delete_trigger
* 这些触发器确保每当在数据表中创建、更新或删除笔记时笔记表中的snippet字段都会被更新。
*/
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);
}
/**
* 这是一个静态方法它返回NotesDatabaseHelper类的单个实例。
* 它将Context对象作为参数并检查NotesDatabaseHelper的实例是否为null。
* 如果实例为null则创建NotesDatabaseHelper类的新实例并返回它。如果实例已经存在则返回现有实例。
* 该方法是同步的,以确保一次只有一个线程可以访问它,避免任何并发问题。
*/
static synchronized NotesDatabaseHelper getInstance(Context context) {
if (mInstance == null) {
mInstance = new NotesDatabaseHelper(context);
}
return mInstance;
}
/**
* 这是NotesDatabaseHelper类中onCreate和onUpgrade方法的实现。
* 第一次创建数据库时调用onCreate
* 它分别使用createNoteTable和createDataTable方法在数据库中创建Note和Data两个表。
* 当数据库需要升级到较新版本时将调用onUpgrade
* 它首先检查数据库的旧版本,并执行必要的升级将其带到新版本。
* 在这个实现中有三个升级步骤从版本1升级到版本2这将删除现有的Note和数据表并使用createNoteTable和createDataTable方法重新创建它们。
* 从版本2升级到版本3这将删除一些未使用的触发器并向Note表添加一个新列gtask_id。它还为回收筒创建一个新的系统文件夹。
* 从版本3升级到版本4这将向注释表添加一个新的列版本。
* 如果在升级步骤中删除了任何触发器则调用reCreateNoteTableTriggers和recreateDatabletriggers方法来重新创建它们。
* 如果升级因某种原因失败将引发IllegalStateException。
*/
@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;
if (oldVersion == 1) {
upgradeToV2(db);
skipV2 = true; // this upgrade including the upgrade from v2 to v3
oldVersion++;
}
if (oldVersion == 2 && !skipV2) {
upgradeToV3(db);
reCreateTriggers = true;
oldVersion++;
}
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
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");
}
}