gpt4 book ai didi

android - ExpandableListView 的 SimpleCursorTreeAdapter 和 CursorLoader

转载 作者:IT老高 更新时间:2023-10-28 23:00:23 29 4
gpt4 key购买 nike

我正在尝试通过使用 CursorLoaderSimpleCursorTreeAdapter 来异步查询提供程序

这是我的 Fragment 类,它实现了 CursorLoader

public class GroupsListFragment extends ExpandableListFragment implements
LoaderManager.LoaderCallbacks<Cursor> {

private final String DEBUG_TAG = getClass().getSimpleName().toString();

private static final String[] CONTACTS_PROJECTION = new String[] {
ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME };

private static final String[] GROUPS_SUMMARY_PROJECTION = new String[] {
ContactsContract.Groups.TITLE, ContactsContract.Groups._ID,
ContactsContract.Groups.SUMMARY_COUNT,
ContactsContract.Groups.ACCOUNT_NAME,
ContactsContract.Groups.ACCOUNT_TYPE,
ContactsContract.Groups.DATA_SET };

GroupsAdapter mAdapter;

@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);

populateContactList();

getLoaderManager().initLoader(-1, null, this);
}

public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// This is called when a new Loader needs to be created.
Log.d(DEBUG_TAG, "onCreateLoader for loader_id " + id);
CursorLoader cl;
if (id != -1) {
// child cursor
Uri contactsUri = ContactsContract.Data.CONTENT_URI;
String selection = "(("
+ ContactsContract.CommonDataKinds.GroupMembership.DISPLAY_NAME
+ " NOTNULL) AND ("
+ ContactsContract.CommonDataKinds.GroupMembership.HAS_PHONE_NUMBER
+ "=1) AND ("
+ ContactsContract.CommonDataKinds.GroupMembership.DISPLAY_NAME
+ " != '') AND ("
+ ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID
+ " = ? ))";
String sortOrder = ContactsContract.CommonDataKinds.GroupMembership.DISPLAY_NAME
+ " COLLATE LOCALIZED ASC";
String[] selectionArgs = new String[] { String.valueOf(id) };

cl = new CursorLoader(getActivity(), contactsUri,
CONTACTS_PROJECTION, selection, selectionArgs, sortOrder);
} else {
// group cursor
Uri groupsUri = ContactsContract.Groups.CONTENT_SUMMARY_URI;
String selection = "((" + ContactsContract.Groups.TITLE
+ " NOTNULL) AND (" + ContactsContract.Groups.TITLE
+ " != '' ))";
String sortOrder = ContactsContract.Groups.TITLE
+ " COLLATE LOCALIZED ASC";
cl = new CursorLoader(getActivity(), groupsUri,
GROUPS_SUMMARY_PROJECTION, selection, null, sortOrder);
}

return cl;
}

public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Swap the new cursor in.
int id = loader.getId();
Log.d(DEBUG_TAG, "onLoadFinished() for loader_id " + id);
if (id != -1) {
// child cursor
if (!data.isClosed()) {
Log.d(DEBUG_TAG, "data.getCount() " + data.getCount());
try {
mAdapter.setChildrenCursor(id, data);
} catch (NullPointerException e) {
Log.w("DEBUG","Adapter expired, try again on the next query: "
+ e.getMessage());
}
}
} else {
mAdapter.setGroupCursor(data);
}

}

public void onLoaderReset(Loader<Cursor> loader) {
// This is called when the last Cursor provided to onLoadFinished()
// is about to be closed.
int id = loader.getId();
Log.d(DEBUG_TAG, "onLoaderReset() for loader_id " + id);
if (id != -1) {
// child cursor
try {
mAdapter.setChildrenCursor(id, null);
} catch (NullPointerException e) {
Log.w("TAG", "Adapter expired, try again on the next query: "
+ e.getMessage());
}
} else {
mAdapter.setGroupCursor(null);
}
}

/**
* Populate the contact list
*/
private void populateContactList() {
// Set up our adapter
mAdapter = new GroupsAdapter(getActivity(),this,
android.R.layout.simple_expandable_list_item_1,
android.R.layout.simple_expandable_list_item_1,
new String[] { ContactsContract.Groups.TITLE }, // Name for group layouts
new int[] { android.R.id.text1 },
new String[] { ContactsContract.Contacts.DISPLAY_NAME }, // Name for child layouts
new int[] { android.R.id.text1 });

setListAdapter(mAdapter);
}
}

这是我的适配器,它继承了 SimpleCursorTreeAdapter

public class GroupsAdapter extends SimpleCursorTreeAdapter {

private final String DEBUG_TAG = getClass().getSimpleName().toString();

private ContactManager mActivity;
private GroupsListFragment mFragment;

// Note that the constructor does not take a Cursor. This is done to avoid
// querying the database on the main thread.
public GroupsAdapter(Context context, GroupsListFragment glf,
int groupLayout, int childLayout, String[] groupFrom,
int[] groupTo, String[] childrenFrom, int[] childrenTo) {

super(context, null, groupLayout, groupFrom, groupTo, childLayout,
childrenFrom, childrenTo);
mActivity = (ContactManager) context;
mFragment = glf;
}

@Override
protected Cursor getChildrenCursor(Cursor groupCursor) {
// Given the group, we return a cursor for all the children within that group
int groupId = groupCursor.getInt(groupCursor
.getColumnIndex(ContactsContract.Groups._ID));

Log.d(DEBUG_TAG, "getChildrenCursor() for groupId " + groupId);

Loader loader = mActivity.getLoaderManager().getLoader(groupId);
if ( loader != null && loader.isReset() ) {
mActivity.getLoaderManager().restartLoader(groupId, null, mFragment);
} else {
mActivity.getLoaderManager().initLoader(groupId, null, mFragment);
}

}

}

问题是,当我单击父组之一时,三件事中的一件会以一种不一致的方式发生。

1) 要么组打开, child 出现在它下面

2) 组未打开,setChildrenCursor() 调用抛出 NullPointerException 错误,该错误被 try catch block 捕获

3) 组不开,不报错

以下是组展开并显示子项的场景中的一些调试输出:

当显示所有组时,它会输出:

05-20 10:08:22.765: D/GroupsListFragment(22132): onCreateLoader for loader_id -1
05-20 10:08:23.613: D/GroupsListFragment(22132): onLoadFinished() for loader_id -1

-1是组游标的loader_id

然后,如果我特别选择一个组(我们称之为 A 组),它会输出:

05-20 23:22:31.140: D/GroupsAdapter(13844): getChildrenCursor() for groupId 67
05-20 23:22:31.140: D/GroupsListFragment(13844): onCreateLoader for loader_id 67
05-20 23:22:31.254: D/GroupsListFragment(13844): onLoadFinished() for loader_id 67
05-20 23:22:31.254: D/GroupsListFragment(13844): data.getCount() 4
05-20 23:22:31.254: W/GroupsListFragment(13844): Adapter expired, try again on the next query: null

组不展开,NullPointerException 被捕获。然后,如果我选择另一个组(我们称之为 B 组),它会输出:

05-20 23:25:38.089: D/GroupsAdapter(13844): getChildrenCursor() for groupId 3
05-20 23:25:38.089: D/GroupsListFragment(13844): onCreateLoader for loader_id 3
05-20 23:25:38.207: D/GroupsListFragment(13844): onLoadFinished() for loader_id 3
05-20 23:25:38.207: D/GroupsListFragment(13844): data.getCount() 6

这一次,NullPointerException 没有被抛出。而不是扩展 B 组,而是扩展 A 组。

谁能解释 setChildrenCursor() 调用所表现出的行为?

我认为在 onCreateLoader() 中如何实例化组/子 CursorLoader 存在问题。对于组 CursorLoader 我只想要手机中的所有组。子 CursorLoader 应包含组内的所有联系人。有谁知道可能是什么问题?

更新

感谢@Yam 的建议,我现在修改了 getChildrenCursor() 方法。我现在选择 groupCursor 位置而不是 ContactsContract.Groups._ID 的值来传递给 initLoader() 调用。我还将逻辑更改为仅在 loader 不为 null 且 loader isReset 为 false 时调用 restartLoader()。

protected Cursor getChildrenCursor(Cursor groupCursor) {
// Given the group, we return a cursor for all the children within that
// group
int groupPos = groupCursor.getPosition();
Log.d(DEBUG_TAG, "getChildrenCursor() for groupPos " + groupPos);

Loader loader = mActivity.getLoaderManager().getLoader(groupPos);
if (loader != null && !loader.isReset()) {
mActivity.getLoaderManager().restartLoader(groupPos, null, mFragment);
} else {
mActivity.getLoaderManager().initLoader(groupPos, null, mFragment);
}

return null;
}

这绝对更有意义,并且不会表现出组有时而不是其他时间扩展的一些不稳定行为。

但是,有些联系人显示在他们不属于的组下。还有一些组中确实有联系人,但不会显示任何联系人。所以看来 getChildrenCursor() 问题现在可以解决了。

但现在看来,CursorLoader 是如何在 onCreateLoader() 方法中实例化的问题。 onCreateLoader() 方法中返回的 CursorLoader 是否为子光标实例化不正确?

更新

所以我发现了我的一个问题。在 getChildrenCursor() 方法中,如果我将 groupId 传递给 initLoader() 方法,然后在 onCreateLoader() 方法中,当 CursorLoader 已创建,它将为查询获取正确的 groupid 参数。但是,在 onLoadFinished() 中,对 setChildrenCursor() 的调用正在传递第一个参数而不是 groupPosition 的加载程序 ID。我猜我必须将加载器 ID 映射到某些数据结构中的组位置。但我不确定这是否是最好的方法。有人有什么建议吗?

最佳答案

所以我发现我需要将 loaderids 映射到 groupPositions,这解决了我的问题:

这是我的 Fragment 类,它实现了 CursorLoader

public class GroupsListFragment extends ExpandableListFragment implements
LoaderManager.LoaderCallbacks<Cursor> {

private final String DEBUG_TAG = getClass().getSimpleName().toString();

private static final String[] CONTACTS_PROJECTION = new String[] {
ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME };

private static final String[] GROUPS_PROJECTION = new String[] {
ContactsContract.Groups.TITLE, ContactsContract.Groups._ID };

GroupsAdapter mAdapter;

@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);

populateContactList();

// Prepare the loader. Either re-connect with an existing one,
// or start a new one.
Loader loader = getLoaderManager().getLoader(-1);
if (loader != null && !loader.isReset()) {
getLoaderManager().restartLoader(-1, null, this);
} else {
getLoaderManager().initLoader(-1, null, this);
}
}

public Loader<Cursor> onCreateLoader(int id, Bundle args) {
// This is called when a new Loader needs to be created.
Log.d(DEBUG_TAG, "onCreateLoader for loader_id " + id);
CursorLoader cl;
if (id != -1) {
// child cursor
Uri contactsUri = ContactsContract.Data.CONTENT_URI;
String selection = "((" + ContactsContract.Contacts.DISPLAY_NAME
+ " NOTNULL) AND ("
+ ContactsContract.Contacts.HAS_PHONE_NUMBER + "=1) AND ("
+ ContactsContract.Contacts.DISPLAY_NAME + " != '') AND ("
+ ContactsContract.CommonDataKinds.GroupMembership.GROUP_ROW_ID
+ " = ? ))";
String sortOrder = ContactsContract.Contacts.DISPLAY_NAME
+ " COLLATE LOCALIZED ASC";
String[] selectionArgs = new String[] { String.valueOf(id) };

cl = new CursorLoader(getActivity(), contactsUri,
CONTACTS_PROJECTION, selection, selectionArgs, sortOrder);
} else {
// group cursor
Uri groupsUri = ContactsContract.Groups.CONTENT_URI;
String selection = "((" + ContactsContract.Groups.TITLE
+ " NOTNULL) AND (" + ContactsContract.Groups.TITLE
+ " != '' ))";
String sortOrder = ContactsContract.Groups.TITLE
+ " COLLATE LOCALIZED ASC";
cl = new CursorLoader(getActivity(), groupsUri,
GROUPS_PROJECTION, selection, null, sortOrder);
}

return cl;
}

public void onLoadFinished(Loader<Cursor> loader, Cursor data) {
// Swap the new cursor in.
int id = loader.getId();
Log.d(DEBUG_TAG, "onLoadFinished() for loader_id " + id);
if (id != -1) {
// child cursor
if (!data.isClosed()) {
Log.d(DEBUG_TAG, "data.getCount() " + data.getCount());

HashMap<Integer,Integer> groupMap = mAdapter.getGroupMap();
try {
int groupPos = groupMap.get(id);
Log.d(DEBUG_TAG, "onLoadFinished() for groupPos " + groupPos);
mAdapter.setChildrenCursor(groupPos, data);
} catch (NullPointerException e) {
Log.w("DEBUG","Adapter expired, try again on the next query: "
+ e.getMessage());
}
}
} else {
mAdapter.setGroupCursor(data);
}

}

public void onLoaderReset(Loader<Cursor> loader) {
// This is called when the last Cursor provided to onLoadFinished()
// is about to be closed.
int id = loader.getId();
Log.d(DEBUG_TAG, "onLoaderReset() for loader_id " + id);
if (id != -1) {
// child cursor
try {
mAdapter.setChildrenCursor(id, null);
} catch (NullPointerException e) {
Log.w("TAG", "Adapter expired, try again on the next query: "
+ e.getMessage());
}
} else {
mAdapter.setGroupCursor(null);
}
}

/**
* Populate the contact list
*/
private void populateContactList() {
// Set up our adapter
mAdapter = new GroupsAdapter(getActivity(),this,
android.R.layout.simple_expandable_list_item_1,
android.R.layout.simple_expandable_list_item_1,
new String[] { ContactsContract.Groups.TITLE }, // Name for group layouts
new int[] { android.R.id.text1 },
new String[] { ContactsContract.Contacts.DISPLAY_NAME }, // Name for child layouts
new int[] { android.R.id.text1 });

setListAdapter(mAdapter);
}
}

这是我的适配器,它继承了 SimpleCursorTreeAdapter

public class GroupsAdapter extends SimpleCursorTreeAdapter {

private final String DEBUG_TAG = getClass().getSimpleName().toString();

private ContactManager mActivity;
private GroupsListFragment mFragment;

protected final HashMap<Integer, Integer> mGroupMap;

// Note that the constructor does not take a Cursor. This is done to avoid
// querying the database on the main thread.
public GroupsAdapter(Context context, GroupsListFragment glf,
int groupLayout, int childLayout, String[] groupFrom,
int[] groupTo, String[] childrenFrom, int[] childrenTo) {

super(context, null, groupLayout, groupFrom, groupTo, childLayout,
childrenFrom, childrenTo);
mActivity = (ContactManager) context;
mFragment = glf;
mGroupMap = new HashMap<Integer, Integer>();
}

@Override
protected Cursor getChildrenCursor(Cursor groupCursor) {
// Given the group, we return a cursor for all the children within that group
int groupPos = groupCursor.getPosition();
int groupId = groupCursor.getInt(groupCursor
.getColumnIndex(ContactsContract.Groups._ID));
Log.d(DEBUG_TAG, "getChildrenCursor() for groupPos " + groupPos);
Log.d(DEBUG_TAG, "getChildrenCursor() for groupId " + groupId);

mGroupMap.put(groupId, groupPos);

Loader loader = mActivity.getLoaderManager().getLoader(groupId);
if ( loader != null && !loader.isReset() ) {
mActivity.getLoaderManager().restartLoader(groupId, null, mFragment);
} else {
mActivity.getLoaderManager().initLoader(groupId, null, mFragment);
}

return null;
}

//Accessor method
public HashMap<Integer, Integer> getGroupMap() {
return mGroupMap;
}

}

关于android - ExpandableListView 的 SimpleCursorTreeAdapter 和 CursorLoader,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10611927/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com