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.
pyx_gitpractice/src/Model/Note.java

390 lines
15 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.model;
import android.content.ContentProviderOperation;
import android.content.ContentProviderResult;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Context;
import android.content.OperationApplicationException;
import android.net.Uri;
import android.os.RemoteException;
import android.util.Log;
import net.micode.notes.data.Notes;
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;
/**
* 该类表示一个笔记对象,用于管理笔记的各种属性和数据,
* 包括笔记的基本信息(如创建时间、修改时间等)以及笔记的文本数据和通话数据。
*/
public class Note {
// 用于存储笔记的差异值,即笔记有改动的属性值
private ContentValues mNoteDiffValues;
// 用于存储笔记的数据,包括文本数据和通话数据
private NoteData mNoteData;
// 日志标签,用于在日志中标识该类的信息
private static final String TAG = "Note";
/**
* 创建一个新的笔记 ID用于向数据库中添加新笔记。
*
* @param context 应用程序上下文,用于访问内容解析器
* @param folderId 笔记所属文件夹的 ID
* @return 新创建的笔记的 ID
*/
public static synchronized long getNewNoteId(Context context, long folderId) {
// 创建一个新的 ContentValues 对象,用于存储要插入数据库的笔记信息
ContentValues values = new ContentValues();
// 获取当前时间作为笔记的创建时间
long createdTime = System.currentTimeMillis();
// 将创建时间添加到 ContentValues 中
values.put(NoteColumns.CREATED_DATE, createdTime);
// 将修改时间设置为创建时间,因为是新创建的笔记
values.put(NoteColumns.MODIFIED_DATE, createdTime);
// 设置笔记的类型为普通笔记
values.put(NoteColumns.TYPE, Notes.TYPE_NOTE);
// 标记笔记为本地已修改
values.put(NoteColumns.LOCAL_MODIFIED, 1);
// 设置笔记所属文件夹的 ID
values.put(NoteColumns.PARENT_ID, folderId);
// 使用内容解析器插入新笔记,并获取插入后的 URI
Uri uri = context.getContentResolver().insert(Notes.CONTENT_NOTE_URI, values);
long noteId = 0;
try {
// 从 URI 中提取笔记的 ID
noteId = Long.valueOf(uri.getPathSegments().get(1));
} catch (NumberFormatException e) {
// 若提取 ID 时出现异常,记录错误日志
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;
}
/**
* 构造函数,初始化笔记的差异值和笔记数据对象。
*/
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());
}
/**
* 设置笔记的文本数据的属性值。
*
* @param key 属性名
* @param value 属性值
*/
public void setTextData(String key, String value) {
mNoteData.setTextData(key, value);
}
/**
* 设置笔记的文本数据的 ID。
*
* @param id 文本数据的 ID
*/
public void setTextDataId(long id) {
mNoteData.setTextDataId(id);
}
/**
* 获取笔记的文本数据的 ID。
*
* @return 文本数据的 ID
*/
public long getTextDataId() {
return mNoteData.mTextDataId;
}
/**
* 设置笔记的通话数据的 ID。
*
* @param id 通话数据的 ID
*/
public void setCallDataId(long id) {
mNoteData.setCallDataId(id);
}
/**
* 设置笔记的通话数据的属性值。
*
* @param key 属性名
* @param value 属性值
*/
public void setCallData(String key, String value) {
mNoteData.setCallData(key, value);
}
/**
* 判断笔记是否被本地修改过。
*
* @return 若笔记被本地修改过返回 true否则返回 false
*/
public boolean isLocalModified() {
return mNoteDiffValues.size() > 0 || mNoteData.isLocalModified();
}
/**
* 将笔记的修改同步到数据库中。
*
* @param context 应用程序上下文,用于访问内容解析器
* @param noteId 笔记的 ID
* @return 若同步成功返回 true否则返回 false
*/
public boolean syncNote(Context context, long noteId) {
if (noteId <= 0) {
// 若笔记 ID 不合法,抛出异常
throw new IllegalArgumentException("Wrong note id:" + noteId);
}
if (!isLocalModified()) {
// 若笔记未被修改,直接返回 true
return true;
}
/**
* 理论上,一旦数据发生变化,笔记的 LOCAL_MODIFIED 和 MODIFIED_DATE 应该被更新。
* 为了数据安全,即使更新笔记失败,我们也会更新笔记的数据信息。
*/
if (context.getContentResolver().update(
ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId), mNoteDiffValues, null,
null) == 0) {
// 若更新笔记失败,记录错误日志
Log.e(TAG, "Update note error, should not happen");
// 不返回,继续执行后续操作
}
// 清空笔记的差异值
mNoteDiffValues.clear();
if (mNoteData.isLocalModified()
&& (mNoteData.pushIntoContentResolver(context, noteId) == null)) {
// 若笔记数据被修改且同步失败,返回 false
return false;
}
return true;
}
/**
* 内部类,用于管理笔记的数据,包括文本数据和通话数据。
*/
private class NoteData {
// 文本数据的 ID
private long mTextDataId;
// 存储文本数据的 ContentValues 对象
private ContentValues mTextDataValues;
// 通话数据的 ID
private long mCallDataId;
// 存储通话数据的 ContentValues 对象
private ContentValues mCallDataValues;
// 日志标签,用于在日志中标识该内部类的信息
private static final String TAG = "NoteData";
/**
* 构造函数,初始化文本数据和通话数据的 ContentValues 对象,以及 ID 为 0。
*/
public NoteData() {
mTextDataValues = new ContentValues();
mCallDataValues = new ContentValues();
mTextDataId = 0;
mCallDataId = 0;
}
/**
* 判断笔记数据是否被本地修改过。
*
* @return 若笔记数据被本地修改过返回 true否则返回 false
*/
boolean isLocalModified() {
return mTextDataValues.size() > 0 || mCallDataValues.size() > 0;
}
/**
* 设置笔记的文本数据的 ID。
*
* @param id 文本数据的 ID
*/
void setTextDataId(long id) {
if(id <= 0) {
// 若文本数据 ID 不合法,抛出异常
throw new IllegalArgumentException("Text data id should larger than 0");
}
mTextDataId = id;
}
/**
* 设置笔记的通话数据的 ID。
*
* @param id 通话数据的 ID
*/
void setCallDataId(long id) {
if (id <= 0) {
// 若通话数据 ID 不合法,抛出异常
throw new IllegalArgumentException("Call data id should larger than 0");
}
mCallDataId = id;
}
/**
* 设置笔记的通话数据的属性值,并标记笔记为本地已修改,同时更新修改时间。
*
* @param key 属性名
* @param value 属性值
*/
void setCallData(String key, String value) {
mCallDataValues.put(key, value);
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
/**
* 设置笔记的文本数据的属性值,并标记笔记为本地已修改,同时更新修改时间。
*
* @param key 属性名
* @param value 属性值
*/
void setTextData(String key, String value) {
mTextDataValues.put(key, value);
mNoteDiffValues.put(NoteColumns.LOCAL_MODIFIED, 1);
mNoteDiffValues.put(NoteColumns.MODIFIED_DATE, System.currentTimeMillis());
}
/**
* 将笔记的数据(文本数据和通话数据)推送到内容解析器中进行同步。
*
* @param context 应用程序上下文,用于访问内容解析器
* @param noteId 笔记的 ID
* @return 若同步成功返回笔记的 URI否则返回 null
*/
Uri pushIntoContentResolver(Context context, long noteId) {
/**
* 进行安全检查,确保笔记 ID 合法。
*/
if (noteId <= 0) {
// 若笔记 ID 不合法,抛出异常
throw new IllegalArgumentException("Wrong note id:" + noteId);
}
// 创建一个 ContentProviderOperation 列表,用于批量操作
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
// ContentProviderOperation 构建器
ContentProviderOperation.Builder builder = null;
if(mTextDataValues.size() > 0) {
// 若文本数据有修改
mTextDataValues.put(DataColumns.NOTE_ID, noteId);
if (mTextDataId == 0) {
// 若文本数据 ID 为 0说明是新的文本数据
mTextDataValues.put(DataColumns.MIME_TYPE, TextNote.CONTENT_ITEM_TYPE);
// 插入新的文本数据
Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI,
mTextDataValues);
try {
// 获取插入后的文本数据 ID
setTextDataId(Long.valueOf(uri.getPathSegments().get(1)));
} catch (NumberFormatException e) {
// 若获取 ID 失败,记录错误日志并清空文本数据
Log.e(TAG, "Insert new text data fail with noteId" + noteId);
mTextDataValues.clear();
return null;
}
} else {
// 若文本数据 ID 不为 0说明是更新已有的文本数据
builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mTextDataId));
builder.withValues(mTextDataValues);
operationList.add(builder.build());
}
// 清空文本数据的 ContentValues 对象
mTextDataValues.clear();
}
if(mCallDataValues.size() > 0) {
// 若通话数据有修改
mCallDataValues.put(DataColumns.NOTE_ID, noteId);
if (mCallDataId == 0) {
// 若通话数据 ID 为 0说明是新的通话数据
mCallDataValues.put(DataColumns.MIME_TYPE, CallNote.CONTENT_ITEM_TYPE);
// 插入新的通话数据
Uri uri = context.getContentResolver().insert(Notes.CONTENT_DATA_URI,
mCallDataValues);
try {
// 获取插入后的通话数据 ID
setCallDataId(Long.valueOf(uri.getPathSegments().get(1)));
} catch (NumberFormatException e) {
// 若获取 ID 失败,记录错误日志并清空通话数据
Log.e(TAG, "Insert new call data fail with noteId" + noteId);
mCallDataValues.clear();
return null;
}
} else {
// 若通话数据 ID 不为 0说明是更新已有的通话数据
builder = ContentProviderOperation.newUpdate(ContentUris.withAppendedId(
Notes.CONTENT_DATA_URI, mCallDataId));
builder.withValues(mCallDataValues);
operationList.add(builder.build());
}
// 清空通话数据的 ContentValues 对象
mCallDataValues.clear();
}
if (operationList.size() > 0) {
try {
// 批量执行 ContentProviderOperation 列表中的操作
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;
}
}
return null;
}
}
}