|
|
|
@ -0,0 +1,596 @@
|
|
|
|
|
/*
|
|
|
|
|
* 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.tool;
|
|
|
|
|
|
|
|
|
|
import android.content.ContentProviderOperation;
|
|
|
|
|
import android.content.ContentProviderResult;
|
|
|
|
|
import android.content.ContentResolver;
|
|
|
|
|
import android.content.ContentUris;
|
|
|
|
|
import android.content.ContentValues;
|
|
|
|
|
import android.content.OperationApplicationException;
|
|
|
|
|
import android.database.Cursor;
|
|
|
|
|
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.NoteColumns;
|
|
|
|
|
import net.micode.notes.ui.NotesListAdapter.AppWidgetAttribute;
|
|
|
|
|
|
|
|
|
|
import java.util.ArrayList;
|
|
|
|
|
import java.util.HashSet;
|
|
|
|
|
|
|
|
|
|
// DataUtils类作为一个工具类,可能提供了一系列与笔记数据操作相关的实用方法,目前展示的是批量删除笔记的方法所在的类定义部分。
|
|
|
|
|
public class DataUtils {
|
|
|
|
|
// 定义一个公共静态的常量字符串TAG,用于在日志记录中标识当前类,方便后续在查看日志输出时,能够快速准确地分辨出哪些日志信息是由这个类中的操作产生的,这对于调试程序以及排查问题很有帮助。
|
|
|
|
|
public static final String TAG = "DataUtils";
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* batchDeleteNotes方法用于批量删除笔记,它接收一个内容解析器(ContentResolver)和一个存放笔记ID的HashSet集合作为参数,
|
|
|
|
|
* 根据传入的笔记ID集合情况以及实际执行删除操作的结果,返回一个布尔值来表示批量删除操作是否成功完成。
|
|
|
|
|
*
|
|
|
|
|
* @param resolver 安卓系统中的内容解析器,它充当了应用程序与内容提供器之间的桥梁,通过它可以发起对数据库中相关数据(此处是笔记数据)的操作请求,比如删除操作。
|
|
|
|
|
* @param ids 一个HashSet集合,其元素类型为Long,用于存放要删除的笔记的唯一标识符。如果这个集合为null或者集合中没有元素(即size为0),会按照特定的逻辑进行处理并返回相应结果,而不会真正去执行数据库删除操作。
|
|
|
|
|
* @return 如果批量删除操作成功执行(意味着所有符合条件的笔记都被成功删除,或者传入的集合为空等无需实际删除的情况),则返回true;若在操作过程中出现异常(例如远程异常、操作应用异常等)或者部分笔记未能成功删除等情况,就返回false。
|
|
|
|
|
*/
|
|
|
|
|
public static boolean batchDeleteNotes(ContentResolver resolver, HashSet<Long> ids) {
|
|
|
|
|
// 首先判断传入的ids集合是否为null,若为null,表示没有有效的要删除的笔记ID信息传入,这种情况下可能是调用者没有提供具体要删除的笔记,或者出现了某种错误导致参数传递异常。
|
|
|
|
|
// 此时记录一条调试级别的日志(使用Log.d方法,d表示debug,用于输出一些在调试阶段有助于查看代码执行情况的信息),日志内容为“the ids is null”,提示当前传入的要删除笔记的ID集合为空,方便开发人员排查问题。
|
|
|
|
|
// 然后直接返回true,将这种情况视为无需执行实际删除操作也算成功的一种约定逻辑,这样可以避免后续代码因为接收到空指针(null)作为参数而导致出现空指针异常等错误情况,使程序逻辑更加健壮。
|
|
|
|
|
if (ids == null) {
|
|
|
|
|
Log.d(TAG, "the ids is null");
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 接着判断ids集合的大小是否为0,即集合中没有元素,表示虽然传入了集合对象,但实际上并没有指定要删除的具体笔记ID,也就是没有实际要删除的笔记任务。
|
|
|
|
|
// 同样记录一条调试日志,内容为“no id is in the hashset”,告知当前传入的集合中没有有效的笔记ID,然后返回true,把这种无实际删除任务的场景当作一种成功情况来处理,符合常规的逻辑处理习惯,也避免了不必要的错误提示和复杂的错误处理逻辑。
|
|
|
|
|
if (ids.size() == 0) {
|
|
|
|
|
Log.d(TAG, "no id is in the hashset");
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 创建一个ArrayList<ContentProviderOperation>类型的列表对象operationList,它用于存储一系列的ContentProviderOperation对象。
|
|
|
|
|
// ContentProviderOperation对象可以用来定义针对内容提供器(通常对应数据库操作)的具体操作,在这里就是用于构建要批量执行的删除笔记的操作集合,后续会通过内容解析器一次性批量执行这些操作来实现批量删除笔记的功能。
|
|
|
|
|
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
|
|
|
|
|
|
|
|
|
|
// 通过for循环遍历传入的ids集合,对于集合中的每个笔记ID,都要构建相应的删除操作并添加到operationList列表中,这样就能为每个要删除的笔记都准备好对应的删除操作指令,方便后续批量执行。
|
|
|
|
|
for (long id : ids) {
|
|
|
|
|
// 在构建删除操作之前,先判断当前笔记ID是否等于系统根文件夹的ID,这里使用Notes.ID_ROOT_FOLDER(应该是在Notes类中预先定义好的一个表示系统根文件夹的常量值)来进行比较。
|
|
|
|
|
// 通常情况下,系统根文件夹是整个笔记体系结构中的重要基础部分,不应该被随意删除,因为它可能关联着许多其他的笔记数据或者系统相关的重要逻辑,如果误删可能会导致程序出现严重问题。
|
|
|
|
|
if (id == Notes.ID_ROOT_FOLDER) {
|
|
|
|
|
// 如果当前笔记ID等于系统根文件夹的ID,那么记录一条错误级别的日志(使用Log.e方法,e表示error,用于输出表示出现错误情况的重要信息,方便开发人员及时发现和解决问题),日志内容为“Don't delete system folder root”,明确提示不能删除系统根文件夹,起到警示作用。
|
|
|
|
|
// 然后使用continue语句跳过本次循环,即不针对这个系统根文件夹ID构建删除操作,也不会将对应的操作添加到operationList列表中,直接进入下一次循环,继续处理下一个笔记ID,确保不会误删重要的系统文件夹数据。
|
|
|
|
|
Log.e(TAG, "Don't delete system folder root");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果当前笔记ID不是系统根文件夹的ID,那么就可以构建对应的删除操作了。
|
|
|
|
|
// 首先创建一个ContentProviderOperation的构建器对象builder,通过调用ContentProviderOperation类的newDelete方法来创建,这个方法用于构建一个删除类型的操作。
|
|
|
|
|
// 在调用newDelete方法时,需要传入一个表示要删除数据的内容URI(Uniform Resource Identifier,统一资源标识符),这里通过ContentUris.withAppendedId方法根据当前笔记ID(id)来生成对应的内容URI。
|
|
|
|
|
// ContentUris.withAppendedId方法会将给定的基础URI(此处是Notes.CONTENT_NOTE_URI,应该是预定义的指向笔记数据资源的通用URI)与具体的笔记ID进行拼接,形成一个能够准确指向要删除的那条笔记数据的唯一URI,这样后续执行删除操作时就能准确找到对应的笔记记录进行删除了。
|
|
|
|
|
ContentProviderOperation.Builder builder = ContentProviderOperation
|
|
|
|
|
.newDelete(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id));
|
|
|
|
|
|
|
|
|
|
// 将构建好的删除操作(通过builder.build()方法将构建器对象转换为实际可执行的ContentProviderOperation对象)添加到operationList列表中,不断重复这个过程,就能把所有要删除的笔记对应的删除操作都添加到列表里,为批量执行删除操作做好准备。
|
|
|
|
|
operationList.add(builder.build());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// 当为所有要删除的笔记都构建好对应的删除操作并添加到operationList列表后,就可以通过内容解析器的applyBatch方法来批量执行这些操作了。
|
|
|
|
|
// applyBatch方法接收两个参数,第一个参数Notes.AUTHORITY(应该是在Notes类中预先定义好的一个表示操作权限的常量字符串,用于指定当前操作能够访问哪些内容提供器资源的权限范围),第二个参数就是前面构建好的包含所有删除操作的operationList列表。
|
|
|
|
|
// 该方法会尝试批量执行operationList中的所有ContentProviderOperation操作,并返回一个ContentProviderResult[]类型的数组,数组中的每个元素对应一个操作的执行结果,通过检查这些结果可以知道每个删除操作是否成功执行了。
|
|
|
|
|
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);
|
|
|
|
|
|
|
|
|
|
// 接下来判断操作结果数组是否满足以下几种可能表示操作失败的情况:
|
|
|
|
|
// 1. results为null,说明可能在执行批量操作过程中出现了严重问题,导致无法获取到任何操作结果,比如可能与内容提供器的通信出现了故障等原因。
|
|
|
|
|
// 2. results.length为0,表示虽然获取到了结果数组,但是数组中没有任何元素,意味着可能没有实际执行任何有效的操作,也可能是出现了异常情况导致没有结果返回。
|
|
|
|
|
// 3. results[0]为null,说明即使有结果数组,但第一个元素(通常第一个元素对应第一个操作的结果,如果操作是按顺序执行的话)就是空的,可能第一个操作就出现了问题,进而影响了整个批量操作的结果有效性。
|
|
|
|
|
// 如果满足以上任意一种情况,就意味着批量删除操作可能没有成功执行或者没有符合条件的笔记被实际删除,需要进行相应的错误处理并向调用者返回操作失败的结果。
|
|
|
|
|
if (results == null || results.length == 0 || results[0] == null) {
|
|
|
|
|
// 记录一条调试日志,内容为“delete notes failed, ids:”加上要删除笔记的ID集合的字符串表示形式(通过ids.toString()方法将HashSet集合转换为字符串,方便在日志中查看具体是哪些笔记的删除操作出现了问题),提示当前删除笔记的操作失败了,以便开发人员根据日志信息排查具体是哪些笔记没能成功删除以及可能出现问题的原因。
|
|
|
|
|
Log.d(TAG, "delete notes failed, ids:" + ids.toString());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果操作结果数组正常,即不满足上述表示失败的情况,说明批量删除操作成功执行了,所有符合条件的笔记都已被成功删除,此时返回true,告知调用者批量删除操作已经顺利完成,让调用者可以根据返回值进行后续的逻辑处理,比如更新界面显示、处理相关业务逻辑等。
|
|
|
|
|
return true;
|
|
|
|
|
} catch (RemoteException e) {
|
|
|
|
|
// 如果在执行批量删除操作过程中出现了RemoteException异常,这个异常通常表示在与远程的内容提供器进行通信时出现了问题,比如网络连接异常、远程服务不可用等原因导致无法正常执行操作。
|
|
|
|
|
// 当捕获到这个异常时,记录一条错误日志,使用String.format方法将异常的字符串表示(e.toString(),可以获取异常的详细类名等信息)和详细的错误消息(e.getMessage(),通常包含更具体的错误描述内容)按照一定格式输出,方便查看和排查问题根源,例如可以根据日志信息定位是通信的哪个环节出现了故障,以便后续修复问题。
|
|
|
|
|
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
|
|
|
|
|
} catch (OperationApplicationException e) {
|
|
|
|
|
// 如果在执行批量删除操作过程中出现了OperationApplicationException异常,这个异常一般是因为构建的操作(ContentProviderOperation)在应用(执行)过程中不符合相关规则或者内容提供器内部处理操作时出现了错误等情况导致的。
|
|
|
|
|
// 同样,当捕获到这个异常时,记录一条错误日志,按照指定格式(使用String.format方法)输出异常的字符串表示和详细错误消息,用于调试和问题追踪,帮助开发人员确定是操作构建环节还是内容提供器执行环节出现了问题,进而采取相应的解决措施。
|
|
|
|
|
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果在执行批量删除操作过程中出现了上述的RemoteException或OperationApplicationException异常,导致操作未能完整成功执行,那么最终返回false,表示批量删除操作失败,让调用者知晓操作的最终结果是不成功的,以便进行相应的错误处理或提示用户等操作。
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 定义一个静态公共方法,用于将单个笔记移动到指定文件夹。
|
|
|
|
|
// 该方法接收四个参数:ContentResolver用于与安卓系统的内容提供器交互以操作数据库;
|
|
|
|
|
// long类型的id表示要移动的笔记的唯一标识符;
|
|
|
|
|
// long类型的srcFolderId表示笔记当前所在文件夹的标识符;
|
|
|
|
|
// long类型的desFolderId表示笔记将要移动到的目标文件夹的标识符。
|
|
|
|
|
public static void moveNoteToFoler(ContentResolver resolver, long id, long srcFolderId, long desFolderId) {
|
|
|
|
|
// 创建一个ContentValues对象,它用于存储要更新到数据库中的键值对数据,
|
|
|
|
|
// 在这里会存放与笔记相关的字段及其对应要更新的值,以此来实现对笔记相关属性的修改。
|
|
|
|
|
ContentValues values = new ContentValues();
|
|
|
|
|
|
|
|
|
|
// 使用ContentValues对象的put方法,将NoteColumns.PARENT_ID字段(通常用于表示笔记所属的文件夹在数据库中的标识符)的值设置为desFolderId,
|
|
|
|
|
// 这一步操作的目的是在数据库中更新笔记的所属文件夹信息,将笔记关联到目标文件夹,实现移动笔记到新文件夹的关键改变。
|
|
|
|
|
values.put(NoteColumns.PARENT_ID, desFolderId);
|
|
|
|
|
|
|
|
|
|
// 同样使用put方法,将NoteColumns.ORIGIN_PARENT_ID字段(一般用于记录笔记原本所属的文件夹标识符,可用于追踪笔记的移动历史等用途)的值设置为srcFolderId,
|
|
|
|
|
// 这样做是为了在数据库中保存笔记原来所在文件夹的信息,方便后续查看笔记是从哪个文件夹被移动过来的,有助于数据的溯源和相关业务逻辑处理。
|
|
|
|
|
values.put(NoteColumns.ORIGIN_PARENT_ID, srcFolderId);
|
|
|
|
|
|
|
|
|
|
// 再次使用put方法,把NoteColumns.LOCAL_MODIFIED字段(可作为一个标记,用于表示笔记是否在本地有过修改,方便其他相关逻辑根据此标记来处理后续事宜,比如数据同步等)的值设置为1,
|
|
|
|
|
// 由于移动笔记这个操作在本地改变了笔记的相关属性,所以将此标记设为1,告知系统该笔记发生了本地相关的修改,后续可能触发相应的业务逻辑来处理这个变化。
|
|
|
|
|
values.put(NoteColumns.LOCAL_MODIFIED, 1);
|
|
|
|
|
|
|
|
|
|
// 通过传入的ContentResolver对象的update方法,来执行实际的数据库更新操作。
|
|
|
|
|
// 首先使用ContentUris.withAppendedId方法根据笔记的唯一标识符id,与预定义的笔记内容的基础URI(Notes.CONTENT_NOTE_URI,它指向存储笔记相关数据的数据库位置)拼接,生成一个精确指向要操作的特定笔记记录的内容URI。
|
|
|
|
|
// 然后将前面构建好的包含要更新字段及对应值的ContentValues对象(values)传入,后面两个参数为null,意味着没有额外的筛选条件(比如按照其他字段的值进一步筛选要更新的记录范围)和更新参数(例如更新操作的一些额外配置等),
|
|
|
|
|
// 就是单纯基于通过id确定的特定笔记记录,按照values里设定的字段值进行更新,从而完成将笔记移动到目标文件夹相关属性更新的操作,实现笔记移动的功能。
|
|
|
|
|
resolver.update(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id), values, null, null);
|
|
|
|
|
}
|
|
|
|
|
// 定义一个静态公共方法,用于批量将多个笔记移动到指定的文件夹。
|
|
|
|
|
// 该方法接收三个参数:ContentResolver用于与安卓系统的内容提供器交互以操作数据库;
|
|
|
|
|
// HashSet<Long>类型的ids是一个存放要移动笔记的唯一标识符的集合,集合中的每个Long类型元素对应一个笔记的ID;
|
|
|
|
|
// long类型的folderId表示目标文件夹的标识符,所有在ids集合中的笔记都将被移动到这个文件夹中。
|
|
|
|
|
// 方法根据批量移动操作的执行结果返回一个布尔值,若操作成功返回true,若出现异常或部分笔记移动失败则返回false。
|
|
|
|
|
public static boolean batchMoveToFolder(ContentResolver resolver, HashSet<Long> ids,
|
|
|
|
|
long folderId) {
|
|
|
|
|
// 判断传入的ids集合是否为null,若为空集合,表示没有要移动的笔记的ID信息传入,可能是调用该方法时参数传递有误或者没有指定具体要移动的笔记。
|
|
|
|
|
// 在这种情况下,记录一条调试级别的日志(使用Log.d方法,用于输出一些有助于调试查看代码执行情况的信息),日志内容为“the ids is null”,提示当前传入的要移动笔记的ID集合为空。
|
|
|
|
|
// 然后直接返回true,将这种没有实际要移动笔记任务的情况视为一种特殊的“成功”情况来处理,避免后续代码因为接收到空指针(null)参数而出现异常,简化了方法对边界情况的处理逻辑。
|
|
|
|
|
if (ids == null) {
|
|
|
|
|
Log.d(TAG, "the ids is null");
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 创建一个ArrayList类型的列表对象operationList,它用于存储ContentProviderOperation类型的对象,
|
|
|
|
|
// 这些对象将用于构建针对每个笔记的具体更新操作,通过将多个这样的操作对象添加到列表中,后续可以一次性批量执行这些操作,实现批量移动笔记的功能。
|
|
|
|
|
ArrayList<ContentProviderOperation> operationList = new ArrayList<ContentProviderOperation>();
|
|
|
|
|
|
|
|
|
|
// 通过for循环遍历传入的ids集合,针对集合中的每一个笔记ID,都要构建相应的更新操作并添加到operationList列表中,以此为每个要移动的笔记准备好对应的操作指令。
|
|
|
|
|
for (long id : ids) {
|
|
|
|
|
// 创建一个ContentProviderOperation的构建器对象builder,通过调用ContentProviderOperation类的newUpdate方法来创建,
|
|
|
|
|
// 传入的参数是使用ContentUris.withAppendedId方法根据当前笔记的ID(id)生成的内容URI,这个内容URI精确指向了要更新的笔记记录在数据库中的位置,
|
|
|
|
|
// 构建出一个用于更新操作的构建器,后续可以基于这个构建器进一步设置要更新的字段及对应的值,从而完成一个完整的更新操作构建。
|
|
|
|
|
ContentProviderOperation.Builder builder = ContentProviderOperation
|
|
|
|
|
.newUpdate(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, id));
|
|
|
|
|
|
|
|
|
|
// 使用构建器对象builder的withValue方法,将NoteColumns.PARENT_ID字段(笔记所属文件夹的标识符字段)的值设置为folderId,
|
|
|
|
|
// 这一步操作明确了要将当前笔记的所属文件夹更新为目标文件夹,是实现将笔记移动到指定文件夹的关键设置,对应了批量移动笔记的核心业务逻辑。
|
|
|
|
|
builder.withValue(NoteColumns.PARENT_ID, folderId);
|
|
|
|
|
|
|
|
|
|
// 使用构建器对象builder的withValue方法,将NoteColumns.LOCAL_MODIFIED字段(用于标记笔记在本地是否有修改的字段)的值设置为1,
|
|
|
|
|
// 因为移动笔记的操作属于对笔记在本地进行了修改,设置此标记可以让系统或其他相关逻辑知晓笔记发生了变化,便于后续进行如数据同步等相关业务逻辑的处理。
|
|
|
|
|
builder.withValue(NoteColumns.LOCAL_MODIFIED, 1);
|
|
|
|
|
|
|
|
|
|
// 将构建好的完整的ContentProviderOperation对象(通过builder.build()方法将构建器转换为可执行的操作对象)添加到operationList列表中,
|
|
|
|
|
// 不断重复这个过程,为ids集合中每个笔记都构建并添加对应的更新操作对象,形成一个包含所有要执行的批量更新操作的列表,为后续批量执行做准备。
|
|
|
|
|
operationList.add(builder.build());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
// 通过ContentResolver对象的applyBatch方法,批量执行operationList列表中存储的所有ContentProviderOperation更新操作。
|
|
|
|
|
// applyBatch方法的第一个参数Notes.AUTHORITY是一个预定义的字符串常量,用于指定操作的权限范围,表明这些操作是针对哪个内容提供器资源有权限进行操作的,相当于一个操作许可标识。
|
|
|
|
|
// 第二个参数就是前面构建好的包含所有要执行更新操作的operationList列表,该方法会尝试依次执行列表中的每个操作,并返回一个ContentProviderResult[]类型的数组,数组中的每个元素对应一个操作的执行结果,通过检查这些结果可以判断每个操作是否成功执行。
|
|
|
|
|
ContentProviderResult[] results = resolver.applyBatch(Notes.AUTHORITY, operationList);
|
|
|
|
|
|
|
|
|
|
// 判断操作结果数组是否满足以下几种可能表示操作失败的情况:
|
|
|
|
|
// 1. 如果results为null,说明在执行批量操作过程中可能出现了严重问题,例如与内容提供器的通信完全失败,导致无法获取到任何操作结果,这种情况可能是网络故障、服务不可用等原因引起的。
|
|
|
|
|
// 2. 如果results.length为0,表示虽然获取到了结果数组,但数组中没有任何元素,意味着可能没有实际执行任何有效的操作,有可能是操作构建出现问题或者执行过程中出现异常,导致没有结果返回。
|
|
|
|
|
// 3. 如果results[0]为null,说明即使有结果数组,但第一个元素(通常第一个元素对应第一个操作的结果,如果操作是按顺序执行的话)就是空的,这可能意味着第一个操作就出现了问题,进而影响了整个批量操作的结果有效性,例如第一个操作由于某些条件不满足而无法执行成功等情况。
|
|
|
|
|
// 如果满足上述任意一种情况,就意味着批量移动操作可能没有成功执行或者没有符合条件的笔记被实际移动,需要进行相应的错误处理并向调用者返回操作失败的结果。
|
|
|
|
|
if (results == null || results.length == 0 || results[0] == null) {
|
|
|
|
|
// 记录一条调试日志(使用Log.d方法),日志内容为“delete notes failed, ids:”加上要移动笔记的ID集合的字符串表示形式(通过ids.toString()方法将HashSet集合转换为字符串,方便在日志中查看具体是哪些笔记的移动操作出现了问题),
|
|
|
|
|
// 以此提示当前批量移动笔记的操作失败了,方便开发人员根据日志信息排查具体是哪些笔记没能成功移动以及可能出现问题的原因所在。
|
|
|
|
|
Log.d(TAG, "delete notes failed, ids:" + ids.toString());
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果操作结果数组正常,即不满足上述表示失败的情况,说明批量移动操作成功执行了,所有符合条件的笔记都已被成功移动到目标文件夹,此时返回true,告知调用者批量移动操作已经顺利完成,以便调用者可以根据这个返回值进行后续的逻辑处理,比如更新界面显示、触发相关业务逻辑等操作。
|
|
|
|
|
return true;
|
|
|
|
|
} catch (RemoteException e) {
|
|
|
|
|
// 如果在执行批量移动操作过程中出现了RemoteException异常,这个异常通常表示在与远程的内容提供器进行通信时出现了问题,
|
|
|
|
|
// 例如网络连接异常中断、远程服务端出现故障导致无法响应请求等原因,致使无法正常执行操作。
|
|
|
|
|
// 当捕获到这个异常时,记录一条错误日志(使用Log.e方法,用于输出表示出现错误情况的重要信息,方便开发人员及时发现和解决问题),
|
|
|
|
|
// 通过String.format方法将异常的字符串表示(e.toString(),可以获取异常的详细类名等信息)和详细的错误消息(e.getMessage(),通常包含更具体的错误描述内容)按照一定格式输出,
|
|
|
|
|
// 方便查看和排查问题根源,例如可以根据日志信息定位是通信的哪个环节出现了故障,以便后续采取相应的修复措施来解决问题。
|
|
|
|
|
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
|
|
|
|
|
} catch (OperationApplicationException e) {
|
|
|
|
|
// 如果在执行批量移动操作过程中出现了OperationApplicationException异常,这个异常一般是因为构建的操作(ContentProviderOperation)在应用(执行)过程中不符合相关规则或者内容提供器内部处理操作时出现了错误等情况导致的,
|
|
|
|
|
// 例如操作的参数设置不符合要求、内容提供器对操作的处理逻辑中出现了业务错误等原因都可能引发此异常。
|
|
|
|
|
// 同样,当捕获到这个异常时,记录一条错误日志(使用Log.e方法),按照指定格式(使用String.format方法)输出异常的字符串表示和详细错误消息,
|
|
|
|
|
// 用于调试和问题追踪,帮助开发人员确定是操作构建环节还是内容提供器执行环节出现了问题,进而采取针对性的解决办法来修复异常情况。
|
|
|
|
|
Log.e(TAG, String.format("%s: %s", e.toString(), e.getMessage()));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 如果在执行批量移动操作过程中出现了上述的RemoteException或OperationApplicationException异常,导致操作未能完整成功执行,那么最终返回false,
|
|
|
|
|
// 表示批量移动操作失败,让调用者知晓操作的最终结果是不成功的,以便调用者进行相应的错误处理,比如向用户显示操作失败的提示信息、进行数据回滚等操作。
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the all folder count except system folders {@link Notes#TYPE_SYSTEM}}
|
|
|
|
|
*/
|
|
|
|
|
/**
|
|
|
|
|
* 获取用户文件夹数量的静态方法。该方法通过查询数据库,统计满足特定条件的文件夹数量并返回结果,
|
|
|
|
|
* 这里的特定条件是文件夹类型为普通文件夹(非系统文件夹)且不在回收站中。
|
|
|
|
|
*
|
|
|
|
|
* @param resolver 安卓系统中的内容解析器,用于向数据库发起查询操作,是与数据库交互获取数据的关键对象。
|
|
|
|
|
* @return 返回一个整数,表示满足条件的用户文件夹的数量,如果查询过程中出现异常或者没有符合条件的文件夹,返回值可能为0。
|
|
|
|
|
*/
|
|
|
|
|
public static int getUserFolderCount(ContentResolver resolver) {
|
|
|
|
|
// 使用内容解析器的 `query` 方法发起数据库查询操作,查询的URI为 `Notes.CONTENT_NOTE_URI`(这应该是预定义的用于访问笔记相关内容的通用URI,数据库中存放笔记及文件夹等各种属性信息的地址入口)。
|
|
|
|
|
// 查询的字段列表设置为 `new String[] { "COUNT(*)" }`,这里使用了数据库的聚合函数 `COUNT(*)`,表示要统计满足条件的记录行数,也就是符合特定条件的文件夹的数量,而不是获取具体的文件夹记录的各个字段值。
|
|
|
|
|
// 筛选条件通过SQL语句形式指定,要求 `NoteColumns.TYPE` 字段(用于表示笔记或文件夹的类型)等于普通文件夹类型(通过 `Notes.TYPE_FOLDER` 常量表示,这里先将其转换为字符串形式用于条件判断,意味着只统计类型为文件夹的记录),并且 `NoteColumns.PARENT_ID` 字段(表示父文件夹的ID,用于判断文件夹所在位置等情况)不等于回收站文件夹的ID(通过 `Notes.ID_TRASH_FOLER` 常量表示,同样转换为字符串用于条件判断,即排除回收站中的文件夹),通过这样的条件筛选出符合要求的用户文件夹记录来进行数量统计。
|
|
|
|
|
// 最后一个参数 `null` 表示无排序、分组等其他额外的查询条件设定,就是单纯按照给定的筛选条件统计文件夹数量。
|
|
|
|
|
Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI,
|
|
|
|
|
new String[] { "COUNT(*)" },
|
|
|
|
|
NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>?",
|
|
|
|
|
new String[] { String.valueOf(Notes.TYPE_FOLDER), String.valueOf(Notes.ID_TRASH_FOLER)},
|
|
|
|
|
null);
|
|
|
|
|
|
|
|
|
|
int count = 0;
|
|
|
|
|
// 判断游标对象 `cursor` 是否获取成功(即不为 `null`),如果游标获取成功,说明查询操作至少在获取游标这一步是正常执行的,接下来可以尝试从游标中获取统计的文件夹数量数据(前提是查询结果中有符合条件的数据)。
|
|
|
|
|
if (cursor!= null) {
|
|
|
|
|
// 将游标移动到第一条数据位置(因为查询结果如果有符合条件的数据,这里只有一条统计结果数据,所以移动到第一条即可获取到数量值),准备尝试获取其中统计的文件夹数量值。
|
|
|
|
|
if (cursor.moveToFirst()) {
|
|
|
|
|
try {
|
|
|
|
|
// 通过 `cursor.getInt(0)` 尝试从游标当前指向的记录中获取第一个(也是唯一一个,因为前面查询只返回了一个统计数量值,索引从0开始计数)字段的值,也就是满足条件的文件夹数量,并将其赋值给 `count` 变量进行存储。
|
|
|
|
|
count = cursor.getInt(0);
|
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
|
// 如果在获取游标中数据时出现索引越界异常(比如可能查询结果格式不符合预期,导致获取指定列数据时出错等情况),记录一条错误日志,日志内容为“get folder count failed:”加上异常的字符串表示(e.toString()),方便排查数据获取异常的问题,提示获取文件夹数量操作失败了。
|
|
|
|
|
Log.e(TAG, "get folder count failed:" + e.toString());
|
|
|
|
|
} finally {
|
|
|
|
|
// 无论是否成功从游标中获取到了文件夹数量值,都要关闭游标对象 `cursor`,释放相关的系统资源(比如数据库连接等资源),避免资源泄漏,这是良好的编程习惯,确保系统资源能合理利用。
|
|
|
|
|
cursor.close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 将获取到的(或者初始化为0的,如果查询出现问题等情况)文件夹数量 `count` 返回给调用者,完成方法的功能,即提供满足条件的用户文件夹数量信息。
|
|
|
|
|
return count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 检查指定的笔记在笔记数据库中是否可见(根据给定的类型以及是否不在回收站等条件判断)的静态方法,通过查询数据库获取相应结果并返回布尔值表示可见性情况。
|
|
|
|
|
*
|
|
|
|
|
* @param resolver 安卓系统中的内容解析器,用于向数据库发起查询操作,以获取与笔记相关的数据信息,是与数据库交互的关键对象。
|
|
|
|
|
* @param noteId 要检查的笔记的唯一标识ID,用于在数据库中准确查找对应的笔记记录,以此确定该笔记是否满足可见性条件。
|
|
|
|
|
* @param type 笔记的类型,用于在查询条件中筛选出符合此类型的笔记,辅助判断笔记的可见性。
|
|
|
|
|
* @return 如果根据查询条件能在数据库中找到对应的笔记记录(即笔记存在且满足可见性相关条件),返回 `true`,表示笔记在数据库中可见;否则返回 `false`。
|
|
|
|
|
*/
|
|
|
|
|
public static boolean visibleInNoteDatabase(ContentResolver resolver, long noteId, int type) {
|
|
|
|
|
// 使用内容解析器的 `query` 方法发起数据库查询操作,通过 `ContentUris.withAppendedId` 方法根据给定的笔记ID(`noteId`)生成对应的内容URI(指向要查询的笔记资源),查询的字段列表设置为 `null`,表示查询所有字段(此处实际可能不需要所有字段,只是一种通用的查询方式,具体可根据业务需求优化)。
|
|
|
|
|
// 查询的筛选条件通过SQL语句指定,要求笔记的类型(`NoteColumns.TYPE` 字段)等于传入的类型(`type` 参数,通过 `String.valueOf` 方法将其转换为字符串形式用于SQL语句条件判断)并且父文件夹ID(`NoteColumns.PARENT_ID` 字段)不等于回收站文件夹ID(`Notes.ID_TRASH_FOLER`,同样转换为字符串用于条件判断),这样筛选出符合特定类型且不在回收站的笔记记录。
|
|
|
|
|
// 最后一个参数为 `null`,表示无排序等额外条件。
|
|
|
|
|
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId),
|
|
|
|
|
null,
|
|
|
|
|
NoteColumns.TYPE + "=? AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER,
|
|
|
|
|
new String [] {String.valueOf(type)},
|
|
|
|
|
null);
|
|
|
|
|
|
|
|
|
|
boolean exist = false;
|
|
|
|
|
// 判断游标对象 `cursor` 是否获取成功(不为 `null`),如果游标获取成功,说明查询操作至少在获取游标这一步是正常执行的,可以进一步根据游标中的数据情况判断笔记是否存在(满足条件)。
|
|
|
|
|
if (cursor!= null) {
|
|
|
|
|
// 通过 `cursor.getCount` 方法获取游标中的数据记录数量,如果数量大于0,表示找到了符合条件的笔记记录,说明笔记在数据库中是满足可见性相关条件存在的,将 `exist` 变量设置为 `true`。
|
|
|
|
|
if (cursor.getCount() > 0) {
|
|
|
|
|
exist = true;
|
|
|
|
|
}
|
|
|
|
|
// 无论是否找到了符合条件的记录,都要关闭游标对象 `cursor`,释放相关的系统资源(如数据库连接等资源),避免资源泄漏,养成良好的资源管理习惯。
|
|
|
|
|
cursor.close();
|
|
|
|
|
}
|
|
|
|
|
// 返回 `exist` 变量的值,该值表示根据查询判断的笔记在数据库中的可见性情况,`true` 表示可见,`false` 表示不可见。
|
|
|
|
|
return exist;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 该静态方法用于检查指定的笔记ID在笔记数据库中是否存在,通过向数据库发起查询操作,根据查询结果来判断对应笔记记录是否存在,并返回相应的布尔值表示存在与否情况。
|
|
|
|
|
*
|
|
|
|
|
* @param resolver 安卓系统中的内容解析器,它充当了应用程序与数据库之间交互的桥梁,用于发起针对笔记数据库的查询操作,以此来查找是否存在指定ID的笔记记录。
|
|
|
|
|
* @param noteId 要检查的笔记在数据库中的唯一标识ID,通过这个ID能够在数据库中精准定位到对应的笔记记录(如果存在的话),它是确定查询目标的关键参数。
|
|
|
|
|
* @return 如果根据查询操作在笔记数据库中找到了对应ID的笔记记录,那么返回true,表示该笔记存在于数据库中;否则返回false,表示数据库中不存在此ID对应的笔记记录。
|
|
|
|
|
*/
|
|
|
|
|
public static boolean existInNoteDatabase(ContentResolver resolver, long noteId) {
|
|
|
|
|
// 使用内容解析器(resolver)的query方法发起数据库查询操作。
|
|
|
|
|
// 首先通过ContentUris.withAppendedId方法,根据传入的笔记ID(noteId)生成对应的内容URI(Uniform Resource Identifier,统一资源标识符),这个生成的URI指向了数据库中具体要查询的笔记资源位置,就像是给数据库中的笔记记录定了一个精确的地址,方便后续准确查找对应的笔记。
|
|
|
|
|
// 后面的四个参数依次为:
|
|
|
|
|
// - 查询的字段列表设置为null,表示查询所有字段。这里之所以设置为null,可能只是简单地想确认笔记是否存在,而暂时不需要获取笔记记录里具体某个或某些字段的值,所以采用这种通用的查询方式,不过在实际应用中,如果明确知道不需要所有字段信息,可以优化此处的查询字段设置,以提高查询效率。
|
|
|
|
|
// - 筛选条件设置为null,表示没有特定的筛选条件,就是单纯地按照根据笔记ID生成的URI去查找对应的笔记记录,没有其他诸如按照笔记类型、创建时间等额外条件来进一步限制查询范围。
|
|
|
|
|
// - 查询参数设置为null,同样表示没有额外的参数需求,比如在使用通配符查询等场景下可能会传入一些参数,此处不需要所以设为null。
|
|
|
|
|
// - 排序规则设置为null,意味着查询结果不需要按照任何特定的顺序进行排列,比如按时间先后、字母顺序等排序,这里只关心是否能找到对应笔记记录,对结果顺序没有要求。
|
|
|
|
|
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_NOTE_URI, noteId),
|
|
|
|
|
null, null, null, null);
|
|
|
|
|
|
|
|
|
|
boolean exist = false;
|
|
|
|
|
// 判断游标对象cursor是否获取成功(即不为null),如果游标获取成功,说明查询操作至少在获取游标这一步是正常执行的,意味着与数据库的交互没有出现连接失败等严重问题,此时可以进一步通过游标中的数据情况来判断对应的笔记记录是否存在。
|
|
|
|
|
if (cursor!= null) {
|
|
|
|
|
// 通过cursor.getCount()方法获取游标中查询到的数据记录数量,该方法返回的是一个整数,表示符合查询条件(此处实际就是根据笔记ID查找对应的记录)的记录个数。
|
|
|
|
|
// 如果返回的数量大于0,说明找到了至少一条符合条件的笔记记录,也就意味着数据库中存在对应ID的笔记,此时将exist变量设置为true,表示笔记存在。
|
|
|
|
|
if (cursor.getCount() > 0) {
|
|
|
|
|
exist = true;
|
|
|
|
|
}
|
|
|
|
|
// 无论最终是否找到了对应笔记记录,都要关闭游标对象cursor,释放相关的系统资源(比如数据库连接资源、内存资源等),避免资源泄漏,这是良好的编程习惯,确保系统资源能够合理地被利用,防止因未关闭游标而导致的潜在性能问题或资源耗尽问题。
|
|
|
|
|
cursor.close();
|
|
|
|
|
}
|
|
|
|
|
// 返回exist变量的值,这个值就是根据前面的查询和判断过程所确定的,表示指定的笔记在数据库中是否存在的最终结果,true表示存在,false表示不存在,将这个结果返回给调用该方法的地方,以便调用者根据这个结果进行后续的业务逻辑处理,比如根据笔记是否存在来决定是否执行更新、删除等其他操作。
|
|
|
|
|
return exist;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 此静态方法的作用是检查指定的数据ID在数据数据库(通过Notes.CONTENT_DATA_URI来确定对应的数据库资源位置,具体所指的数据内容依赖于业务逻辑中该URI的定义)中是否存在,同样是通过查询数据库并依据查询结果返回布尔值来表明存在情况。
|
|
|
|
|
*
|
|
|
|
|
* @param resolver 安卓系统中的内容解析器,负责与数据数据库进行交互,发起查询操作以查找是否存在指定ID的数据记录,是实现数据库查询功能的关键组件。
|
|
|
|
|
* @param dataId 要检查的数据在其对应数据库中的唯一标识ID,利用这个ID可以在数据库中准确地定位到相应的数据记录(若存在的话),它明确了查询操作具体针对的目标数据。
|
|
|
|
|
* @return 如果通过查询在数据数据库中找到了对应dataId的数据记录,那么返回true,表示该数据存在于数据库中;反之则返回false,表示数据库中不存在此ID对应的数据记录,以此告知调用者对应的数据是否存在,方便调用者进行后续的相关处理。
|
|
|
|
|
*/
|
|
|
|
|
public static boolean existInDataDatabase(ContentResolver resolver, long dataId) {
|
|
|
|
|
// 借助内容解析器(resolver)的query方法来发起针对数据数据库的查询操作。
|
|
|
|
|
// 首先利用ContentUris.withAppendedId方法,依据传入的数据ID(dataId)生成相应的内容URI,该URI精确指向了数据数据库中要查询的数据资源所在位置,为后续准确查找对应的数据记录提供了明确的地址信息。
|
|
|
|
|
// 之后的四个参数设定情况与`existInNoteDatabase`方法中的类似:
|
|
|
|
|
// - 查询的字段列表设为null,表示查询所有字段。这里可能只是单纯想确认数据是否存在,暂时无需特定字段的值,不过如有需要可以根据实际情况优化为指定具体的查询字段,以提升查询性能。
|
|
|
|
|
// - 筛选条件为null,意味着没有额外的筛选条件限制,仅仅是按照根据数据ID生成的URI去查找对应的记录,不存在像按照数据类型、关联对象等其他条件来进一步缩小查询范围的情况。
|
|
|
|
|
// - 查询参数设为null,表明没有需要额外传入的参数,比如在某些特定的模糊查询等场景下可能需要传入参数,此处不需要所以置为null。
|
|
|
|
|
// - 排序规则设为null,说明对查询结果的顺序没有要求,不需要按照任何特定的方式(如大小顺序、时间先后等)对结果进行排列,重点在于确认是否能找到对应的数据记录。
|
|
|
|
|
Cursor cursor = resolver.query(ContentUris.withAppendedId(Notes.CONTENT_DATA_URI, dataId),
|
|
|
|
|
null, null, null, null);
|
|
|
|
|
|
|
|
|
|
boolean exist = false;
|
|
|
|
|
// 检查游标对象cursor是否成功获取(不为null),若游标获取成功,代表查询操作在获取游标这一环节是正常的,不存在与数据库连接失败之类的基础问题,进而可以根据游标中的数据状况来判断对应的数据记录是否存在。
|
|
|
|
|
if (cursor!= null) {
|
|
|
|
|
// 通过cursor.getCount()方法获取游标中所包含的数据记录数量,该数值反映了符合查询条件(也就是根据传入的数据ID查找对应记录)的记录个数。
|
|
|
|
|
// 当这个数量大于0时,意味着找到了至少一条符合要求的数据记录,也就表明数据库中确实存在对应ID的数据,此时将exist变量设置为true,表示数据存在。
|
|
|
|
|
if (cursor.getCount() > 0) {
|
|
|
|
|
exist = true;
|
|
|
|
|
}
|
|
|
|
|
// 无论最终有没有找到对应的数据记录,都务必关闭游标对象cursor,释放与之相关的系统资源,像数据库连接、占用的内存等资源,以此避免资源泄漏,遵循良好的编程规范,保障系统资源的合理运用以及系统的稳定运行。
|
|
|
|
|
cursor.close();
|
|
|
|
|
}
|
|
|
|
|
// 返回exist变量的值,该值代表了经过前面的查询和判断流程后确定的指定数据在数据库中是否存在的最终结果,true表示存在,false表示不存在,将这个结果反馈给调用该方法的地方,便于调用者依据此结果开展后续的业务逻辑操作,例如依据数据是否存在决定下一步的数据处理步骤等。
|
|
|
|
|
return exist;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* 该静态方法用于检查具有指定名称的文件夹在笔记数据库中是否可见。所谓“可见”,是基于特定的条件判断,即文件夹的类型为普通文件夹(非特殊系统文件夹等)、不在回收站中且文件夹名称与传入的名称相匹配。通过查询数据库并根据查询结果返回布尔值来表示该文件夹是否符合可见条件存在于数据库中。
|
|
|
|
|
*
|
|
|
|
|
* @param resolver 安卓系统中的内容解析器,用于向笔记数据库发起查询操作,是与数据库交互获取相关数据的关键对象,借助它能够执行SQL查询语句来查找满足条件的文件夹记录。
|
|
|
|
|
* @param name 要检查的文件夹的名称,作为查询条件之一,用于在数据库中匹配名称相同的文件夹记录,以此确定是否存在符合可见性条件且名称相符的文件夹。
|
|
|
|
|
* @return 如果根据查询条件能在数据库中找到对应的文件夹记录(即文件夹存在且满足可见性相关条件),返回 `true`,表示具有该名称的文件夹在数据库中可见;否则返回 `false`。
|
|
|
|
|
*/
|
|
|
|
|
public static boolean checkVisibleFolderName(ContentResolver resolver, String name) {
|
|
|
|
|
// 使用内容解析器(resolver)的 `query` 方法发起数据库查询操作,查询的URI指定为 `Notes.CONTENT_NOTE_URI`(这应该是预定义的用于访问笔记以及相关文件夹等内容的通用数据库资源位置标识,数据库中存放着这些信息的相关记录)。
|
|
|
|
|
// 查询的字段列表设置为 `null`,意味着查询会返回所有字段的数据,但在这里其实我们主要关心的是是否能找到符合条件的文件夹记录,并不一定需要获取所有字段内容,只是采用了一种通用的查询方式,具体可根据业务实际需求优化字段列表,以提高查询效率等。
|
|
|
|
|
// 查询的筛选条件通过SQL语句形式拼接指定,具体如下:
|
|
|
|
|
// - `NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER`:表示文件夹的类型(通过 `NoteColumns.TYPE` 字段标识)要等于预定义的普通文件夹类型常量(`Notes.TYPE_FOLDER`),以此筛选出是文件夹类型的记录,排除其他如笔记类型等记录,确保只在文件夹范畴内查找。
|
|
|
|
|
// - `AND` 是SQL语句中的逻辑与连接词,用于连接多个筛选条件,表示需要同时满足多个条件才能符合要求。
|
|
|
|
|
// - `NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER`:要求文件夹的父文件夹ID(通过 `NoteColumns.PARENT_ID` 字段表示)不等于回收站文件夹的ID(`Notes.ID_TRASH_FOLER` 常量),即排除在回收站中的文件夹,只查找不在回收站的正常文件夹。
|
|
|
|
|
// - `AND` 再次连接下一个条件。
|
|
|
|
|
// - `NoteColumns.SNIPPET + "=?"`:表示文件夹的摘要信息(这里假设是通过 `NoteColumns.SNIPPET` 字段存储文件夹名称,具体取决于业务逻辑中对该字段的定义,不过从代码逻辑来看它用于名称匹配)要等于传入的名称(`name` 参数),这里的 `?` 是占位符,后续会通过传入的 `new String[] { name }` 将实际的名称值替换进去,用于精确匹配名称相同的文件夹。
|
|
|
|
|
// 最后传入的 `new String[] { name }` 就是前面筛选条件中占位符 `?` 对应的实际参数值,将传入的文件夹名称替换到查询条件中进行精确匹配,最后的 `null` 参数表示无排序、分组等额外的查询条件设定,就是单纯按照上述条件查找符合要求的文件夹记录。
|
|
|
|
|
Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI, null,
|
|
|
|
|
NoteColumns.TYPE + "=" + Notes.TYPE_FOLDER +
|
|
|
|
|
" AND " + NoteColumns.PARENT_ID + "<>" + Notes.ID_TRASH_FOLER +
|
|
|
|
|
" AND " + NoteColumns.SNIPPET + "=?",
|
|
|
|
|
new String[] { name }, null);
|
|
|
|
|
|
|
|
|
|
boolean exist = false;
|
|
|
|
|
// 判断游标对象 `cursor` 是否获取成功(即不为 `null`),如果游标获取成功,说明查询操作至少在获取游标这一步是正常执行的,接下来可以进一步根据游标中的数据情况判断是否存在符合条件的文件夹记录(也就是判断文件夹是否可见且名称匹配)。
|
|
|
|
|
if (cursor!= null) {
|
|
|
|
|
// 通过 `cursor.getCount` 方法获取游标中的数据记录数量,如果数量大于0,表示找到了符合条件的文件夹记录,说明在数据库中存在满足可见性相关条件且名称与传入的 `name` 相符的文件夹,此时将 `exist` 变量设置为 `true`。
|
|
|
|
|
if (cursor.getCount() > 0) {
|
|
|
|
|
exist = true;
|
|
|
|
|
}
|
|
|
|
|
// 无论最终是否找到了符合条件的文件夹记录,都要关闭游标对象 `cursor`,释放相关的系统资源(如数据库连接等资源),避免资源泄漏,养成良好的资源管理习惯,确保系统资源能合理利用且不会因为未关闭游标而出现潜在问题。
|
|
|
|
|
cursor.close();
|
|
|
|
|
}
|
|
|
|
|
// 返回 `exist` 变量的值,该值表示根据查询判断的具有指定名称的文件夹在数据库中的可见性情况,`true` 表示可见,`false` 表示不可见,将这个结果返回给调用该方法的地方,以便调用者根据此结果进行后续的业务逻辑处理,比如根据文件夹是否可见来决定是否展示相关界面元素等操作。
|
|
|
|
|
return exist;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 该静态方法用于获取指定文件夹下所有笔记对应的小部件属性信息,并将这些信息封装到 `HashSet<AppWidgetAttribute>` 集合中返回。通过查询数据库,解析游标返回的数据记录,提取小部件的相关属性(如小部件ID和小部件类型),构造 `AppWidgetAttribute` 对象并添加到集合中,如果没有符合条件的数据则返回 `null`。
|
|
|
|
|
*
|
|
|
|
|
* @param resolver 安卓系统中的内容解析器,用于向笔记数据库发起查询操作,以获取与文件夹下笔记及小部件属性相关的数据信息,它是实现与数据库交互、获取所需数据的核心对象。
|
|
|
|
|
* @param folderId 要查询的文件夹的唯一标识ID,通过该ID作为筛选条件,用于在数据库中筛选出属于该文件夹下笔记对应的小部件属性记录,确定查询的范围,确保只获取指定文件夹相关的小部件属性信息。
|
|
|
|
|
* @return 返回一个 `HashSet<AppWidgetAttribute>` 集合,其中元素类型为 `AppWidgetAttribute`(应该是自定义的表示小部件属性的类,包含小部件ID和小部件类型等属性成员),集合中包含了指定文件夹下所有笔记对应的小部件属性信息,如果没有符合条件的小部件属性记录(比如指定文件夹下没有笔记或者笔记都没有关联小部件等情况),则返回 `null`,方便调用者根据返回值进行相应的后续处理,比如判断是否需要展示小部件相关界面等操作。
|
|
|
|
|
*/
|
|
|
|
|
public static HashSet<AppWidgetAttribute> getFolderNoteWidget(ContentResolver resolver, long folderId) {
|
|
|
|
|
// 使用内容解析器(resolver)的 `query` 方法发起数据库查询操作,查询的URI设定为 `Notes.CONTENT_NOTE_URI`(这通常是预定义的用于访问笔记相关内容以及与之关联的小部件等信息的通用数据库资源位置标识,存放着这些方面的数据记录)。
|
|
|
|
|
// 查询的字段列表指定为 `new String[] { NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE }`,表示此次查询只希望获取小部件的ID(通过 `NoteColumns.WIDGET_ID` 字段标识)和小部件的类型(通过 `NoteColumns.WIDGET_TYPE` 字段标识)这两个与小部件属性相关的字段信息,而不是获取所有字段数据,这样可以精准获取我们所需的数据,避免获取不必要的数据,提高查询效率并节省资源,同时方便后续对获取到的数据进行解析和封装操作。
|
|
|
|
|
// 筛选条件通过SQL语句形式指定为 `NoteColumns.PARENT_ID + "=?"`,表示按照笔记的父文件夹ID进行筛选,其中 `?` 是占位符,后续通过 `new String[] { String.valueOf(folderId) }` 将实际的文件夹ID(`folderId` 参数,先将其转换为字符串形式)传入作为筛选条件的值,以此精确查找属于指定文件夹(`folderId` 对应的文件夹)下笔记对应的小部件属性记录,确保获取的数据是与目标文件夹相关的。
|
|
|
|
|
// 最后一个参数 `null` 表示无排序、分组等其他额外的查询条件设定,就是单纯按照给定的文件夹ID来获取其下笔记对应的小部件属性信息。
|
|
|
|
|
Cursor c = resolver.query(Notes.CONTENT_NOTE_URI,
|
|
|
|
|
new String[] { NoteColumns.WIDGET_ID, NoteColumns.WIDGET_TYPE },
|
|
|
|
|
NoteColumns.PARENT_ID + "=?",
|
|
|
|
|
new String[] { String.valueOf(folderId) },
|
|
|
|
|
null);
|
|
|
|
|
|
|
|
|
|
HashSet<AppWidgetAttribute> set = null;
|
|
|
|
|
// 判断游标对象 `c` 是否获取成功(即不为 `null`),如果游标获取成功,说明查询操作至少在获取游标这一步是正常执行的,接下来可以尝试从游标中获取数据并进行相应的处理,若游标获取失败(为 `null`),则直接返回 `null`,表示没有获取到有效数据,符合没有符合条件的小部件属性记录的情况。
|
|
|
|
|
if (c!= null) {
|
|
|
|
|
// 将游标移动到第一条数据位置(因为通常查询结果中有符合条件的数据时,第一条就是我们要找的对应记录,当然如果没有符合条件的数据,这个操作会返回 `false`,后续就不会执行获取数据的操作了),准备开始尝试从游标中获取小部件属性信息并进行封装处理,如果游标中有数据,说明存在符合条件的小部件属性记录,可以进行后续操作。
|
|
|
|
|
if (c.moveToFirst()) {
|
|
|
|
|
// 创建一个 `HashSet<AppWidgetAttribute>` 集合对象 `set`,用于存储后续从游标中解析并封装好的小部件属性信息,后续会将从游标中获取到的每条记录对应的小部件属性封装为 `AppWidgetAttribute` 对象添加到这个集合中,通过集合来统一管理和返回所有符合条件的小部件属性信息。
|
|
|
|
|
set = new HashSet<AppWidgetAttribute>();
|
|
|
|
|
// 使用 `do-while` 循环遍历游标中的所有数据记录,每次循环处理一条记录,直到游标移动到最后一条记录后无法再移动(`moveToNext` 返回 `false`)为止,这样可以确保获取到所有符合条件的小部件属性信息,不会遗漏任何一条记录对应的属性内容。
|
|
|
|
|
do {
|
|
|
|
|
try {
|
|
|
|
|
// 创建一个 `AppWidgetAttribute` 对象 `widget`,它是自定义的用于封装小部件属性信息的类的实例,用于存放从游标中获取到的当前记录对应的小部件的相关属性,后续会将这个对象添加到 `set` 集合中。
|
|
|
|
|
AppWidgetAttribute widget = new AppWidgetAttribute();
|
|
|
|
|
// 通过 `c.getInt(0)` 方法从游标中获取当前记录的小部件ID字段(索引为0,因为前面查询指定了只获取两个字段,小部件ID字段排在第一位)的值,并赋值给 `widget` 对象的 `widgetId` 属性,这样就获取并封装了小部件的ID信息。
|
|
|
|
|
widget.widgetId = c.getInt(0);
|
|
|
|
|
// 通过 `c.getInt(1)` 方法从游标中获取当前记录的小部件类型字段(索引为1)的值,并赋值给 `widget` 对象的 `widgetType` 属性,以此获取并封装了小部件的类型信息,完成了从游标数据到 `AppWidgetAttribute` 对象属性的赋值操作,将当前记录对应的小部件属性完整封装到了 `widget` 对象中。
|
|
|
|
|
widget.widgetType = c.getInt(1);
|
|
|
|
|
// 将封装好的 `widget` 对象添加到 `set` 集合中,这样集合中就会不断积累所有符合条件的小部件属性信息,每循环一次添加一个小部件的属性信息,直到遍历完所有数据记录为止。
|
|
|
|
|
set.add(widget);
|
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
|
// 如果在获取游标中数据时出现索引越界异常(比如可能查询结果格式不符合预期,导致获取指定列数据时出错等情况),记录一条错误日志,通过 `Log.e` 方法将异常的字符串表示(`e.toString()`)输出到日志中,方便排查数据获取异常的问题,以便后续对代码进行优化或者修正数据查询相关的逻辑错误。
|
|
|
|
|
Log.e(TAG, e.toString());
|
|
|
|
|
}
|
|
|
|
|
} while (c.moveToNext());
|
|
|
|
|
}
|
|
|
|
|
// 无论是否成功遍历完所有数据记录以及是否添加了小部件属性信息到集合中,都要关闭游标对象 `c`,释放相关的系统资源(如数据库连接等资源),避免资源泄漏,遵循良好的编程习惯,确保系统资源能合理利用且不会因为未关闭游标而引发潜在的性能问题等情况。
|
|
|
|
|
c.close();
|
|
|
|
|
}
|
|
|
|
|
// 返回包含小部件属性信息的 `HashSet<AppWidgetAttribute>` 集合 `set`,如果没有符合条件的数据(即游标为 `null` 或者游标中没有符合条件的记录等情况),则返回 `null`,调用者可以根据返回值进行相应的后续处理,比如判断是否为空来决定是否展示小部件相关的界面元素等操作。
|
|
|
|
|
return set;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 该静态方法用于根据给定的笔记ID,从笔记相关的数据数据库(通过 `Notes.CONTENT_DATA_URI` 确定对应的数据库资源位置)中获取对应的电话号码信息。
|
|
|
|
|
* 如果能成功从数据库中查询到电话号码,则返回该电话号码字符串;若查询过程出现异常或者没有找到对应的电话号码信息,则返回空字符串。
|
|
|
|
|
*
|
|
|
|
|
* @param resolver 安卓系统中的内容解析器,用于向数据库发起查询操作,是与数据库交互获取相关数据的关键对象,借助它可以执行SQL查询语句来查找满足条件的包含电话号码的记录。
|
|
|
|
|
* @param noteId 要获取电话号码的笔记在数据库中的唯一标识ID,通过这个ID能够在数据库中精准定位到对应的笔记记录,进而查找与之关联的电话号码信息,它是确定查询目标的关键参数。
|
|
|
|
|
* @return 如果根据查询能在数据库中找到对应笔记记录且能正确获取其中的电话号码字段值,返回该电话号码字符串;否则返回空字符串,以此告知调用者是否获取到了有效的电话号码信息,方便调用者进行后续的业务逻辑处理,比如展示电话号码或者根据是否获取到进行相应的提示等操作。
|
|
|
|
|
*/
|
|
|
|
|
public static String getCallNumberByNoteId(ContentResolver resolver, long noteId) {
|
|
|
|
|
// 使用内容解析器(resolver)的 `query` 方法发起数据库查询操作,查询的URI指定为 `Notes.CONTENT_DATA_URI`(这应该是预定义的用于访问笔记相关详细数据,例如此处与通话记录电话号码等相关信息对应的数据库资源位置标识,存放着这些相关的数据记录)。
|
|
|
|
|
// 查询的字段列表设置为 `new String [] { CallNote.PHONE_NUMBER }`,意味着此次查询只希望获取电话号码这一个字段的信息(通过 `CallNote.PHONE_NUMBER` 字段标识电话号码,具体该字段的定义取决于业务逻辑中对通话相关数据结构的设计),而不是获取所有字段数据,这样可以精准获取我们所需的数据,避免获取不必要的数据,提高查询效率并节省资源,同时也明确了我们此次查询的核心目标就是获取电话号码。
|
|
|
|
|
// 查询的筛选条件通过SQL语句形式拼接指定,具体如下:
|
|
|
|
|
// - `CallNote.NOTE_ID + "=? AND " + CallNote.MIME_TYPE + "=?"`:表示要查找的记录需同时满足笔记ID(通过 `CallNote.NOTE_ID` 字段标识)等于传入的笔记ID(`noteId` 参数,通过 `String.valueOf` 方法将其转换为字符串形式用于SQL语句条件判断),并且数据的MIME类型(通过 `CallNote.MIME_TYPE` 字段标识,通常用于区分不同类型的数据内容)等于预定义的特定内容类型常量(`CallNote.CONTENT_ITEM_TYPE`),通过这两个条件的组合,精确筛选出与指定笔记ID关联且类型符合要求的包含电话号码信息的记录。
|
|
|
|
|
// - 后面的 `new String [] { String.valueOf(noteId), CallNote.CONTENT_ITEM_TYPE }` 就是前面筛选条件中两个占位符 `?` 对应的实际参数值,按照顺序依次将笔记ID和特定内容类型的值传入作为筛选条件的值,用于精确匹配符合要求的记录。
|
|
|
|
|
// 最后一个参数 `null` 表示无排序、分组等额外的查询条件设定,就是单纯按照上述条件查找对应的电话号码信息所在的记录。
|
|
|
|
|
Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI,
|
|
|
|
|
new String [] { CallNote.PHONE_NUMBER },
|
|
|
|
|
CallNote.NOTE_ID + "=? AND " + CallNote.MIME_TYPE + "=?",
|
|
|
|
|
new String [] { String.valueOf(noteId), CallNote.CONTENT_ITEM_TYPE },
|
|
|
|
|
null);
|
|
|
|
|
|
|
|
|
|
// 首先判断游标对象 `cursor` 是否获取成功(即不为 `null`),并且游标是否能够移动到第一条数据位置(`moveToFirst` 方法返回 `true` 表示游标中有数据且成功移动到第一条记录位置,意味着找到了符合条件的记录,当然如果没有符合条件的数据,这个操作会返回 `false`),只有这两个条件都满足,才说明找到了对应笔记且存在与之关联的电话号码信息,可以尝试获取电话号码数据。
|
|
|
|
|
if (cursor!= null && cursor.moveToFirst()) {
|
|
|
|
|
try {
|
|
|
|
|
// 通过 `cursor.getString(0)` 方法从游标当前指向的记录中获取第一个(也是唯一一个,因为前面查询只指定了获取电话号码这一个字段,索引从0开始计数)字段的值,也就是获取对应的电话号码信息,并将其作为方法的返回值返回给调用者,完成获取电话号码并返回的功能操作。
|
|
|
|
|
return cursor.getString(0);
|
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
|
// 如果在获取游标中数据时出现索引越界异常(比如可能查询结果格式不符合预期,导致获取指定列数据时出错等情况),记录一条错误日志,通过 `Log.e` 方法输出日志信息,日志内容为 `"Get call number fails "` 加上异常的字符串表示(`e.toString()`),方便排查数据获取异常的问题,以便后续对代码进行优化或者修正数据查询相关的逻辑错误。
|
|
|
|
|
Log.e(TAG, "Get call number fails " + e.toString());
|
|
|
|
|
} finally {
|
|
|
|
|
// 无论是否成功从游标中获取到了电话号码信息,都要关闭游标对象 `cursor`,释放相关的系统资源(如数据库连接等资源),避免资源泄漏,养成良好的资源管理习惯,确保系统资源能合理利用且不会因为未关闭游标而出现潜在问题。
|
|
|
|
|
cursor.close();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 如果游标为 `null` 或者游标中没有符合条件的数据记录(即无法移动到第一条记录位置),说明没有获取到有效的电话号码信息,此时返回空字符串作为默认返回值,告知调用者没有查询到对应的电话号码,方便调用者根据此结果进行后续的业务逻辑处理,比如显示提示信息等操作。
|
|
|
|
|
return "";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 该静态方法用于根据给定的电话号码和通话日期,从笔记相关的数据数据库(通过 `Notes.CONTENT_DATA_URI` 确定对应的数据库资源位置)中查找对应的笔记ID。
|
|
|
|
|
* 如果能成功从数据库中查询到符合条件的笔记ID,则返回该ID值;若查询过程出现异常或者没有找到对应的笔记ID,则返回0作为默认值,表示未找到匹配的记录。
|
|
|
|
|
*
|
|
|
|
|
* @param resolver 安卓系统中的内容解析器,用于向数据库发起查询操作,是与数据库交互获取相关数据的关键对象,借助它可以执行SQL查询语句来查找满足条件的包含对应笔记ID的记录。
|
|
|
|
|
* @param phoneNumber 要查找关联笔记ID的电话号码,作为查询条件之一,用于在数据库中匹配通话记录中电话号码相同的记录,以此来进一步查找与之关联的笔记ID,确定查询的关键线索。
|
|
|
|
|
* @param callDate 通话日期,同样作为查询条件,用于进一步精确筛选出在指定日期进行的通话记录对应的笔记ID,通过电话号码和通话日期两个条件的组合,更精准地定位到符合要求的笔记记录对应的ID。
|
|
|
|
|
* @return 如果根据查询能在数据库中找到对应通话记录且能正确获取其中的笔记ID字段值,返回该笔记ID值;否则返回0,以此告知调用者是否获取到了有效的笔记ID信息,方便调用者进行后续的业务逻辑处理,比如根据笔记ID查找更多笔记相关信息或者根据是否获取到进行相应的提示等操作。
|
|
|
|
|
*/
|
|
|
|
|
public static long getNoteIdByPhoneNumberAndCallDate(ContentResolver resolver, String phoneNumber, long callDate) {
|
|
|
|
|
// 使用内容解析器(resolver)的 `query` 方法发起数据库查询操作,查询的URI指定为 `Notes.CONTENT_DATA_URI`(这是预定义的用于访问笔记相关详细数据,例如此处与通话记录等相关信息对应的数据库资源位置标识,存放着这些相关的数据记录)。
|
|
|
|
|
// 查询的字段列表设置为 `new String [] { CallNote.NOTE_ID }`,表示此次查询只希望获取笔记ID这一个字段的信息(通过 `CallNote.NOTE_ID` 字段标识笔记ID,具体该字段的定义取决于业务逻辑中对通话相关数据结构的设计),而不是获取所有字段数据,这样可以精准获取我们所需的数据,避免获取不必要的数据,提高查询效率并节省资源,同时明确了此次查询的核心目标就是获取与给定电话号码和通话日期关联的笔记ID。
|
|
|
|
|
// 查询的筛选条件通过SQL语句形式拼接指定,具体如下:
|
|
|
|
|
// - `CallNote.CALL_DATE + "=? AND " + CallNote.MIME_TYPE + "=? AND PHONE_NUMBERS_EQUAL(" + CallNote.PHONE_NUMBER + ",?)"`:表示要查找的记录需同时满足通话日期(通过 `CallNote.CALL_DATE` 字段标识)等于传入的通话日期(`callDate` 参数,通过 `String.valueOf` 方法将其转换为字符串形式用于SQL语句条件判断,不过此处 `long` 类型直接传入也可,因为数据库底层在处理数值类型时会进行相应转换),并且数据的MIME类型(通过 `CallNote.MIME_TYPE` 字段标识,用于区分不同类型的数据内容)等于预定义的特定内容类型常量(`CallNote.CONTENT_ITEM_TYPE`),同时还需要通过 `PHONE_NUMBERS_EQUAL` 这个自定义的函数(从代码逻辑推测应该是用于比较电话号码是否相等的函数,具体实现依赖于业务逻辑中数据库相关的函数定义)来判断通话记录中的电话号码(`CallNote.PHONE_NUMBER` 字段)是否与传入的电话号码(`phoneNumber` 参数)相等,通过这三个条件的组合,精确筛选出与指定电话号码和通话日期匹配且类型符合要求的包含对应笔记ID信息的记录。
|
|
|
|
|
// - 后面的 `new String [] { String.valueOf(callDate), CallNote.CONTENT_ITEM_TYPE, phoneNumber }` 就是前面筛选条件中三个占位符 `?` 对应的实际参数值,按照顺序依次将通话日期、特定内容类型和电话号码的值传入作为筛选条件的值,用于精确匹配符合要求的记录。
|
|
|
|
|
// 最后一个参数 `null` 表示无排序、分组等额外的查询条件设定,就是单纯按照上述条件查找对应的笔记ID所在的记录。
|
|
|
|
|
Cursor cursor = resolver.query(Notes.CONTENT_DATA_URI,
|
|
|
|
|
new String [] { CallNote.NOTE_ID },
|
|
|
|
|
CallNote.CALL_DATE + "=? AND " + CallNote.MIME_TYPE + "=? AND PHONE_NUMBERS_EQUAL("
|
|
|
|
|
+ CallNote.PHONE_NUMBER + ",?)",
|
|
|
|
|
new String [] { String.valueOf(callDate), CallNote.CONTENT_ITEM_TYPE, phoneNumber },
|
|
|
|
|
null);
|
|
|
|
|
|
|
|
|
|
// 首先判断游标对象 `cursor` 是否获取成功(即不为 `null`),如果游标获取成功,说明查询操作至少在获取游标这一步是正常执行的,接下来再判断游标是否能够移动到第一条数据位置(`moveToFirst` 方法返回 `true` 表示游标中有数据且成功移动到第一条记录位置,意味着找到了符合条件的记录,若返回 `false` 则表示没有符合条件的数据),只有游标不为 `null` 且能移动到第一条记录位置时,才说明找到了对应通话记录且存在与之关联的笔记ID,可以尝试获取笔记ID数据。
|
|
|
|
|
if (cursor!= null) {
|
|
|
|
|
if (cursor.moveToFirst()) {
|
|
|
|
|
try {
|
|
|
|
|
// 通过 `cursor.getLong(0)` 方法从游标当前指向的记录中获取第一个(也是唯一一个,因为前面查询只指定了获取笔记ID这一个字段,索引从0开始计数)字段的值,也就是获取对应的笔记ID信息,并将其作为方法的返回值返回给调用者,完成获取笔记ID并返回的功能操作。
|
|
|
|
|
return cursor.getLong(0);
|
|
|
|
|
} catch (IndexOutOfBoundsException e) {
|
|
|
|
|
// 如果在获取游标中数据时出现索引越界异常(比如可能查询结果格式不符合预期,导致获取指定列数据时出错等情况),记录一条错误日志,通过 `Log.e` 方法输出日志信息,日志内容为 `"Get call note id fails "` 加上异常的字符串表示(`e.toString()`),方便排查数据获取异常的问题,以便后续对代码进行优化或者修正数据查询相关的逻辑错误。
|
|
|
|
|
Log.e(TAG, "Get call note id fails " + e.toString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 无论是否成功从游标中获取到了笔记ID信息(即无论是否能移动到第一条记录位置获取到数据),都要关闭游标对象 `cursor`,释放相关的系统资源(如数据库连接等资源),避免资源泄漏,养成良好的资源管理习惯,确保系统资源能合理利用且不会因为未关闭游标而出现潜在问题。
|
|
|
|
|
cursor.close();
|
|
|
|
|
}
|
|
|
|
|
// 如果游标为 `null` 或者游标中没有符合条件的数据记录(即无法移动到第一条记录位置获取到笔记ID),说明没有获取到有效的笔记ID信息,此时返回0作为默认返回值,告知调用者没有查询到对应的笔记ID,方便调用者根据此结果进行后续的业务逻辑处理,比如显示提示信息等操作。
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* 该静态方法的功能是根据给定的笔记ID,从笔记数据库(通过 `Notes.CONTENT_NOTE_URI` 来定位相关数据库资源)中获取对应笔记的摘要信息(通常是笔记内容的部分关键展示内容,此处由 `NoteColumns.SNIPPET` 字段表示)。
|
|
|
|
|
* 如果能在数据库中成功找到对应笔记并获取到摘要信息,则返回该摘要信息字符串;若根据传入的笔记ID在数据库中未找到相应笔记,将会抛出异常告知调用者笔记不存在。
|
|
|
|
|
*
|
|
|
|
|
* @param resolver 安卓系统中的内容解析器,它充当了应用程序与数据库之间交互的桥梁,用于向数据库发起查询操作,以此查找对应笔记的摘要信息,是实现数据获取功能的关键对象。
|
|
|
|
|
* @param noteId 要获取摘要信息的笔记在数据库中的唯一标识ID,通过这个ID可以在数据库中准确地定位到对应的笔记记录,从而获取其中存储的摘要信息,它是确定查询目标笔记的关键参数。
|
|
|
|
|
* @return 如果数据库中存在对应笔记且成功获取到其摘要信息(`NoteColumns.SNIPPET` 字段的值),则返回该摘要信息的字符串表示;若未找到对应笔记,会抛出 `IllegalArgumentException` 异常,并在异常信息中明确提示对应的笔记不存在以及传入的笔记ID,方便调用者根据异常情况进行相应的错误处理,例如提示用户笔记不存在等操作。
|
|
|
|
|
*/
|
|
|
|
|
public static String getSnippetById(ContentResolver resolver, long noteId) {
|
|
|
|
|
// 使用内容解析器(resolver)的 `query` 方法发起数据库查询操作。
|
|
|
|
|
// 查询的URI指定为 `Notes.CONTENT_NOTE_URI`,这是预定义的用于访问笔记相关内容的通用数据库资源位置标识,数据库中存放着笔记的各种属性信息,包括我们要获取的摘要信息所在的记录。
|
|
|
|
|
// 查询的字段列表设置为 `new String [] { NoteColumns.SNIPPET }`,意味着此次查询只希望获取笔记的摘要信息这一个字段的数据(`NoteColumns.SNIPPET` 字段用于存储摘要相关内容,具体含义取决于业务逻辑中对笔记摘要的定义和存储方式),通过这样精准指定字段的方式,可以避免获取不必要的数据,提高查询效率并节省资源,同时也能准确获取到我们所需的摘要信息内容。
|
|
|
|
|
// 查询的筛选条件通过SQL语句形式指定为 `NoteColumns.ID + "=?"`,表示按照笔记的ID进行筛选,其中 `?` 是占位符,后续通过 `new String [] { String.valueOf(noteId)}` 将实际的笔记ID(`noteId` 参数,先将其转换为字符串形式以便符合SQL语句中参数传递的要求)传入作为筛选条件的值,以此精确查找对应ID的笔记记录,确保获取的是指定笔记的摘要信息。
|
|
|
|
|
// 最后一个参数 `null` 表示无排序、分组等其他额外的查询条件设定,就是单纯按照给定的笔记ID来获取其摘要信息,保持查询的简洁性和针对性。
|
|
|
|
|
Cursor cursor = resolver.query(Notes.CONTENT_NOTE_URI,
|
|
|
|
|
new String [] { NoteColumns.SNIPPET },
|
|
|
|
|
NoteColumns.ID + "=?",
|
|
|
|
|
new String [] { String.valueOf(noteId)},
|
|
|
|
|
null);
|
|
|
|
|
|
|
|
|
|
// 判断游标对象 `cursor` 是否获取成功(即不为 `null`),如果游标获取成功,说明查询操作至少在获取游标这一步是正常执行的,接下来可以尝试从游标中获取数据(也就是笔记的摘要信息),前提是游标中存在符合条件的数据记录。
|
|
|
|
|
if (cursor!= null) {
|
|
|
|
|
// 初始化一个空字符串 `snippet`,用于存储后续从游标中获取到的笔记摘要信息。如果最终没能从游标中获取到有效的摘要信息(比如对应笔记存在但摘要字段为空等情况),这个空字符串也能保证方法按照预期返回一个合适的值,避免返回 `null` 等可能导致调用者出现空指针异常的情况,使程序逻辑更加健壮。
|
|
|
|
|
String snippet = "";
|
|
|
|
|
// 将游标移动到第一条数据位置(因为通常查询结果中如果有符合条件的数据,第一条就是我们要找的对应笔记记录所在位置,当然,如果没找到符合条件的数据,这个操作会返回 `false`,后续就不会执行获取数据的操作了),准备尝试获取其中的摘要信息字段值。
|
|
|
|
|
if (cursor.moveToFirst()) {
|
|
|
|
|
// 通过 `cursor.getString(0)` 尝试从游标当前指向的记录中获取第一个(也是唯一一个,因为前面查询只指定了获取摘要信息这一个字段,索引从0开始计数)字段的值,也就是笔记的摘要信息,并将其赋值给 `snippet` 变量进行存储,完成了从数据库查询结果中提取摘要信息到变量的操作。
|
|
|
|
|
snippet = cursor.getString(0);
|
|
|
|
|
}
|
|
|
|
|
// 无论是否成功从游标中获取到了摘要信息,都要关闭游标对象 `cursor`,释放相关的系统资源(比如数据库连接等资源),避免资源泄漏,这是良好的编程习惯,确保系统资源能合理利用,防止因未关闭游标而导致潜在的性能问题或资源耗尽问题。
|
|
|
|
|
cursor.close();
|
|
|
|
|
// 将获取到的(或者初始化为空字符串的)笔记摘要信息 `snippet` 返回给调用者,完成方法的功能,即提供对应笔记的摘要信息字符串,以便调用者根据此摘要信息进行后续的业务逻辑处理,比如在界面上展示摘要内容等操作。
|
|
|
|
|
return snippet;
|
|
|
|
|
}
|
|
|
|
|
// 如果游标对象 `cursor` 为 `null`,说明根据给定的笔记ID在数据库中没有找到对应的笔记记录,这种情况下抛出 `IllegalArgumentException` 异常,并在异常信息中明确提示 “Note is not found with id: ” 加上传入的笔记ID,告知调用者试图获取摘要信息的笔记不存在,方便调用者根据异常情况进行相应的错误处理,例如给用户显示相应的提示信息等操作。
|
|
|
|
|
throw new IllegalArgumentException("Note is not found with id: " + noteId);
|
|
|
|
|
}
|
|
|
|
|
/**
|
|
|
|
|
* 该静态方法用于对给定的笔记摘要信息字符串进行格式化处理,主要的格式化操作包括去除字符串两端的空白字符(空格、制表符、换行符等),以及如果字符串中包含换行符,则截取换行符之前的内容作为最终的格式化结果返回。
|
|
|
|
|
* 如果传入的字符串为 `null`,则直接返回 `null`,不进行任何格式化操作。
|
|
|
|
|
*
|
|
|
|
|
* @param snippet 要进行格式化处理的笔记摘要信息字符串,它可能是从数据库中获取到的原始摘要内容,也可能是其他来源的相关字符串,该方法会对其进行格式调整后返回更符合展示或使用要求的字符串形式。
|
|
|
|
|
* @return 返回经过格式化处理后的笔记摘要信息字符串,如果传入的字符串为 `null`,则直接返回 `null`;如果字符串不为 `null`,则按照上述的格式化规则处理后返回相应的结果,方便后续在界面展示或其他业务逻辑中使用格式化后的摘要内容。
|
|
|
|
|
*/
|
|
|
|
|
public static String getFormattedSnippet(String snippet) {
|
|
|
|
|
// 首先判断传入的 `snippet` 字符串是否为 `null`,如果是 `null`,说明没有有效的摘要信息传入,这种情况下不需要进行任何格式化操作,直接按照方法的约定返回 `null`,保持与输入的一致性,避免对 `null` 值进行不必要的处理导致出现空指针异常等问题。
|
|
|
|
|
if (snippet!= null) {
|
|
|
|
|
// 使用 `trim` 方法去除 `snippet` 字符串两端的空白字符(包括空格、制表符、换行符等),使字符串在展示或后续使用时更加整洁,去除不必要的空白部分,这是一种常见的字符串预处理操作,有助于提高数据的规范性和可读性。
|
|
|
|
|
snippet = snippet.trim();
|
|
|
|
|
|
|
|
|
|
// 使用 `indexOf` 方法查找 `snippet` 字符串中第一个换行符(`\n`)出现的位置索引,如果找到了换行符(返回值不为 `-1`),说明字符串中包含换行内容,按照格式化要求,我们只取换行符之前的内容作为最终的摘要信息。
|
|
|
|
|
int index = snippet.indexOf('\n');
|
|
|
|
|
if (index!= -1) {
|
|
|
|
|
// 通过 `substring` 方法截取从字符串开头到换行符位置(不包含换行符本身)的子字符串,将截取后的字符串重新赋值给 `snippet`,实现了去除换行符及之后内容的操作,使摘要信息更加简洁明了,符合格式化的预期效果。
|
|
|
|
|
snippet = snippet.substring(0, index);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// 返回经过上述格式化处理后的 `snippet` 字符串,如果传入的字符串为 `null`,则返回 `null`;如果经过格式化操作有了相应的调整,则返回调整后的字符串内容,以便后续根据这个格式化后的摘要信息进行展示、存储或其他相关业务逻辑处理。
|
|
|
|
|
return snippet;
|
|
|
|
|
}
|