diff --git a/src/notes/data/NotesDatabaseHelper.java b/src/notes/data/NotesDatabaseHelper.java index f64297b..c6daf1a 100644 --- a/src/notes/data/NotesDatabaseHelper.java +++ b/src/notes/data/NotesDatabaseHelper.java @@ -28,8 +28,16 @@ import net.micode.notes.data.Notes.NoteColumns; /** - * 数据库帮助类,负责数据库的创建、升级和管理 - * 单例模式实现,提供了创建表、管理触发器和系统文件夹的功能 + * 数据库帮助类 (Data Layer - Database Helper) + *
+ * 核心职责: + * 1. 负责 SQLite 数据库的创建与版本升级 (onCreate, onUpgrade)。 + * 2. 定义并维护数据库表结构(便签表、数据表)及索引。 + * 3. 通过 SQL 触发器实现复杂的业务规则,如文件夹计数同步、数据关联删除、内容片段(SNIPPET)自动更新等。 + * 4. 初始化系统文件夹(根目录、通话记录、临时文件夹、回收站)。 + *
+ * 设计模式:采用单例模式,确保全局仅有一个数据库连接实例,避免多线程下的资源竞争和数据不一致。 + * 架构位置:位于数据持久化层,是 {@link NotesProvider} 的底层依赖,为整个应用提供结构化数据存储。 */ public class NotesDatabaseHelper extends SQLiteOpenHelper { /** @@ -38,12 +46,16 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { private static final String DB_NAME = "note.db"; /** - * 数据库版本号 + * 数据库版本号,版本迭代历史详见 {@link #onUpgrade} 方法 */ private static final int DB_VERSION = 4; /** * 数据库表名定义接口 + *
+ * 定义两个核心表: + * 1. {@link #NOTE}:便签元数据表,存储文件夹、标题、时间、类型等信息。 + * 2. {@link #DATA}:便签内容数据表,支持多种 MIME 类型(文本、图片、提醒等)。 */ public interface TABLE { /** @@ -63,10 +75,21 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { private static final String TAG = "NotesDatabaseHelper"; /** - * 单例实例 + * 单例实例,通过 {@link #getInstance(Context)} 获取 */ private static NotesDatabaseHelper mInstance; + /** + * 创建便签表 (note) 的 SQL 语句。 + *
+ * 核心字段说明: + * - {@link NoteColumns#PARENT_ID}: 父文件夹 ID,用于构建树形结构。 + * - {@link NoteColumns#SNIPPET}: 内容摘要,由触发器从 data 表自动同步。 + * - {@link NoteColumns#TYPE}: 区分普通笔记、文件夹、系统文件夹。 + * - {@link NoteColumns#BG_COLOR_ID}: 背景色ID。【2025 AI分类】此字段现用于存储 AI 智能分类结果,实现颜色聚类排序。 + * - {@link NoteColumns#GTASK_ID}: Google 任务同步 ID,用于云端同步。 + * - {@link NoteColumns#VERSION}: 数据版本号,用于乐观锁或同步冲突解决。 + */ private static final String CREATE_NOTE_TABLE_SQL = "CREATE TABLE " + TABLE.NOTE + "(" + NoteColumns.ID + " INTEGER PRIMARY KEY," + @@ -88,6 +111,16 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { NoteColumns.VERSION + " INTEGER NOT NULL DEFAULT 0" + ")"; + /** + * 创建数据表 (data) 的 SQL 语句。 + *
+ * 设计模式:采用 EAV (Entity-Attribute-Value) 变体。 + * 核心字段说明: + * - {@link DataColumns#MIME_TYPE}: 数据类型(如文本、图片、提醒),决定 CONTENT 字段的语义。 + * - {@link DataColumns#NOTE_ID}: 外键,关联到 note 表的 ID。 + * - {@link DataColumns#CONTENT}: 实际数据内容。 + * - DATA1~DATA5: 通用扩展字段,存储整数或文本,具体含义由 MIME_TYPE 决定。 + */ private static final String CREATE_DATA_TABLE_SQL = "CREATE TABLE " + TABLE.DATA + "(" + DataColumns.ID + " INTEGER PRIMARY KEY," + @@ -103,12 +136,17 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { DataColumns.DATA5 + " TEXT NOT NULL DEFAULT ''" + ")"; + /** + * 在 data 表的 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 + ");"; /** - * 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 "+ @@ -120,7 +158,9 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " END"; /** - * Decrease folder's note count when move note from folder + * 触发器:当更新便签的父文件夹时(移动便签),减少旧文件夹的笔记计数。 + *
+ * 防御性编程:确保计数不小于 0。 */ private static final String NOTE_DECREASE_FOLDER_COUNT_ON_UPDATE_TRIGGER = "CREATE TRIGGER decrease_folder_count_on_update " + @@ -133,7 +173,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " 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 " + @@ -145,7 +185,9 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " END"; /** - * Decrease folder's note count when delete note from the folder + * 触发器:当删除便签时,减少其父文件夹的笔记计数。 + *
+ * 防御性编程:确保计数不小于 0。 */ private static final String NOTE_DECREASE_FOLDER_COUNT_ON_DELETE_TRIGGER = "CREATE TRIGGER decrease_folder_count_on_delete " + @@ -158,7 +200,10 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " END"; /** - * Update note's content when insert data with type {@link DataConstants#NOTE} + * 触发器:当在 data 表中插入类型为 {@link DataConstants#NOTE}(文本内容)的数据时, + * 自动更新 note 表中对应便签的 {@link NoteColumns#SNIPPET} 字段。 + *
+ * 业务规则:实现内容与摘要的实时同步,确保列表页能立即显示最新内容。 */ private static final String DATA_UPDATE_NOTE_CONTENT_ON_INSERT_TRIGGER = "CREATE TRIGGER update_note_content_on_insert " + @@ -171,7 +216,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " END"; /** - * Update note's content when data with {@link DataConstants#NOTE} type has changed + * 触发器:当更新 data 表中类型为 {@link DataConstants#NOTE} 的数据时,自动更新对应便签的摘要。 */ private static final String DATA_UPDATE_NOTE_CONTENT_ON_UPDATE_TRIGGER = "CREATE TRIGGER update_note_content_on_update " + @@ -184,7 +229,7 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " END"; /** - * Update note's content when data with {@link DataConstants#NOTE} type has deleted + * 触发器:当删除 data 表中类型为 {@link DataConstants#NOTE} 的数据时,将对应便签的摘要清空。 */ private static final String DATA_UPDATE_NOTE_CONTENT_ON_DELETE_TRIGGER = "CREATE TRIGGER update_note_content_on_delete " + @@ -197,7 +242,10 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " END"; /** - * Delete datas belong to note which has been deleted + * 级联删除触发器:当删除 note 表中的一条记录(一个便签/文件夹)时, + * 自动删除 data 表中所有关联的 ({@link DataColumns#NOTE_ID}) 数据记录。 + *
+ * 数据一致性:确保没有孤儿数据残留,是数据库层面实现的外键级联删除(尽管未使用 FOREIGN KEY 约束)。 */ private static final String NOTE_DELETE_DATA_ON_DELETE_TRIGGER = "CREATE TRIGGER delete_data_on_delete " + @@ -208,7 +256,10 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " END"; /** - * Delete notes belong to folder which has been deleted + * 级联删除触发器:当删除一个文件夹(TYPE 为文件夹)时, + * 自动删除其下的所有子便签(根据 PARENT_ID 匹配)。 + *
+ * 注意:此触发器会与 {@link #NOTE_DELETE_DATA_ON_DELETE_TRIGGER} 形成连锁反应,最终清理所有相关数据。 */ private static final String FOLDER_DELETE_NOTES_ON_DELETE_TRIGGER = "CREATE TRIGGER folder_delete_notes_on_delete " + @@ -219,7 +270,10 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " END"; /** - * Move notes belong to folder which has been moved to trash folder + * 业务规则触发器:当将一个文件夹移动到回收站(其 PARENT_ID 被更新为 {@link Notes#ID_TRASH_FOLER})时, + * 自动将其下的所有子便签的 PARENT_ID 也更新为回收站 ID。 + *
+ * 设计意图:实现“移动文件夹到回收站即移动其全部内容”的用户预期,避免文件夹进入回收站后内容外露。 */ private static final String FOLDER_MOVE_NOTES_ON_TRASH_TRIGGER = "CREATE TRIGGER folder_move_notes_on_trash " + @@ -232,16 +286,23 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { " END"; /** - * 私有构造函数,防止外部实例化 - * @param context 上下文 + * 私有构造函数,强制通过 {@link #getInstance(Context)} 获取单例。 + * + * @param context 应用上下文,用于数据库创建和路径定位。 */ public NotesDatabaseHelper(Context context) { super(context, DB_NAME, null, DB_VERSION); } /** - * 创建笔记表 - * @param db 数据库实例 + * 创建便签表 (note) 及其关联的触发器与系统数据。 + *
+ * 执行步骤: + * 1. 执行建表 SQL。 + * 2. 重建所有业务触发器。 + * 3. 插入四个必需的系统文件夹记录。 + * + * @param db 可写的数据库实例。 */ public void createNoteTable(SQLiteDatabase db) { // 执行创建表SQL @@ -254,8 +315,12 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { } /** - * 重新创建笔记表相关触发器 - * @param db 数据库实例 + * 重建 note 表的所有 SQL 触发器。 + *
+ * 方法逻辑:先删除可能存在的旧触发器,再创建新触发器。 + * 此方法用于保障表结构升级后,触发器逻辑与新版表结构保持一致。 + * + * @param db 可写的数据库实例。 */ private void reCreateNoteTableTriggers(SQLiteDatabase db) { // 删除旧触发器(如果存在) @@ -278,8 +343,15 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { } /** - * 创建系统文件夹 - * @param db 数据库实例 + * 初始化插入系统文件夹记录。 + *
+ * 系统文件夹是应用运行的基础,包括: + * 1. 通话记录文件夹 ({@link Notes#ID_CALL_RECORD_FOLDER}) + * 2. 根文件夹 ({@link Notes#ID_ROOT_FOLDER}):用户看到的默认文件夹。 + * 3. 临时文件夹 ({@link Notes#ID_TEMPARAY_FOLDER}):用于暂存正在移动的便签。 + * 4. 回收站 ({@link Notes#ID_TRASH_FOLER}):存储已删除的便签。 + * + * @param db 可写的数据库实例。 */ private void createSystemFolder(SQLiteDatabase db) { ContentValues values = new ContentValues(); @@ -317,8 +389,9 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { } /** - * 创建数据表 - * @param db 数据库实例 + * 创建数据表 (data) 及其关联的触发器与索引。 + * + * @param db 可写的数据库实例。 */ public void createDataTable(SQLiteDatabase db) { // 执行创建表SQL @@ -331,8 +404,11 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { } /** - * 重新创建数据表相关触发器 - * @param db 数据库实例 + * 重建 data 表的所有 SQL 触发器。 + *
+ * 这些触发器主要负责维护 note 表的 SNIPPET 字段与 data 表 CONTENT 字段的一致性。 + * + * @param db 可写的数据库实例。 */ private void reCreateDataTableTriggers(SQLiteDatabase db) { db.execSQL("DROP TRIGGER IF EXISTS update_note_content_on_insert"); @@ -345,9 +421,12 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { } /** - * 获取单例实例 - * @param context 上下文 - * @return 数据库帮助类实例 + * 获取数据库帮助类的全局单例实例。 + *
+ * 线程安全:通过 synchronized 方法确保多线程环境下仅创建一个实例。 + * + * @param context 应用上下文。 + * @return NotesDatabaseHelper 的单例实例。 */ static synchronized NotesDatabaseHelper getInstance(Context context) { if (mInstance == null) { @@ -357,8 +436,11 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { } /** - * 创建数据库 - * @param db 数据库实例 + * 数据库首次创建时回调。 + *
+ * 执行顺序:先创建 note 表(含系统文件夹),再创建 data 表。 + * + * @param db 数据库实例。 */ @Override public void onCreate(SQLiteDatabase db) { @@ -369,38 +451,48 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { } /** - * 升级数据库 - * @param db 数据库实例 - * @param oldVersion 旧版本号 - * @param newVersion 新版本号 + * 数据库版本升级时回调。 + *
+ * 升级策略:采用递进式升级,每个版本号对应一个升级方法。 + * 注意处理跨版本升级(如从v1直接升到v4)的路径。 + * + * @param db 可写的数据库实例。 + * @param oldVersion 当前设备上的旧数据库版本。 + * @param newVersion 目标新版本({@link #DB_VERSION})。 + * @throws IllegalStateException 如果升级路径无法处理,将抛出此异常。 */ @Override public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { boolean reCreateTriggers = false; boolean skipV2 = false; + // 1. 从版本1升级 if (oldVersion == 1) { upgradeToV2(db); skipV2 = true; // this upgrade including the upgrade from v2 to v3 oldVersion++; } + // 2. 从版本2升级(如果未跳过) if (oldVersion == 2 && !skipV2) { upgradeToV3(db); reCreateTriggers = true; oldVersion++; } + // 3. 从版本3升级 if (oldVersion == 3) { upgradeToV4(db); oldVersion++; } + // 4. 如果表结构在v3升级中发生较大变更,需要重建触发器以确保兼容性 if (reCreateTriggers) { reCreateNoteTableTriggers(db); reCreateDataTableTriggers(db); } + // 5. 最终版本校验:确保所有升级步骤已执行完毕 if (oldVersion != newVersion) { throw new IllegalStateException("Upgrade notes database to version " + newVersion + "fails"); @@ -408,8 +500,13 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { } /** - * 升级到版本2 - * @param db 数据库实例 + * 升级数据库到版本 2。 + *
+ * 升级方式:激进式重构。直接删除旧表,然后调用 {@link #onCreate} 重建全新表结构。 + * 适用场景:早期版本表结构不稳定或存在重大设计缺陷时使用。 + * 副作用:所有用户数据将被清空! + * + * @param db 可写的数据库实例。 */ private void upgradeToV2(SQLiteDatabase db) { db.execSQL("DROP TABLE IF EXISTS " + TABLE.NOTE); @@ -419,8 +516,15 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { } /** - * 升级到版本3 - * @param db 数据库实例 + * 升级数据库到版本 3。 + *
+ * 升级方式:渐进式迁移 (ALTER TABLE)。 + * 主要变更: + * 1. 移除过时的修改日期触发器(其逻辑已整合到表定义默认值中)。 + * 2. 增加 Google 任务同步 ID 字段 ({@link NoteColumns#GTASK_ID})。 + * 3. 新增“回收站”系统文件夹。 + * + * @param db 可写的数据库实例。 */ private void upgradeToV3(SQLiteDatabase db) { // drop unused triggers @@ -438,11 +542,17 @@ public class NotesDatabaseHelper extends SQLiteOpenHelper { } /** - * 升级到版本4 - * @param db 数据库实例 + * 升级数据库到版本 4。 + *
+ * 升级方式:渐进式迁移。 + * 主要变更:增加数据版本字段 ({@link NoteColumns#VERSION})。 + *
+ * 设计意图:为未来可能的数据同步冲突解决(乐观锁)或更精细的增量同步提供基础。
+ *
+ * @param db 可写的数据库实例。
*/
private void upgradeToV4(SQLiteDatabase db) {
db.execSQL("ALTER TABLE " + TABLE.NOTE + " ADD COLUMN " + NoteColumns.VERSION
+ " INTEGER NOT NULL DEFAULT 0");
}
-}
+}
\ No newline at end of file
diff --git a/src/notes/gtask/remote/GTaskClient.java b/src/notes/gtask/remote/GTaskClient.java
index a10ffe1..71b180c 100644
--- a/src/notes/gtask/remote/GTaskClient.java
+++ b/src/notes/gtask/remote/GTaskClient.java
@@ -324,28 +324,21 @@ public class GTaskClient {
Log.d(TAG, "encoding: " + contentEncoding);
}
- InputStream input = entity.getContent();
- if (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip")) {
- input = new GZIPInputStream(entity.getContent());
- } else if (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate")) {
- Inflater inflater = new Inflater(true);
- input = new InflaterInputStream(entity.getContent(), inflater);
- }
-
- try {
- InputStreamReader isr = new InputStreamReader(input);
- BufferedReader br = new BufferedReader(isr);
+ try (InputStream input = entity.getContent();
+ InputStream finalInput = (contentEncoding != null && contentEncoding.equalsIgnoreCase("gzip"))
+ ? new GZIPInputStream(input)
+ : (contentEncoding != null && contentEncoding.equalsIgnoreCase("deflate"))
+ ? new InflaterInputStream(input, new Inflater(true))
+ : input;
+ InputStreamReader isr = new InputStreamReader(finalInput);
+ BufferedReader br = new BufferedReader(isr)) {
+
StringBuilder sb = new StringBuilder();
-
- while (true) {
- String buff = br.readLine();
- if (buff == null) {
- return sb.toString();
- }
- sb = sb.append(buff);
+ String buff;
+ while ((buff = br.readLine()) != null) {
+ sb.append(buff);
}
- } finally {
- input.close();
+ return sb.toString();
}
}
diff --git a/src/notes/tool/BackupUtils.java b/src/notes/tool/BackupUtils.java
index b869743..e853810 100644
--- a/src/notes/tool/BackupUtils.java
+++ b/src/notes/tool/BackupUtils.java
@@ -236,67 +236,69 @@ public class BackupUtils {
return STATE_SD_CARD_UNMOUONTED;
}
- // 获取输出流
- PrintStream ps = getExportToTextPrintStream();
- if (ps == null) {
- Log.e(TAG, "get print stream error");
- return STATE_SYSTEM_ERROR;
- }
-
- // 第一部分:导出文件夹及其中的笔记
- // 查询所有文件夹(排除回收站,但包含通话记录文件夹)
- Cursor folderCursor = mContext.getContentResolver().query(
- Notes.CONTENT_NOTE_URI,
- NOTE_PROJECTION,
- "(" + NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + " AND "
- + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + ") OR "
- + NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER, null, null);
-
- if (folderCursor != null) {
- if (folderCursor.moveToFirst()) {
- do {
- // 输出文件夹名称
- String folderName = "";
- if(folderCursor.getLong(NOTE_COLUMN_ID) == Notes.ID_CALL_RECORD_FOLDER) {
- folderName = mContext.getString(R.string.call_record_folder_name);
- } else {
- folderName = folderCursor.getString(NOTE_COLUMN_SNIPPET);
- }
- if (!TextUtils.isEmpty(folderName)) {
- ps.println(String.format(getFormat(FORMAT_FOLDER_NAME), folderName));
- }
- // 导出该文件夹下的所有笔记
- String folderId = folderCursor.getString(NOTE_COLUMN_ID);
- exportFolderToText(folderId, ps);
- } while (folderCursor.moveToNext());
+ // 使用try-with-resources自动关闭输出流
+ try (PrintStream ps = getExportToTextPrintStream()) {
+ if (ps == null) {
+ Log.e(TAG, "get print stream error");
+ return STATE_SYSTEM_ERROR;
}
- folderCursor.close();
- }
- // 第二部分:导出根目录下的笔记(不属于任何文件夹的笔记)
- Cursor noteCursor = mContext.getContentResolver().query(
- Notes.CONTENT_NOTE_URI,
- NOTE_PROJECTION,
- NoteColumns.TYPE + "=" + +Notes.TYPE_NOTE + " AND " + NoteColumns.PARENT_ID
- + "=0", null, null);
+ // 第一部分:导出文件夹及其中的笔记
+ // 查询所有文件夹(排除回收站,但包含通话记录文件夹)
+ Cursor folderCursor = mContext.getContentResolver().query(
+ Notes.CONTENT_NOTE_URI,
+ NOTE_PROJECTION,
+ "(" + NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER + " AND "
+ + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER + ") OR "
+ + NoteColumns.ID + "=" + Notes.ID_CALL_RECORD_FOLDER, null, null);
+
+ if (folderCursor != null) {
+ if (folderCursor.moveToFirst()) {
+ do {
+ // 输出文件夹名称
+ String folderName = "";
+ if(folderCursor.getLong(NOTE_COLUMN_ID) == Notes.ID_CALL_RECORD_FOLDER) {
+ folderName = mContext.getString(R.string.call_record_folder_name);
+ } else {
+ folderName = folderCursor.getString(NOTE_COLUMN_SNIPPET);
+ }
+ if (!TextUtils.isEmpty(folderName)) {
+ ps.println(String.format(getFormat(FORMAT_FOLDER_NAME), folderName));
+ }
+ // 导出该文件夹下的所有笔记
+ String folderId = folderCursor.getString(NOTE_COLUMN_ID);
+ exportFolderToText(folderId, ps);
+ } while (folderCursor.moveToNext());
+ }
+ folderCursor.close();
+ }
- if (noteCursor != null) {
- if (noteCursor.moveToFirst()) {
- do {
- ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format(
- mContext.getString(R.string.format_datetime_mdhm),
- noteCursor.getLong(NOTE_COLUMN_MODIFIED_DATE))));
- // 导出该笔记的内容
- String noteId = noteCursor.getString(NOTE_COLUMN_ID);
- exportNoteToText(noteId, ps);
- } while (noteCursor.moveToNext());
+ // 第二部分:导出根目录下的笔记(不属于任何文件夹的笔记)
+ Cursor noteCursor = mContext.getContentResolver().query(
+ Notes.CONTENT_NOTE_URI,
+ NOTE_PROJECTION,
+ NoteColumns.TYPE + "=" + +Notes.TYPE_NOTE + " AND " + NoteColumns.PARENT_ID
+ + "=0", null, null);
+
+ if (noteCursor != null) {
+ if (noteCursor.moveToFirst()) {
+ do {
+ ps.println(String.format(getFormat(FORMAT_NOTE_DATE), DateFormat.format(
+ mContext.getString(R.string.format_datetime_mdhm),
+ noteCursor.getLong(NOTE_COLUMN_MODIFIED_DATE))));
+ // 导出该笔记的内容
+ String noteId = noteCursor.getString(NOTE_COLUMN_ID);
+ exportNoteToText(noteId, ps);
+ } while (noteCursor.moveToNext());
+ }
+ noteCursor.close();
}
- noteCursor.close();
- }
- // 关闭输出流
- ps.close();
- return STATE_SUCCESS;
+ return STATE_SUCCESS;
+ } catch (Exception e) {
+ Log.e(TAG, "Export text failed: " + e.getMessage());
+ return STATE_SYSTEM_ERROR;
+ }
}
/**
diff --git a/src/notes/tool/DataUtils.java b/src/notes/tool/DataUtils.java
index b4cdb3d..a0aa76f 100644
--- a/src/notes/tool/DataUtils.java
+++ b/src/notes/tool/DataUtils.java
@@ -153,15 +153,10 @@ public class DataUtils {
int count = 0;
if(cursor != null) {
- if(cursor.moveToFirst()) {
- try {
- count = cursor.getInt(0); // 获取计数结果
- } catch (IndexOutOfBoundsException e) {
- Log.e(TAG, "get folder count failed:" + e.toString());
- } finally {
- cursor.close();
- }
+ if(cursor.moveToFirst() && cursor.getColumnCount() > 0) {
+ count = cursor.getInt(0); // 获取计数结果
}
+ cursor.close();
}
return count;
}
@@ -181,14 +176,14 @@ public class DataUtils {
new String [] {String.valueOf(type)},
null);
- boolean exist = false;
+ boolean exists = false;
if (cursor != null) {
if (cursor.getCount() > 0) { // 如果查询结果数量大于0,则表示存在
- exist = true;
+ exists = true;
}
cursor.close();
}
- return exist;
+ return exists;
}
/**
@@ -202,14 +197,14 @@ public class DataUtils {
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId),
null, null, null, null);
- boolean exist = false;
+ boolean exists = false;
if (cursor != null) {
if (cursor.getCount() > 0) {
- exist = true;
+ exists = true;
}
cursor.close();
}
- return exist;
+ return exists;
}
/**
@@ -223,14 +218,14 @@ public class DataUtils {
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId),
null, null, null, null);
- boolean exist = false;
+ boolean exists = false;
if (cursor != null) {
if (cursor.getCount() > 0) {
- exist = true;
+ exists = true;
}
cursor.close();
}
- return exist;
+ return exists;
}
/**
@@ -246,14 +241,14 @@ public class DataUtils {
" AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER +
" AND " + NoteColumns.SNIPPET + "=?",
new String[] { name }, null);
- boolean exist = false;
+ boolean exists = false;
if(cursor != null) {
if(cursor.getCount() > 0) {
- exist = true;
+ exists = true;
}
cursor.close();
}
- return exist;
+ return exists;
}
/**
@@ -275,13 +270,12 @@ public class DataUtils {
if (c.moveToFirst()) {
set = new HashSet