के लिए मैं अतुल्यकालिक रूप से एक SimpleCursorTreeAdapter
SimpleCursorTreeAdapter और CursorLoader ExpandableListView
यहाँ के साथ एक CursorLoader
का उपयोग करके एक प्रदाता क्वेरी करने के लिए कोशिश कर रहा हूँ मेरी 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) या तो समूह को खोलता है और बच्चों को यह
2) के नीचे दिखाई देते समूह नहीं खुलती है और setChildrenCursor()
कॉल एक NullPointerException
त्रुटि जो कोशिश कैच ब्लॉक
3) में पकड़ा जाता है फेंकता समूह नहीं खुलती है और कोई त्रुटि
यहाँ फेंक दिया जाता है एक परिदृश्य में कुछ डिबगिंग आउटपुट, जिसमें एक समूह का विस्तार होता है और बच्चों को दिखा रहा है:
सभी समूहों disp रहे हैं रखी यह ouputs:
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 है
फिर अगर मैं विशेष रूप से (सिर्फ यह समूह एक कॉल) यह आउटपुट में एक समूह का चयन करें:
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
पकड़ा जाता है। तो अगर मैं एक और समूह का चयन करें (सिर्फ यह समूह बी कॉल) यह आउटपुट:
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
फेंक नहीं है। और समूह बी के विस्तार के बजाय, समूह ए का विस्तार किया गया है।
क्या कोई इस व्यवहार को समझा सकता है कि setChildrenCursor()
कॉल प्रदर्शित हो रहा है?
मुझे लगता है कि समूह/बच्चे कर्सर लोडर onCreateLoader()
में तत्काल कैसे हैं, इस समस्या में कोई समस्या है। समूह CursorLoader
के लिए मैं बस अपने फोन में सभी समूह चाहता हूं। बच्चे CursorLoader
में समूह के भीतर सभी संपर्क होना चाहिए। क्या किसी के पास कोई विचार है कि समस्या क्या हो सकती है?
अद्यतन
@ रतालू की सलाह के लिए धन्यवाद मैं अब getChildrenCursor()
विधि संशोधित किया है। अब मैं initLoader() कॉल में पास करने के लिए ContactContract.Groups._ID का मान नहीं है, तो कर्सर स्थिति का चयन कर रहा हूं। मैंने रीस्टार्ट लोडर() को कॉल करने के लिए तर्क भी बदल दिया जब लोडर शून्य नहीं है और लोडर है रीसेट गलत है।
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()
मुद्दों को हल किया जा सकता है।
लेकिन अब यह एक मुद्दा है कि onCreateLoader()
विधि में कर्सर लोडर को तत्काल कैसे किया जाता है। क्या CursorLoader
onCreateLoader()
में बाल कर्सर को अनुचित तरीके से तत्काल करने के लिए विधि में लौटाया गया है?
अद्यतन
तो मैं अपने मुद्दों में से एक की पहचान की है। getChildrenCursor()
विधि में यदि मैं समूह को initLoader()
विधि में onCreateLoader()
विधि में पास करता हूं, तो CursorLoader
बनाया गया है, तो यह क्वेरी के लिए सही समूहबद्ध पैरामीटर प्राप्त करेगा। हालांकि, onLoadFinished()
में setChildrenCursor()
पर कॉल पहले पैरामीटर के लिए लोडर आईडी पास नहीं कर रहा है समूह समूह नहीं। मुझे लगता है कि मुझे कुछ डेटा संरचना में समूह की स्थिति में लोडर आईडी को मैप करना होगा। लेकिन मुझे यकीन नहीं है कि यह सबसे अच्छा तरीका है या नहीं। क्या किसी के पास कोई सुझाव है?
मैंने अभी यह किया है, लेकिन यह एक कर्सर लोडर का उपयोग नहीं कर रहा था, इसलिए यह मुझे फेंक रहा है ...मेरे कार्यान्वयन में, getChildrenCursor एक कर्सर देता है। लोडरमेनर के साथ, वह कर्सर/डेटा वास्तव में कहां जा रहा है? यदि आप कन्स्ट्रक्टर में कर्सर नहीं खिला रहे हैं, तो ग्रुप कर्सर के रूप में 'GetChildrenCursor' में क्या खिलाया जा रहा है? – Barak
समूह कर्सर लोडरमेनर के ऑनलोड लोड() विधि में सेट किया गया है। मैंने डीबगर के साथ कोड के माध्यम से कदम उठाया है और getChildenCursor() विधि में, समूह कर्सर हमेशा परिभाषित किया जाता है। – toobsco42
मुझे पता नहीं है, यह वास्तव में लगता है जैसे आप हमेशा एक आबादी वाले बच्चे नहीं मिल रहे हैं कर्सर ... – Barak