From 3c27d63f2aecb31398cc1005e542439690b7ceb8 Mon Sep 17 00:00:00 2001 From: phbaois7m <1404345300@qq.com> Date: Sat, 21 Dec 2024 21:30:55 +0800 Subject: [PATCH] Update Note.java --- .../src/net/micode/notes/model/Note.java | 320 ++++++++++++------ 1 file changed, 221 insertions(+), 99 deletions(-) diff --git a/src/Notes-master/src/net/micode/notes/model/Note.java b/src/Notes-master/src/net/micode/notes/model/Note.java index 6706cf6..fc61928 100644 --- a/src/Notes-master/src/net/micode/notes/model/Note.java +++ b/src/Notes-master/src/net/micode/notes/model/Note.java @@ -1,20 +1,7 @@ -/* - * 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.model; + import android.content.ContentProviderOperation; import android.content.ContentProviderResult; import android.content.ContentUris; @@ -30,95 +17,158 @@ import net.micode.notes.data.Notes.CallNote; import net.micode.notes.data.Notes.DataColumns; import net.micode.notes.data.Notes.NoteColumns; import net.micode.notes.data.Notes.TextNote; - -import java.util.ArrayList; - - +import java.util.ArrayList;// 定义Note类,用于处理笔记相关的操作 public class Note { + // 用于存储笔记的差异值(以ContentValues的形式) private ContentValues mNoteDiffValues; + // 包含笔记具体数据的对象,内部类NoteData的实例 private NoteData mNoteData; + // 用于日志记录的标签,方便在Log输出中识别是这个类相关的日志信息 private static final String TAG = "Note"; + /** - * Create a new note id for adding a new note to databases + * 创建一个新的笔记ID,用于向数据库中添加新笔记。 + * 同步方法,确保在多线程环境下同时调用时的线程安全。 + * @param context 应用上下文,用于获取ContentResolver等操作数据库相关的对象 + * @param folderId 笔记所属文件夹的ID,用于指定新笔记所在的文件夹 + * @return 返回新创建笔记的ID,如果创建失败则返回0,若获取ID格式转换出错等情况也返回0 */ public static synchronized long getNewNoteId(Context context, long folderId) { - // Create a new note in the database + // 创建一个ContentValues对象,用于存放要插入数据库的笔记数据 ContentValues values = new ContentValues(); + // 获取当前系统时间的毫秒数,作为笔记的创建时间和初始修改时间 long createdTime = System.currentTimeMillis(); + // 将创建时间放入ContentValues中,对应数据库中笔记的创建日期字段 values.put(NoteColumns.CREATED_DATE, createdTime); + // 将创建时间同样放入修改日期字段,初始创建时修改时间和创建时间相同 values.put(NoteColumns.MODIFIED_DATE, createdTime); + // 设置笔记的类型,通用类型(根据Notes.TYPE_NOTE的定义) values.put(NoteColumns.TYPE, Notes.TYPE_NOTE); + // 标记笔记在本地被修改过,判断是否同步等操作 values.put(NoteColumns.LOCAL_MODIFIED, 1); + // 设置笔记所属的父文件夹ID,即与传入的folderId关联 values.put(NoteColumns.PARENT_ID, folderId); + + // 通过ContentResolver向指定的笔记内容URI插入数据,获取插入后返回的Uri Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values); long noteId = 0; try { + // 尝试从返回的Uri中获取路径片段中的第二个元素,并转换为长整型 noteId = Long.valueOf(uri.getPathSegments().get(1)); } catch (NumberFormatException e) { + // 如果转换出错,记录错误日志,并将noteId设为0 Log.e(TAG, "Get note id error :" + e.toString()); noteId = 0; } if (noteId == -1) { + // 如果获取到的笔记ID为 -1,抛出异常,表示出现错误的笔记ID throw new IllegalStateException("Wrong note id:" + noteId); } return noteId; } + // Note类的构造函数,初始化用于存储笔记差异值和笔记数据的对象 public Note() { mNoteDiffValues = new ContentValues(); mNoteData = new NoteData(); } + /** + * 设置笔记的某个值,同时更新本地修改标记以及修改日期。 + * @param key 要设置的属性的键 + * @param value 要设置的属性的值 + */ public void setNoteValue(String key, String value) { mNoteDiffValues.put(key, value); mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1); mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); } + /** + * 设置文本数据的某个属性值 + * 调用内部类NoteData的相应方法来设置 + * + * @param key 文本数据属性的键 + * @param value 文本数据属性的值 + */ public void setTextData(String key, String value) { mNoteData.setTextData(key, value); } + /** + * 设置文本数据的ID,通过内部类NoteData来设置。 + * + * @param id 文本数据的ID + */ public void setTextDataId(long id) { mNoteData.setTextDataId(id); } + /** + * 获取文本数据的ID,返回内部类NoteData中存储的文本数据ID。 + * + * @return 文本数据的ID + */ public long getTextDataId() { return mNoteData.mTextDataId; } + /** + * 设置通话数据的ID,通过内部类NoteData来设置 + * + * @param id 通话数据的ID + */ public void setCallDataId(long id) { mNoteData.setCallDataId(id); } + /** + * 设置通话数据的某个属性值 + * 调用内部类NoteData的相应方法来设置,同时更新本地修改标记以及修改日期。 + * + / public void setCallData(String key, String value) { mNoteData.setCallData(key, value); } + /** + * 判断笔记是否在本地被修改过,通过检查笔记差异值对象以及内部类NoteData中存储的数据是否有变化来判断。 + * + * @return 如果笔记差异值对象有内容或者NoteData中数据有变化则返回true,表示本地被修改过,否则返回false + */ public boolean isLocalModified() { return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified(); } + /** + * 同步笔记数据到相应的存储(比如数据库等)。 + * + * @param context 应用上下文,用于获取ContentResolver等操作数据库相关的对象 + * @param noteId 要同步的笔记的ID + * @return 如果同步成功(包括更新笔记基本信息和相关数据都成功)则返回true,否则返回false + */ public boolean syncNote(Context context, long noteId) { if (noteId <= 0) { + // 如果传入的笔记ID小于等于0,抛出异常,因不符合正常的笔记ID规范 throw new IllegalArgumentException("Wrong note id:" + noteId); } if (!isLocalModified()) { + // 如果笔记没有在本地被修改过,直接返回true return true; } /** - * In theory, once data changed, the note should be updated on {@link NoteColumns#LOCAL_MODIFIED} and - * {@link NoteColumns#MODIFIED_DATE}. For data safety, though update note fails, we also update the - * note data info + * 一旦数据发生变化,笔记应该在{@link NoteColumns#LOCAL_MODIFIED}和 + * {@link NoteColumns#MODIFIED_DATE}字段上进行更新。为了数据安全考虑,即使更新笔记基本信息失败, + * 我们也要更新笔记的数据信息(通过内部类NoteData相关操作) */ if (context.getContentResolver().update( ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), mNoteDiffValues, null, null) == 0) { Log.e(TAG, "Update note error, should not happen"); - // Do not return, fall through + // 即使更新失败,也不直接返回,继续往下执行,尝试更新笔记相关的数据信息 } mNoteDiffValues.clear(); @@ -130,17 +180,20 @@ public class Note { return true; } + // 定义内部类NoteData,用于管理笔记相关的具体数据,比如文本数据、通话数据等 private class NoteData { + // 存储文本数据的ID private long mTextDataId; - + // 用于存储文本数据的ContentValues对象,可能包含文本相关的各种属性值 private ContentValues mTextDataValues; - + // 存储通话数据的ID private long mCallDataId; - + // 用于存储通话数据的ContentValues对象,可能包含通话相关的各种属性值 private ContentValues mCallDataValues; - + // 用于日志记录的标签,方便在Log输出中识别是这个内部类相关的日志信息 private static final String TAG = "NoteData"; + // NoteData类的构造函数,初始化文本数据和通话数据相关的对象以及ID为默认值 public NoteData() { mTextDataValues = new ContentValues(); mCallDataValues = new ContentValues(); @@ -148,17 +201,32 @@ public class Note { mCallDataId = 0; } + /** + * 判断文本数据或者通话数据是否有本地修改,通过检查对应ContentValues对象是否有内容来判断。 + * + * @return 如果文本数据或者通话数据对应的ContentValues对象有内容,则返回true,表示有本地修改,否则返回false + */ boolean isLocalModified() { return mTextDataValues.size() > 0 || mCallDataValues.size() > 0; } + /** + * 设置文本数据的ID,同时进行参数合法性检查,如果ID小于等于0则抛出异常。 + * + * @param id 要设置的文本数据的ID + */ void setTextDataId(long id) { - if(id <= 0) { + if (id <= 0) { throw new IllegalArgumentException("Text data id should larger than 0"); } mTextDataId = id; } + /** + * 设置通话数据的ID,同时进行参数合法性检查,如果ID小于等于0则抛出异常。 + * + * @param id 要设置的通话数据的ID + */ void setCallDataId(long id) { if (id <= 0) { throw new IllegalArgumentException("Call data id should larger than 0"); @@ -166,88 +234,142 @@ public class Note { mCallDataId = id; } + /** + * 设置通话数据的某个属性值,同时更新笔记的本地修改标记以及修改日期(通过外部类的mNoteDiffValues对象)。 + * + + */ void setCallData(String key, String value) { mCallDataValues.put(key, value); mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1); mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); } - void setTextData(String key, String value) { - mTextDataValues.put(key, value); - mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1); - mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis()); - } - + /** + * 设置文本数据的某个属性值,同时更新笔记的本地修改标记以及修改日期(通过外部类的mNoteDiffValues对象)。 + * + + /** + * 将笔记相关的数据(文本数据、通话数据等)推送到ContentResolver中,可能是用于更新或插入到数据库等存储中。 + * + * @param context 应用上下文,用于获取ContentResolver等操作数据库相关的对象 + * @param noteId 笔记的ID,用于关联数据和对应的笔记 + * @return 如果操作成功,返回对应的笔记的URI(更新后的笔记在数据库中的位置标识),否则返回null + */ Uri pushIntoContentResolver(Context context, long noteId) { /** - * Check for safety + * 进行参数合法性检查,如果笔记ID小于等于0则抛出异常,因为无法针对非法的笔记ID进行数据操作。 */ - if (noteId <= 0) { - throw new IllegalArgumentException("Wrong note id:" + noteId); - } + // 首先检查笔记ID是否合法,如果小于等于0则抛出异常,因为合法的笔记ID应该是大于0的正整数 +if (noteId <= 0) { + throw new IllegalArgumentException("Wrong note id:" + noteId); +} - ArrayList operationList = new ArrayList(); - ContentProviderOperation.Builder builder = null; - - if(mTextDataValues.size() > 0) { - mTextDataValues.put(DataColumns.NOTE_ID, noteId); - if (mTextDataId == 0) { - mTextDataValues.put(DataColumns.MIME_TYPE, TextNote.CONTENT_ITEM_TYPE); - Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI, - mTextDataValues); - try { - setTextDataId(Long.valueOf(uri.getPathSegments().get(1))); - } catch (NumberFormatException e) { - Log.e(TAG, "Insert new text data fail with noteId" + noteId); - mTextDataValues.clear(); - return null; - } - } else { - builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId( - Notes.CONTENT_DATA_URI, mTextDataId)); - builder.withValues(mTextDataValues); - operationList.add(builder.build()); - } - mTextDataValues.clear(); - } +// 创建一个用于存储ContentProviderOperation的列表,这个列表将用于批量操作数据库相关的事务 +// 例如批量插入、更新等操作,后续会往这个列表中添加具体的操作对象 +ArrayList operationList = new ArrayList(); +// 初始化一个ContentProviderOperation的构建器为null,后续根据不同情况来创建和配置它 +ContentProviderOperation.Builder builder = null; - if(mCallDataValues.size() > 0) { - mCallDataValues.put(DataColumns.NOTE_ID, noteId); - if (mCallDataId == 0) { - mCallDataValues.put(DataColumns.MIME_TYPE, CallNote.CONTENT_ITEM_TYPE); - Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI, - mCallDataValues); - try { - setCallDataId(Long.valueOf(uri.getPathSegments().get(1))); - } catch (NumberFormatException e) { - Log.e(TAG, "Insert new call data fail with noteId" + noteId); - mCallDataValues.clear(); - return null; - } - } else { - builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId( - Notes.CONTENT_DATA_URI, mCallDataId)); - builder.withValues(mCallDataValues); - operationList.add(builder.build()); - } - mCallDataValues.clear(); - } +// 检查文本数据相关的ContentValues对象是否有内容(即是否有需要处理的文本数据) +if (mTextDataValues.size() > 0) { + // 将当前笔记的ID添加到文本数据的ContentValues中,用于关联文本数据和对应的笔记 + mTextDataValues.put(DataColumns.NOTE_ID, noteId); - if (operationList.size() > 0) { - try { - ContentProviderResult[] results = context.getContentResolver().applyBatch( - Notes.AUTHORITY, operationList); - return (results == null || results.length == 0 || results[0] == null) ? null - : ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId); - } catch (RemoteException e) { - Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); - return null; - } catch (OperationApplicationException e) { - Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); - return null; - } - } + // 如果文本数据的ID为0,意味着可能是新的文本数据,需要执行插入操作 + if (mTextDataId == 0) { + // 设置文本数据的MIME类型,表明这是文本笔记类型的数据(根据TextNote.CONTENT_ITEM_TYPE的定义) + mTextDataValues.put(DataColumns.MIME_TYPE, TextNote.CONTENT_ITEM_TYPE); + + // 通过ContentResolver向指定的笔记数据内容URI插入文本数据,并获取插入后返回的Uri + Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI, + mTextDataValues); + + try { + // 尝试从返回的Uri中获取路径片段中的第二个元素(假设其为新插入文本数据的ID,具体格式由URI相关规则决定)并转换为长整型,然后设置为文本数据的ID + setTextDataId(Long.valueOf(uri.getPathSegments().get(1))); + } catch (NumberFormatException e) { + // 如果转换过程中出现数字格式异常,记录错误日志,表明插入新文本数据失败,并清空文本数据的ContentValues对象,避免后续错误使用这些数据 + Log.e(TAG, "Insert new text data fail with noteId" + noteId); + mTextDataValues.clear(); + // 由于插入失败,返回null表示操作不成功 + return null; + } + } else { + // 如果文本数据的ID不为0,说明是已存在的文本数据,需要执行更新操作 + // 创建一个ContentProviderOperation的更新构建器,指定要更新的内容的URI(通过笔记数据的ID来构建) + builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId( + Notes.CONTENT_DATA_URI, mTextDataId)); + // 将文本数据的ContentValues对象中的值设置到构建器中,用于更新操作 + builder.withValues(mTextDataValues); + // 将构建好的更新操作添加到操作列表中,后续会批量执行这些操作 + operationList.add(builder.build()); + } + // 无论插入还是更新操作完成后,清空文本数据的ContentValues对象,准备下次使用(避免数据残留导致问题) + mTextDataValues.clear(); +} + +// 检查通话数据相关的ContentValues对象是否有内容(即是否有需要处理的通话数据) +if (mCallDataValues.size() > 0) { + // 将当前笔记的ID添加到通话数据的ContentValues中,用于关联通话数据和对应的笔记 + mCallDataValues.put(DataColumns.NOTE_ID, noteId); + + // 如果通话数据的ID为0,意味着可能是新的通话数据,需要执行插入操作 + if (mCallDataId == 0) { + // 设置通话数据的MIME类型,表明这是通话笔记类型的数据(根据CallNote.CONTENT_ITEM_TYPE的定义) + mCallDataValues.put(DataColumns.MIME_TYPE, CallNote.CONTENT_ITEM_TYPE); + + // 通过ContentResolver向指定的笔记数据内容URI插入通话数据,并获取插入后返回的Uri + Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI, + mCallDataValues); + + try { + // 尝试从返回的Uri中获取路径片段中的第二个元素(假设其为新插入通话数据的ID,具体格式由URI相关规则决定)并转换为长整型,然后设置为通话数据的ID + setCallDataId(Long.valueOf(uri.getPathSegments().get(1))); + } catch (NumberFormatException e) { + // 如果转换过程中出现数字格式异常,记录错误日志,表明插入新通话数据失败,并清空通话数据的ContentValues对象,避免后续错误使用这些数据 + Log.e(TAG, "Insert new call data fail with noteId" + noteId); + mCallDataValues.clear(); + // 由于插入失败,返回null表示操作不成功 return null; } + } else { + // 如果通话数据的ID不为0,说明是已存在的通话数据,需要执行更新操作 + // 创建一个ContentProviderOperation的更新构建器,指定要更新的内容的URI(通过通话数据的ID来构建) + builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId( + Notes.CONTENT_DATA_URI, mCallDataId)); + // 将通话数据的ContentValues对象中的值设置到构建器中,用于更新操作 + builder.withValues(mCallDataValues); + // 将构建好的更新操作添加到操作列表中,后续会批量执行这些操作 + operationList.add(builder.build()); } + // 无论插入还是更新操作完成后,清空通话数据的ContentValues对象,准备下次使用(避免数据残留导致问题) + mCallDataValues.clear(); } + +// 检查操作列表中是否有需要执行的操作(即是否添加了文本数据或通话数据的插入、更新操作) +if (operationList.size() > 0) { + try { + // 通过ContentResolver批量执行操作列表中的所有ContentProviderOperation操作,并获取操作结果数组 + ContentProviderResult[] results = context.getContentResolver().applyBatch( + Notes.AUTHORITY, operationList); + + // 根据操作结果进行判断,如果结果数组为null或者长度为0或者第一个结果为null,说明操作可能出现问题,返回null表示操作不成功 + // 否则,返回通过笔记ID构建的对应笔记的URI,表示操作成功(可能用于后续关联等操作) + return (results == null || results.length == 0 || results[0] == null)? null + : ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId); + } catch (RemoteException e) { + // 如果在批量执行操作过程中出现远程异常,记录错误日志,包含异常的toString和详细消息内容 + Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); + // 返回null表示操作因异常而失败 + return null; + } catch (OperationApplicationException e) { + // 如果在应用操作过程中出现异常(比如操作本身不符合规则等问题),记录错误日志,包含异常的toString和详细消息内容 + Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage())); + // 返回null表示操作因异常而失败 + return null; + } +} + +// 如果操作列表中没有需要执行的操作,直接返回null,表示没有进行任何有效的数据推送操作 +return null; \ No newline at end of file