Android ListView示例在结果视图中复制联系人

Android ListView示例在结果视图中复制联系人,android,listview,android-contacts,Android,Listview,Android Contacts,我正在尝试中找到的ListView示例。或多或少,我已经将示例中的代码复制到了活动中(我现在只省略了progressbar) 一切正常,除了列表视图显示我设备上的每个联系人的副本(运行Nexus7,Android 4.2) 每个联系人在列表视图中重复6-7次。我使用的游标已经返回了太多的结果(它应该只返回3个项目,因为我在Nexus atm上只有三个联系人。)。当我检查RAW\u CONTACT\u ID时,重复项总是指向相同的ID值(即,我只得到3个唯一的ID) 这意味着不是我的视图代码有问题

我正在尝试中找到的
ListView
示例。或多或少,我已经将示例中的代码复制到了活动中(我现在只省略了
progressbar

一切正常,除了
列表视图
显示我设备上的每个联系人的副本(运行Nexus7,Android 4.2)

每个联系人在
列表视图中重复6-7次。我使用的游标已经返回了太多的结果(它应该只返回3个项目,因为我在Nexus atm上只有三个联系人。)。当我检查
RAW\u CONTACT\u ID
时,重复项总是指向相同的ID值(即,我只得到3个唯一的ID)

这意味着不是我的视图代码有问题

所以问题是适配器中会出现什么问题

为什么光标返回所有联系人的副本?或者设备上是否存在导致返回这些副本的原因

我看了其他的问题,但似乎没有一个是关于这个问题的

public class ThemeSelectorActivity extends ListActivity implements LoaderManager.LoaderCallbacks{ private static final String TAG = "ThemeSelector"; // The rows that we will retrieve from the db (Contacts used as dummy data) static final String[] PROJECTION = new String[] {ContactsContract.Data._ID, ContactsContract.Data.DISPLAY_NAME}; // The select criteria for fetching contacts static final String SELECTION = "((" + ContactsContract.Data.DISPLAY_NAME + " NOTNULL) AND (" + ContactsContract.Data.DISPLAY_NAME + " != '' ))"; // The Adapter being used to display the list's data SimpleCursorAdapter mAdapter; @Override public void onCreate(Bundle savedInstanceState) { Log.d(TAG, "Create..."); super.onCreate(savedInstanceState); // set the listview to be selectable getListView().setChoiceMode(AbsListView.CHOICE_MODE_SINGLE); // For the cursor adapter, specify which columns go into which views String[] fromColumns = {ContactsContract.Data.DISPLAY_NAME}; int[] toViews = {android.R.id.text1}; // The TextView in simple_list_item_1 // Create an empty adapter we will use to display the loaded data. // We pass null for the cursor, then update it in onLoadFinished() mAdapter = new SimpleCursorAdapter(this, android.R.layout.simple_list_item_1, null, fromColumns, toViews, 0); setListAdapter( mAdapter ); // Prepare the loader. Either re-connect with an existing one, // or start a new one. getLoaderManager().initLoader(0, null, this); } // Called when a new Loader needs to be created public Loader onCreateLoader(int id, Bundle args) { // Now create and return a CursorLoader that will take care of // creating a Cursor for the data being displayed. return new CursorLoader(this, ContactsContract.Data.CONTENT_URI, PROJECTION, SELECTION, null, null); } // Called when a previously created loader has finished loading public void onLoadFinished(Loader loader, Cursor data) { // Swap the new cursor in. (The framework will take care of closing the // old cursor once we return.) mAdapter.swapCursor(data); } // Called when a previously created loader is reset, making the data unavailable public void onLoaderReset(Loader loader) { // This is called when the last Cursor provided to onLoadFinished() // above is about to be closed. We need to make sure we are no // longer using it. mAdapter.swapCursor(null); } @Override /** * Start activity that shows a preview of the selected theme */ public void onListItemClick(ListView l, View v, int position, long id) { super.onListItemClick(l, v, position, id); //String item = (String) getListAdapter().getItem(position); //Toast.makeText(this, item + " selected", Toast.LENGTH_LONG).show(); } } 公共类ThemeSelectorActivity扩展了ListActivity 实现LoaderManager.LoaderCallbacks{ 私有静态最终字符串TAG=“ThemeSelector”; //我们将从数据库中检索的行(联系人用作虚拟数据) 静态最终字符串[]投影=新字符串[]{contacts contract.Data.\u ID, contacts contract.Data.DISPLAY\u NAME}; //获取联系人的选择条件 静态最终字符串选择=“(”+ contacts contract.Data.DISPLAY_NAME+“NOTNULL)和(”+ contacts contract.Data.DISPLAY_NAME+“!=”); //用于显示列表数据的适配器 简单的适应; @凌驾 创建时的公共void(Bundle savedInstanceState) { Log.d(标记“创建…”); super.onCreate(savedInstanceState); //将listview设置为可选择 getListView().setChoiceMode(AbsListView.CHOICE\u MODE\u SINGLE); //对于光标适配器,指定哪些列进入哪些视图 String[]fromColumns={ContactsContract.Data.DISPLAY\u NAME}; int[]toViews={android.R.id.text1};//简单列表项目中的TextView //创建一个空适配器,用于显示加载的数据。 //我们为游标传递null,然后在onLoadFinished()中更新它 mAdapter=新的SimpleCursorAdapter(此, android.R.layout.simple_list_item_1,null, 从列到视图,0); setListAdapter(mAdapter); //准备加载程序。或者重新连接现有加载程序, //或者开始一个新的。 getLoaderManager().initLoader(0,null,this); } //需要创建新加载程序时调用 公共加载器onCreateLoader(int-id,Bundle-args){ //现在创建并返回一个游标加载程序,它将处理 //为正在显示的数据创建光标。 返回新的游标装入器(此,contacts contract.Data.CONTENT\u URI, 投影,选择,空,空); } //当先前创建的加载程序完成加载时调用 public void onLoadFinished(加载器、光标数据){ //在中交换新光标。(框架将负责关闭 //我们返回后,将返回旧光标。) mAdapter.swapCursor(数据); } //重置以前创建的加载程序时调用,使数据不可用 公共void onLoaderReset(加载器){ //当提供给onLoadFinished()的最后一个游标时调用 //以上内容即将关闭。我们需要确保我们没有 //不再使用它。 mAdapter.swapCursor(空); } @凌驾 /** *启动显示所选主题预览的活动 */ public void onListItemClick(列表视图l、视图v、整数位置、长id){ super.onListItemClick(左、右、位置、id); //字符串项=(字符串)getListAdapter().getItem(位置); //Toast.makeText(此项+选定项),Toast.LENGTH_LONG.show(); } }
Contacts contract.Data.CONTENT\u URI显示联系人的所有数据


您应该使用ContactsContract.Contacts.CONTENT\u URI

正如我所说,它基本上是我链接到()的示例的副本,只是暂时删除了进度指示器。但是更新了完整性问题,因为示例有效。你的代码基本上不是。为了确保我在测试中没有遗漏一些琐碎的东西,我在Eclipse中创建了一个新的Android项目(API级别15,min SDK版本14),只是逐步完成了新项目向导。然后复制粘贴示例中的所有代码,将类的名称从ListViewLoader更改为MainActivity(以匹配开始活动),将读取权限添加到清单中,然后运行示例。结果与之前相同,即显示联系人列表,但每个联系人都重复了几次。有什么想法吗?除非您需要跨多个子部分获取数据,否则这是可行的,在这种情况下,数据表实际上更易于处理,因为您可以在一个查询中完成。我同意您@BrillPappin的观点,如果您想获取电子邮件,您不能使用Contacts contract.Contacts.CONTENT\u URI。但是,嘿@BrillPappin,是否可以跨多个子部分而不是使用数据表获取数据?因为您说过处理数据表更容易。谢谢我认为您将需要多个查询,尽管每个android版本的API似乎都有一些变化。