内容简介:http://stackoverflow.com/questions/20585273/cursortreeadapter-with-search-implementation
申请了一个应用程序,我将CursorTreeAdapter用作ExpandableListView.现在我想使用搜索框显示已过滤的ExpandableListView项目.喜欢这个:
这是我到目前为止的代码
MainActivity.java:
package com.example.cursortreeadaptersearch; import java.util.HashMap; import android.app.SearchManager; import android.content.Context; import android.database.ContentObserver; import android.database.Cursor; import android.net.Uri; import android.os.Bundle; import android.os.Handler; import android.provider.ContactsContract; import android.support.v4.app.LoaderManager; import android.support.v4.app.LoaderManager.LoaderCallbacks; import android.support.v4.content.CursorLoader; import android.support.v4.content.Loader; import android.util.Log; import android.widget.ExpandableListView; import android.widget.SearchView; import android.widget.SearchView.OnCloseListener; import android.widget.SearchView.OnQueryTextListener; import com.actionbarsherlock.app.SherlockFragmentActivity; public class MainActivity extends SherlockFragmentActivity { private SearchView search; private MyListAdapter listAdapter; private ExpandableListView myList; private final String DEBUG_TAG = getClass().getSimpleName().toString(); /** * The columns we are interested in from the database */ static final String[] CONTACTS_PROJECTION = new String[] { ContactsContract.Contacts._ID, ContactsContract.Contacts.DISPLAY_NAME, ContactsContract.Contacts.PHOTO_ID, ContactsContract.CommonDataKinds.Email.DATA, ContactsContract.CommonDataKinds.Photo.CONTACT_ID }; 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 }; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); SearchManager searchManager = (SearchManager) getSystemService(Context.SEARCH_SERVICE); search = (SearchView) findViewById(R.id.search); search.setSearchableInfo(searchManager .getSearchableInfo(getComponentName())); search.setIconifiedByDefault(false); search.setOnQueryTextListener(new OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { listAdapter.filterList(query); expandAll(); return false; } @Override public boolean onQueryTextChange(String query) { listAdapter.filterList(query); expandAll(); return false; } }); search.setOnCloseListener(new OnCloseListener() { @Override public boolean onClose() { listAdapter.filterList(""); expandAll(); return false; } }); // get reference to the ExpandableListView myList = (ExpandableListView) findViewById(R.id.expandableList); // create the adapter listAdapter = new MyListAdapter(null, MainActivity.this); // attach the adapter to the list myList.setAdapter(listAdapter); Loader<Cursor> loader = getSupportLoaderManager().getLoader(-1); if (loader != null && !loader.isReset()) { runOnUiThread(new Runnable() { public void run() { getSupportLoaderManager().restartLoader(-1, null, mSpeakersLoaderCallback); } }); } else { runOnUiThread(new Runnable() { public void run() { getSupportLoaderManager().initLoader(-1, null, mSpeakersLoaderCallback).forceLoad(); ; } }); } } @Override public void onResume() { super.onResume(); getApplicationContext().getContentResolver().registerContentObserver( ContactsContract.Data.CONTENT_URI, true, mSpeakerChangesObserver); } @Override public void onPause() { super.onPause(); getApplicationContext().getContentResolver().unregisterContentObserver( mSpeakerChangesObserver); } // method to expand all groups private void expandAll() { int count = listAdapter.getGroupCount(); for (int i = 0; i < count; i++) { myList.expandGroup(i); } } public LoaderManager.LoaderCallbacks<Cursor> mSpeakersLoaderCallback = new LoaderCallbacks<Cursor>() { @Override public Loader<Cursor> onCreateLoader(int id, Bundle args) { Log.d(DEBUG_TAG, "onCreateLoader for loader_id " + id); CursorLoader cl = null; HashMap<Integer, Integer> groupMap = listAdapter.getGroupMap(); if (id != -1) { int groupPos = groupMap.get(id); if (groupPos == 0) { // E-mail group String[] PROJECTION = new String[] { ContactsContract.RawContacts._ID, ContactsContract.CommonDataKinds.Email.DATA }; String sortOrder = "CASE WHEN " + ContactsContract.Contacts.DISPLAY_NAME + " NOT LIKE '%@%' THEN 1 ELSE 2 END, " + ContactsContract.Contacts.DISPLAY_NAME + ", " + ContactsContract.CommonDataKinds.Email.DATA + " COLLATE NOCASE"; String selection = ContactsContract.CommonDataKinds.Email.DATA + " NOT LIKE ''"; cl = new CursorLoader(getApplicationContext(), ContactsContract.CommonDataKinds.Email.CONTENT_URI, PROJECTION, selection, null, sortOrder); } else if (groupPos == 1) { // Name group 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 + " = '1' ))"; // Row ID 1 == All contacts String sortOrder = ContactsContract.CommonDataKinds.GroupMembership.DISPLAY_NAME + " COLLATE LOCALIZED ASC"; cl = new CursorLoader(getApplicationContext(), contactsUri, CONTACTS_PROJECTION, selection, null, sortOrder); } } else { // group cursor Uri groupsUri = ContactsContract.Groups.CONTENT_SUMMARY_URI; String selection = "((" + ContactsContract.Groups.TITLE + " NOTNULL) AND (" + ContactsContract.Groups.TITLE + " == 'Coworkers' ) OR (" + ContactsContract.Groups.TITLE + " == 'My Contacts' ))"; // Select only Coworkers // (E-mail only) and My // Contacts (Name only) String sortOrder = ContactsContract.Groups.TITLE + " COLLATE LOCALIZED ASC"; cl = new CursorLoader(getApplicationContext(), groupsUri, GROUPS_SUMMARY_PROJECTION, selection, null, sortOrder); } return cl; } @Override public void onLoadFinished(Loader<Cursor> loader, Cursor data) { // Swap the new cursor in. int id = loader.getId(); // Log.d("Dump Cursor MainActivity", // DatabaseUtils.dumpCursorToString(data)); 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 = listAdapter .getGroupMap(); try { int groupPos = groupMap.get(id); Log.d(DEBUG_TAG, "onLoadFinished() for groupPos " + groupPos); listAdapter.setChildrenCursor(groupPos, data); } catch (NullPointerException e) { Log.w("DEBUG", "Adapter expired, try again on the next query: " + e.getMessage()); } } } else { listAdapter.setGroupCursor(data); } } @Override 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 { listAdapter.setChildrenCursor(id, null); } catch (NullPointerException e) { Log.w(DEBUG_TAG, "Adapter expired, try again on the next query: " + e.getMessage()); } } else { listAdapter.setGroupCursor(null); } } }; private ContentObserver mSpeakerChangesObserver = new ContentObserver( new Handler()) { @Override public void onChange(boolean selfChange) { if (getApplicationContext() != null) { runOnUiThread(new Runnable() { public void run() { getSupportLoaderManager().restartLoader(-1, null, mSpeakersLoaderCallback); } }); } } }; }
MyListAdapter.java:
package com.example.cursortreeadaptersearch; import java.util.HashMap; import android.content.Context; import android.database.Cursor; import android.provider.ContactsContract; import android.support.v4.content.Loader; import android.util.Log; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.CursorTreeAdapter; import android.widget.TextView; public class MyListAdapter extends CursorTreeAdapter { public HashMap<String, View> childView = new HashMap<String, View>(); /** * The columns we are interested in from the database */ private final String DEBUG_TAG = getClass().getSimpleName().toString(); protected final HashMap<Integer, Integer> mGroupMap; private MainActivity mActivity; private LayoutInflater mInflater; String mConstraint; public MyListAdapter(Cursor cursor, Context context) { super(cursor, context); mActivity = (MainActivity) context; mInflater = LayoutInflater.from(context); mGroupMap = new HashMap<Integer, Integer>(); } @Override public View newGroupView(Context context, Cursor cursor, boolean isExpanded, ViewGroup parent) { final View view = mInflater.inflate(R.layout.list_group, parent, false); return view; } @Override public void bindGroupView(View view, Context context, Cursor cursor, boolean isExpanded) { TextView lblListHeader = (TextView) view .findViewById(R.id.lblListHeader); if (lblListHeader != null) { lblListHeader.setText(cursor.getString(cursor .getColumnIndex(ContactsContract.Groups.TITLE))); } } @Override public View newChildView(Context context, Cursor cursor, boolean isLastChild, ViewGroup parent) { final View view = mInflater.inflate(R.layout.list_item, parent, false); return view; } @Override public void bindChildView(View view, Context context, Cursor cursor, boolean isLastChild) { TextView txtListChild = (TextView) view.findViewById(R.id.lblListItem); if (txtListChild != null) { txtListChild.setText(cursor.getString(1)); // Selects E-mail or // Display Name } } 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.getSupportLoaderManager().getLoader(groupId); if (loader != null && !loader.isReset()) { mActivity.getSupportLoaderManager().restartLoader(groupId, null, mActivity.mSpeakersLoaderCallback); } else { mActivity.getSupportLoaderManager().initLoader(groupId, null, mActivity.mSpeakersLoaderCallback); } return null; } // Access method public HashMap<Integer, Integer> getGroupMap() { return mGroupMap; } public void filterList(CharSequence constraint) { // TODO Filter the data here } }
我有非常大的简化和清理代码(所以你们不需要做).
正如你所看到的,我共有3个游标(组为1,孩子为2).数据来自 ContactsContract (这是用户的联系人).
来自子级1的光标表示所有联系人的所有电子邮件,来自子级别2的光标表示联系人的所有显示名称. (大多数装载机功能是从 here 开始).
现在唯一的办法是如何实现搜索?我应该通过内容提供者或数据库中的原始查询来做吗?我希望显示两个子表的结果.我认为,因为在打字时容易出错,这个tokenize = porter是我的例子中的一个选项.
我希望有人能指出我的方向很好.
编辑:
我已经在MyListAdapter.java中尝试过(
FilterQueryProvider
,建议为 Kyle I.
):
public void filterList(CharSequence constraint) { final Cursor oldCursor = getCursor(); setFilterQueryProvider(filterQueryProvider); getFilter().filter(constraint, new FilterListener() { public void onFilterComplete(int count) { // assuming your activity manages the Cursor // (which is a recommended way) notifyDataSetChanged(); // stopManagingCursor(oldCursor); // final Cursor newCursor = getCursor(); // startManagingCursor(newCursor); // // safely close the oldCursor if (oldCursor != null && !oldCursor.isClosed()) { oldCursor.close(); } } }); } private FilterQueryProvider filterQueryProvider = new FilterQueryProvider() { public Cursor runQuery(CharSequence constraint) { // assuming you have your custom DBHelper instance // ready to execute the DB request String s = '%' + constraint.toString() + '%'; return mActivity.getContentResolver().query(ContactsContract.Data.CONTENT_URI, MainActivity.CONTACTS_PROJECTION, ContactsContract.CommonDataKinds.GroupMembership.DISPLAY_NAME + " LIKE ?", new String[] { s }, null); } };
这在MainActivity.java中:
search.setOnQueryTextListener(new OnQueryTextListener() { @Override public boolean onQueryTextSubmit(String query) { listAdapter.filterList(query); expandAll(); return false; } @Override public boolean onQueryTextChange(String query) { listAdapter.filterList(query); expandAll(); return false; } }); search.setOnCloseListener(new OnCloseListener() { @Override public boolean onClose() { listAdapter.filterList(""); expandAll(); return false; } });
但是当我尝试搜索时,我会收到这些错误:
12-20 13:20:19.449: E/CursorWindow(28747): Failed to read row 0, column -1 from a CursorWindow which has 96 rows, 4 columns. 12-20 13:20:19.449: D/AndroidRuntime(28747): Shutting down VM 12-20 13:20:19.449: W/dalvikvm(28747): threadid=1: thread exiting with uncaught exception (group=0x415c62a0) 12-20 13:20:19.499: E/AndroidRuntime(28747): FATAL EXCEPTION: main 12-20 13:20:19.499: E/AndroidRuntime(28747): java.lang.IllegalStateException: Couldn't read row 0, col -1 from CursorWindow. Make sure the Cursor is initialized correctly before accessing data from it.
我做错了什么?或者是因为在runQuery中只返回1个查询(显示名称)而不是2个(显示名称和电子邮件)?
编辑2:
首先,我将所有的数据库实现都更改为 ContactsContract .这变得更容易维护,以便您不必编写自己的数据库实现.
我现在尝试的是将我的约束保存在
FilterQueryProvider
的runQuery()中,然后在getChildrenCursor中针对该约束运行查询. (如 JRaymond
所示)
private String mConstraint; 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); Bundle b = new Bundle(); b.putString("constraint", mConstraint); Loader loader = mActivity.getSupportLoaderManager().getLoader(groupId); if (loader != null && !loader.isReset()) { if (mConstraint == null || mConstraint.isEmpty()) { // Normal query mActivity.getSupportLoaderManager().restartLoader(groupId, null, mActivity.mSpeakersLoaderCallback); } else { // Constrained query mActivity.getSupportLoaderManager().restartLoader(groupId, b, mActivity.mSpeakersLoaderCallback); } } else { if (mConstraint == null || mConstraint.isEmpty()) { // Normal query mActivity.getSupportLoaderManager().initLoader(groupId, null, mActivity.mSpeakersLoaderCallback); } else { // Constrained query mActivity.getSupportLoaderManager().initLoader(groupId, b, mActivity.mSpeakersLoaderCallback); } } return null; }
这里是
FilterQueryProvider
:
private FilterQueryProvider filterQueryProvider = new FilterQueryProvider() { public Cursor runQuery(CharSequence constraint) { // Load the group cursor here and assign mConstraint mConstraint = constraint.toString(); Uri groupsUri = ContactsContract.Groups.CONTENT_SUMMARY_URI; String selection = "((" + ContactsContract.Groups.TITLE + " NOTNULL) AND (" + ContactsContract.Groups.TITLE + " == 'Coworkers' ) OR (" + ContactsContract.Groups.TITLE + " == 'My Contacts' ))"; // Select only Coworkers // (E-mail only) and My // Contacts (Name only) String sortOrder = ContactsContract.Groups.TITLE + " COLLATE LOCALIZED ASC"; return mActivity.getContentResolver().query(groupsUri, MainActivity.GROUPS_SUMMARY_PROJECTION, selection, null, sortOrder); } };
正如你所看到的,我加载了组的查询,以获得getChildrenCursor的工作.我应该从MainActivity中运行哪些查询?
该项目可以下载 here ,您可以在Eclipse中导入.
我已经研究了你的问题,不幸的是我没有时间复制你的设置.但是,在通用术语中,您应该能够保存约束,然后在“getChildrenCursor”中运行针对该约束的查询:
Cursor getChildrenCursor(Cursor groupCursor) { if (mConstraint == null || mConstraint.isEmpty()) { // Normal query } else { // Constrained query } }
我不确定,但是当您在filterQueryProvider()中返回游标时,我很确定getChildrenCursor()将被调用以响应父游标的更改.然后,您只需管理约束的空/填充状态.
细节:
在你的filterList函数中,而不是做一个复杂的过程,只需调用runQueryOnBackgroundThread(constraint);这将自动将数据库工作卸载到后台.将您的约束保存在filterQueryProvider中:
String s = '%' + constraint.toString() + '%'; mConstraint = s;
对于查询,它只取决于您要从数据库中获取的内容 – 快速调整您发布的代码运行查询,如下所示:
String selection = ContactsContract.CommonDataKinds.Email.DATA + " NOT LIKE ''"; if (constraint != null) { selection += " AND " + ContactsContract.CommonDataKinds.Email.DATA + " LIKE ?"; } cl = new CursorLoader(getApplicationContext(), ContactsContract.CommonDataKinds.Email.CONTENT_URI, PROJECTION, selection, constraint, sortOrder);
我不太确定的一件事是你要进行的自动扩展,我的过滤器可以工作,但是您需要重新打开并重新打开列表才能看到更改.
http://stackoverflow.com/questions/20585273/cursortreeadapter-with-search-implementation
以上所述就是小编给大家介绍的《java – 具有搜索实现的CursorTreeAdapter》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!
猜你喜欢:本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们。
The Everything Store
Brad Stone / Little, Brown and Company / 2013-10-22 / USD 28.00
The definitive story of Amazon.com, one of the most successful companies in the world, and of its driven, brilliant founder, Jeff Bezos. Amazon.com started off delivering books through the mail. Bu......一起来看看 《The Everything Store》 这本书的介绍吧!