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.
xiaomi/ui/NotesListAdapter.java

240 lines
16 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");
* 按照许可要求使用此文件,否则不允许使用。
* 可以通过以下网址获取许可证副本:
* http://www.apache.org/licenses/LICENSE-2.0
*
* 除非适用法律要求或书面同意,软件依据许可证分发是“按现状”分发,
* 不附带任何明示或暗示的保证或条件。请查看许可证了解具体权限和限制。
*/
// 所在包声明表明该类属于笔记应用net.micode.notes的用户界面ui相关模块。
package net.micode.notes.ui;
import android.content.Context;
import android.database.Cursor;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.CursorAdapter;
import net.micode.notes.data.Notes;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
// NotesListAdapter类继承自CursorAdapter是专门用于适配笔记列表数据与视图如ListView的适配器类
// 负责处理笔记数据展示、管理笔记项的选中状态等相关操作逻辑,是笔记列表界面展示与数据交互的重要组成部分。
public class NotesListAdapter extends CursorAdapter {
// 定义一个静态的字符串常量,作为日志输出时的标签,方便在查看日志时快速识别与该适配器相关的日志信息,利于调试与问题排查。
private static final String TAG = "NotesListAdapter";
// 用于保存上下文对象,通过构造函数传入,在整个适配器的生命周期内提供与应用环境相关的资源访问、视图创建等操作所需的上下文环境。
private Context mContext;
// 使用HashMap来存储笔记项在列表中的选中状态Integer类型为笔记项在列表中的位置索引Boolean类型表示对应位置的笔记项是否被选中
// 以此来跟踪用户在笔记列表中的多选操作情况,方便后续根据选中状态进行相应的数据处理和界面更新。
private HashMap<Integer, Boolean> mSelectedIndex;
// 记录笔记的数量(仅统计实际的笔记类型数据项数量,不包含文件夹等其他非笔记类型的数据),
// 该数量会在数据内容变化(如游标更新、数据重新加载)时通过重新计算得到,用于辅助判断如全选等相关业务逻辑。
private int mNotesCount;
// 用于标识当前适配器是否处于多选模式的布尔变量,通过设置该变量来控制适配器在不同模式下的数据处理、视图显示等行为逻辑,
// 例如在多选模式下需正确显示已选笔记项的选中状态、提供相应的批量操作菜单等。
private boolean mChoiceMode;
// 内部静态类用于封装与应用小部件Widget相关的属性信息主要包含小部件的唯一标识ID和小部件的类型信息
// 在涉及笔记与小部件关联的相关操作中,用于传递和处理小部件的相关属性数据。
public static class AppWidgetAttribute {
public int widgetId;
public int widgetType;
};
// 构造方法接收一个Context上下文对象调用父类CursorAdapter的构造方法并传入上下文以及初始化为null的游标对象
// 同时初始化用于记录选中状态的HashMap保存传入的上下文对象并将笔记数量初始化为0完成适配器的初始化设置。
public NotesListAdapter(Context context) {
super(context, null);
mSelectedIndex = new HashMap<Integer, Boolean>();
mContext = context;
mNotesCount = 0;
}
// 重写CursorAdapter的抽象方法用于创建新的视图对象该方法在需要为新的笔记项创建视图进行展示时被调用
// 此处简单地返回一个NotesListItem类型的视图实例通常NotesListItem是自定义的视图类用于具体实现笔记内容在界面上的展示布局等细节逻辑。
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent) {
return new NotesListItem(context);
}
// 重写CursorAdapter的抽象方法负责将数据绑定到已创建的视图上使其能够正确展示笔记信息
// 首先判断传入的视图是否是NotesListItem类型如果是则从游标中解析出笔记数据并封装成NoteItemData对象
// 然后调用NotesListItem的bind方法将上下文、笔记数据对象、当前的多选模式状态以及该笔记项是否被选中的状态传递进去
// 从而实现将数据与视图进行绑定,确保笔记信息准确显示在对应的视图上。
@Override
public void bindView(View view, Context context, Cursor cursor) {
if (view instanceof NotesListItem) {
NoteItemData itemData = new NoteItemData(context, cursor);
((NotesListItem) view).bind(context, itemData, mChoiceMode,
isSelectedItem(cursor.getPosition()));
}
}
// 用于设置指定位置笔记项的选中状态的公有方法接收笔记项在列表中的位置索引int类型和要设置的选中状态布尔值作为参数
// 将对应的位置和选中状态存入mSelectedIndex这个HashMap中之后调用notifyDataSetChanged方法通知适配器数据集已发生变化
// 触发视图的刷新操作,使得界面上该笔记项的选中状态显示能够根据新设置的状态进行更新,例如改变选中项的背景颜色等视觉效果。
public void setCheckedItem(final int position, final boolean checked) {
mSelectedIndex.put(position, checked);
notifyDataSetChanged();
}
// 用于判断当前适配器是否处于多选模式的公有方法直接返回表示多选模式状态的成员变量mChoiceMode的值
// 外部代码可以通过调用该方法来了解适配器当前所处的交互模式状态,进而执行与之对应的不同操作逻辑,例如在多选模式下显示特定的操作菜单等。
public boolean isInChoiceMode() {
return mChoiceMode;
}
// 用于设置适配器的多选模式状态的公有方法接收一个布尔值参数当进入多选模式时传入true
// 先清空之前记录的所有笔记项选中状态通过调用mSelectedIndex的clear方法然后将mChoiceMode变量设置为传入的模式值
// 此后适配器会根据新的模式状态调整相关的数据处理和视图交互逻辑,例如更新界面上笔记项的选中显示效果等。
public void setChoiceMode(boolean mode) {
mSelectedIndex.clear();
mChoiceMode = mode;
}
// 用于实现全选或全不选所有笔记项的公有方法,接收一个布尔值参数,根据该参数决定是将所有笔记项设置为选中还是取消选中状态,
// 首先获取当前适配器关联的游标对象通过调用getCursor方法然后遍历游标中的所有笔记项通过getCount方法获取笔记项总数并移动游标到每个位置
// 对于每个位置的笔记项通过NoteItemData.getNoteType方法判断其类型是否为笔记与Notes.TYPE_NOTE进行比较如果是笔记类型则调用setCheckedItem方法设置其选中状态。
public void selectAll(boolean checked) {
Cursor cursor = getCursor();
for (int i = 0; i < getCount(); i++) {
if (cursor.moveToPosition(i)) {
if (NoteItemData.getNoteType(cursor) == Notes.TYPE_NOTE) {
setCheckedItem(i, checked);
}
}
}
}
// 用于获取所有被选中笔记项的ID集合的公有方法创建一个HashSet<Long>类型的集合用于存储笔记项的ID
// 遍历mSelectedIndex这个记录选中状态的HashMap对于值为true即被选中的项通过调用getItemId方法获取其对应的笔记项ID
// 接着进行合法性判断如果获取到的ID等于Notes.ID_ROOT_FOLDER通常根文件夹ID不应作为笔记项被选中此处作为一种异常情况的判断
// 则在日志中输出相应提示信息使用Log.d方法输出调试级别的日志否则将合法的ID添加到HashSet集合中最后返回该包含所有选中笔记项ID的集合
// 方便外部代码基于这些ID进行批量操作如批量删除、批量移动等操作时确定具体操作的笔记对象。
public HashSet<Long> getSelectedItemIds() {
HashSet<Long> itemSet = new HashSet<Long>();
for (Integer position : mSelectedIndex.keySet()) {
if (mSelectedIndex.get(position) == true) {
Long id = getItemId(position);
if (id == Notes.ID_ROOT_FOLDER) {
Log.d(TAG, "Wrong item id, should not happen");
} else {
itemSet.add(id);
}
}
}
return itemSet;
}
// 用于获取所有被选中笔记项关联的小部件属性集合的公有方法创建一个HashSet<AppWidgetAttribute>类型的集合用于存储小部件相关属性对象,
// 遍历mSelectedIndex这个记录选中状态的HashMap对于值为true即被选中的项通过调用getItem方法获取对应的游标对象代表选中的笔记项数据
// 如果游标不为空则创建一个AppWidgetAttribute对象从游标数据中解析出小部件的ID和类型信息通过NoteItemData类的相关方法获取并赋值给该对象
// 然后将其添加到HashSet集合中最后返回包含所有选中笔记项关联小部件属性的集合该集合可用于后续与小部件相关的批量更新等操作
// 注意按照代码中的注释说明,此处不会关闭游标,游标关闭操作由适配器统一管理,以确保数据访问的正确性和一致性。
public HashSet<AppWidgetAttribute> getSelectedWidget() {
HashSet<AppWidgetAttribute> itemSet = new HashSet<AppWidgetAttribute>();
for (Integer position : mSelectedIndex.keySet()) {
if (mSelectedIndex.get(position) == true) {
Cursor c = (Cursor) getItem(position);
if (c!= null) {
AppWidgetAttribute widget = new AppWidgetAttribute();
NoteItemData item = new NoteItemData(mContext, c);
widget.widgetId = item.getWidgetId();
widget.widgetType = item.getWidgetType();
itemSet.add(widget);
/**
* Don't close cursor here, only the adapter could close it
*/
} else {
Log.e(TAG, "Invalid cursor");
return null;
}
}
}
return itemSet;
}
// 用于获取当前被选中笔记项数量的公有方法首先获取mSelectedIndex中所有值的集合即所有笔记项的选中状态值集合Collection<Boolean>类型),
// 如果该集合为空表示没有任何笔记项设置了选中状态则直接返回0否则通过迭代器Iterator<Boolean>)遍历该集合,
// 统计值为true即被选中的元素个数最后返回统计得到的选中笔记项数量方便外部代码根据选中数量进行相应的逻辑判断或操作提示等。
public int getSelectedCount() {
Collection<Boolean> values = mSelectedIndex.values();
if (null == values) {
return 0;
}
Iterator<Boolean> iter = values.iterator();
int count = 0;
while (iter.hasNext()) {
if (true == iter.next()) {
count++;
}
}
return count;
}
// 用于判断是否所有笔记项都被选中的公有方法首先通过调用getSelectedCount方法获取当前被选中笔记项的数量
// 然后判断如果选中数量不为0即至少有一个笔记项被选中且选中数量等于笔记的总数量通过比较与mNotesCount的值则返回true表示处于全选状态否则返回false
// 可用于在界面上显示全选相关的操作提示或进行与全选状态相关的业务逻辑处理等情况。
public boolean isAllSelected() {
int checkedCount = getSelectedCount();
return (checkedCount!= 0 && checkedCount == mNotesCount);
}
// 用于判断指定位置的笔记项是否被选中的公有方法通过获取mSelectedIndex中对应位置的选中状态值来判断
// 如果该位置的值为null可能是该位置的笔记项还未设置过选中状态则返回false表示未被选中否则返回对应位置记录的布尔值即是否被选中的状态
// 方便外部代码在处理具体的笔记项交互逻辑(如点击某个笔记项时)判断其当前的选中情况,进而执行相应的操作逻辑。
public boolean isSelectedItem(final int position) {
if (null == mSelectedIndex.get(position)) {
return false;
}
return mSelectedIndex.get(position);
}
// 重写父类CursorAdapter的方法当数据集的内容发生变化时例如数据库中的笔记数据有更新、插入或删除等操作导致游标所关联的数据改变会被调用
// 在此方法中先调用父类的onContentChanged方法执行默认的内容改变处理逻辑然后调用calcNotesCount私有方法重新计算笔记的总数量
// 以确保后续基于笔记数量的相关业务逻辑(如全选判断等)能够基于最新的数据情况进行正确操作。
@Override
protected void onContentChanged() {
super.onContentChanged();
calcNotesCount();
}
// 重写父类CursorAdapter的方法用于更改适配器所使用的游标对象通常意味着数据来源发生了变化比如重新从数据库查询获取了新的笔记数据
// 先调用父类的changeCursor方法完成游标切换的默认操作然后调用calcNotesCount私有方法重新计算笔记的总数量
// 使得适配器能够基于新的游标数据更新界面展示,并保证相关数据统计逻辑的准确性,确保后续各种基于笔记数据的操作和显示都是基于最新的有效数据。
@Override
public void changeCursor(Cursor cursor) {
super.changeCursor(cursor);
calcNotesCount();
}
// 私有方法用于计算笔记的总数量首先将mNotesCount初始化为0然后遍历游标中的所有笔记项通过getCount方法获取笔记项总数并移动游标到每个位置
// 对于每个笔记项通过NoteItemData.getNoteType方法判断其类型是否为笔记与Notes.TYPE_NOTE进行比较如果是笔记类型则将笔记总数量加1
// 在遍历过程中如果遇到游标为无效的情况即游标为null则通过Log.e方法输出错误日志信息并直接返回不再继续计算笔记数量
// 以此保证数量统计的准确性是基于有效的游标数据进行的,避免因无效游标导致的错误计算或异常情况。
private void calcNotesCount() {
mNotesCount = 0;
for (int i = 0; i < getCount(); i++) {
Cursor c = (Cursor) getItem(i);
if (c!= null) {
if (NoteItemData.getNoteType(c) == Notes.TYPE_NOTE) {
mNotesCount++;
}
} else {
Log.e(TAG, "Invalid cursor");
return;
}
}
}
}