Android联系人查询 - 光标索引超出范围

Posted

技术标签:

【中文标题】Android联系人查询 - 光标索引超出范围【英文标题】:Android Contacts Query - cursor index out of bounds 【发布时间】:2014-02-13 07:57:26 【问题描述】:

我正在尝试查询联系电话号码和姓名。在编写此方法时,我很确定它将为每个电话号码提供一个新的姓名/号码条目。在我按原样工作后,我会担心在单个联系人下列出号码...

我在第 160 行遇到光标索引越界错误,但不知道为什么(联系人仍然很新鲜)。我已经粘贴了弹出错误的方法以及logcat。

请帮我找出这个错误。另外,如果您知道一种更有效的查询方式,我将不胜感激。

提前致谢

编辑:

感谢 Graham Borland,我发现我的简单错误是“moveToNext()”的位置。将其移动到 for 循环的末尾修复了崩溃。我是对的,它为每个电话号码创建了一个新条目。但是我有这个联系人有 3 个号码,所以它给出了 3 个条目,现在我可以接受,但它在每个条目中给出了相同的号码。有什么想法吗?

private void getContacts() 

    String name, number, label;

    uri = CommonDataKinds.Phone.CONTENT_URI;
    projection = new String[]  CommonDataKinds.Phone.DISPLAY_NAME,
            CommonDataKinds.Phone.NUMBER, CommonDataKinds.Phone.LABEL ;
    selection = null;
    selectionArgs = null;
    sortOrder = CommonDataKinds.Phone.DISPLAY_NAME;

    Cursor peopleCursor = getContentResolver().query(uri, projection,
            selection, selectionArgs, sortOrder);

    if (peopleCursor != null) 

        int indexName = peopleCursor
                .getColumnIndex(CommonDataKinds.Phone.DISPLAY_NAME);
        int indexNumber = peopleCursor
                .getColumnIndex(CommonDataKinds.Phone.NUMBER);
        int indexLabel = peopleCursor
                .getColumnIndex(CommonDataKinds.Phone.LABEL);

        peopleCursor.moveToFirst();

        for (int i = 0; i < peopleCursor.getCount(); i++) 

            ContactNameItems nameItems = new ContactNameItems();
            ContactPhoneItems phoneItems = new ContactPhoneItems();
            numberList = new ArrayList<ContactPhoneItems>();

            peopleCursor.moveToNext();

            name = peopleCursor.getString(indexName);  // This is line 160
            number = peopleCursor.getString(indexNumber);
            label = peopleCursor.getString(indexLabel);

            if (name != null && !name.isEmpty()) 

                nameItems.setName(name);
                mListDataHeader.add(nameItems);

                if (number != null && !number.isEmpty()) 

                    phoneItems.setNumber(number);
                    phoneItems.setPhoneType(label);

                    numberList.add(phoneItems);

                    mListDataChild.put(mListDataHeader.get(i).getName(),
                            numberList);
                    mListAdapter.notifyDataSetChanged();

                
            
        
    
    peopleCursor.close();




01-22 21:42:21.347: E/androidRuntime(793): FATAL EXCEPTION: main
01-22 21:42:21.347: E/AndroidRuntime(793): java.lang.RuntimeException: Unable to resume activity com.psesto.expandablelistview/com.psesto.expandablelistview.MainActivity: android.database.CursorIndexOutOfBoundsException: Index 5 requested, with a size of 5
01-22 21:42:21.347: E/AndroidRuntime(793):  at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2742)
01-22 21:42:21.347: E/AndroidRuntime(793):  at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2771)
01-22 21:42:21.347: E/AndroidRuntime(793):  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2235)
01-22 21:42:21.347: E/AndroidRuntime(793):  at android.app.ActivityThread.access$600(ActivityThread.java:141)
01-22 21:42:21.347: E/AndroidRuntime(793):  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1234)
01-22 21:42:21.347: E/AndroidRuntime(793):  at android.os.Handler.dispatchMessage(Handler.java:99)
01-22 21:42:21.347: E/AndroidRuntime(793):  at android.os.Looper.loop(Looper.java:137)
01-22 21:42:21.347: E/AndroidRuntime(793):  at android.app.ActivityThread.main(ActivityThread.java:5041)
01-22 21:42:21.347: E/AndroidRuntime(793):  at java.lang.reflect.Method.invokeNative(Native Method)
01-22 21:42:21.347: E/AndroidRuntime(793):  at java.lang.reflect.Method.invoke(Method.java:511)
01-22 21:42:21.347: E/AndroidRuntime(793):  at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
01-22 21:42:21.347: E/AndroidRuntime(793):  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
01-22 21:42:21.347: E/AndroidRuntime(793):  at dalvik.system.NativeStart.main(Native Method)
01-22 21:42:21.347: E/AndroidRuntime(793): Caused by: android.database.CursorIndexOutOfBoundsException: Index 5 requested, with a size of 5
01-22 21:42:21.347: E/AndroidRuntime(793):  at android.database.AbstractCursor.checkPosition(AbstractCursor.java:424)
01-22 21:42:21.347: E/AndroidRuntime(793):  at android.database.AbstractWindowedCursor.checkPosition(AbstractWindowedCursor.java:136)
01-22 21:42:21.347: E/AndroidRuntime(793):  at android.database.AbstractWindowedCursor.getString(AbstractWindowedCursor.java:50)
01-22 21:42:21.347: E/AndroidRuntime(793):  at android.database.CursorWrapper.getString(CursorWrapper.java:114)
01-22 21:42:21.347: E/AndroidRuntime(793):  at com.psesto.expandablelistview.MainActivity.getContacts(MainActivity.java:160)
01-22 21:42:21.347: E/AndroidRuntime(793):  at com.psesto.expandablelistview.MainActivity.onResume(MainActivity.java:58)
01-22 21:42:21.347: E/AndroidRuntime(793):  at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1185)
01-22 21:42:21.347: E/AndroidRuntime(793):  at android.app.Activity.performResume(Activity.java:5182)
01-22 21:42:21.347: E/AndroidRuntime(793):  at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2732)
01-22 21:42:21.347: E/AndroidRuntime(793):  ... 12 more

修复:

private void getContacts()

String name, number, label;

uri = CommonDataKinds.Phone.CONTENT_URI;
projection = new String[]  CommonDataKinds.Phone.DISPLAY_NAME,
        CommonDataKinds.Phone.NUMBER, CommonDataKinds.Phone.LABEL ;
selection = null;
selectionArgs = null;
sortOrder = CommonDataKinds.Phone.DISPLAY_NAME;

Cursor peopleCursor = getContentResolver().query(uri, projection,
        selection, selectionArgs, sortOrder);

if (peopleCursor != null) 

    int indexName = peopleCursor
            .getColumnIndex(CommonDataKinds.Phone.DISPLAY_NAME);
    int indexNumber = peopleCursor
            .getColumnIndex(CommonDataKinds.Phone.NUMBER);
    int indexLabel = peopleCursor
            .getColumnIndex(CommonDataKinds.Phone.LABEL);

    peopleCursor.moveToFirst();

    for (int i = 0; i < peopleCursor.getCount(); i++) 

        ContactNameItems nameItems = new ContactNameItems();
        ContactPhoneItems phoneItems = new ContactPhoneItems();
        numberList = new ArrayList<ContactPhoneItems>();

        name = peopleCursor.getString(indexName);  // This is line 160
        number = peopleCursor.getString(indexNumber);
        label = peopleCursor.getString(indexLabel);

        if (name != null && !name.isEmpty()) 

            nameItems.setName(name);
            mListDataHeader.add(nameItems);

            if (number != null && !number.isEmpty()) 

                phoneItems.setNumber(number);
                phoneItems.setPhoneType(label);

                numberList.add(phoneItems);

                mListDataChild.put(mListDataHeader.get(i).getName(),
                        numberList);
                mListAdapter.notifyDataSetChanged();

            
        

        peopleCursor.moveToNext();
    

peopleCursor.close();

【问题讨论】:

【参考方案1】:

试试这个干净的迭代:

for (cursor.moveToFirst(); !cursor.isAfterLast(); cursor.moveToNext()) 
    // do what you need with the cursor here

这是一个典型的错误。 Cursor.moveToFirst() 已经将光标移动到第一个位置,然后Cursor.moveToNext() 将其移动到下一个跳过第一个位置。

要使您的代码正常工作,请从您的代码中删除 Cursor.moveToFirst()

附带说明,如果您正在寻找更简洁的方式来处理游标和内容提供者,请尝试使用这个库:https://github.com/futuresimple/android-db-commons

它会将代码的重要部分更改为以下内容:

   numberList = ProviderAction.query(CommonDataKinds.Phone.CONTENT_URI)
        .projection(CommonDataKinds.Phone.DISPLAY_NAME,
            CommonDataKinds.Phone.NUMBER,
            CommonDataKinds.Phone.LABEL)
        .perform(getContentResolver())
        .toFluentIterable(new Function<Cursor, ContactPhoneItems>() 
          @Override
          public ContactPhoneItems apply(Cursor cursor) 
            ContactPhoneItems item = new ContactPhoneItems();
            item.setNumber(cursor.getString(cursor.getColumnIndexOrThrow(CommonDataKinds.Phone.NUMBER)));
            item.setPhoneType(cursor.getString(cursor.getColumnIndexOrThrow(CommonDataKinds.Phone.LABEL)));
            return item;
          

        )
        .filter(new Predicate<ContactPhoneItems>() 
          @Override
          public boolean apply(ContactPhoneItems contactPhoneItems) 
            return !TextUtils.isEmpty(contactPhoneItems.getNumber());
          
        );

【讨论】:

【参考方案2】:
 peopleCursor.moveToFirst();

 for (int i = 0; i < peopleCursor.getCount(); i++) 

     // do some setup
     peopleCursor.moveToNext();
     // read data from the cursor

这是一种非常复杂且错误的遍历游标的方式。当您第一次读取数据时,您已经移动到第二行(moveToFirst() 后跟moveToNext())。在循环的第 5 次迭代中,您已经超过了结果的末尾,这导致了错误。

改用简单的while 循环。

while (peopleCursor.moveToNext()) 
    ....

更多解释请见What's the best way to iterate an Android Cursor?。

【讨论】:

我需要添加一个数组列表的值,这就是我使用 for 的原因(如果你知道如何使用 'while' 来做同样的事情,我会全力以赴)。但我明白你在说“moveToNext”的位置。我要把它移到循环的末尾,看看会发生什么 好的...将它移到最后修复了崩溃(耶!)。我是对的,它为每个电话号码创建了一个新条目。但是我有这个联系人有 3 个号码,所以它给出了 3 个条目,现在我可以接受,但它在每个条目中给出了相同的号码。有什么想法吗? @WizardKnight 这是一个完全不同的故事。有一个很好的培训涵盖了 Android 联系人访问:developer.android.com/training/contacts-provider/index.html

以上是关于Android联系人查询 - 光标索引超出范围的主要内容,如果未能解决你的问题,请参考以下文章

在假设函数中执行数据库查询时列表索引超出范围

PreparedStatement 参数索引超出范围

Bigquery - 数组索引 5 超出范围

刷新时数组索引超出范围

致命错误:索引超出范围 - Swift 3 和 Firebase

Django -> queryset[index] 索引超出范围