Android загружает контакты слишком медленно


В моем приложении есть 5 блесен, заполненных контактами в телефоне. Я использую код ниже, чтобы заполнить массив контактами, а затем заполнить блесны элементами массива (здесь только 1 блесна).

Когда пользователь открывает приложение, блесны заполняются, чтобы пользователь мог выбрать одно имя для каждого блесны. Дело в том, что загрузка макета с блеснами занимает около 3 секунд, когда пользователь открывает приложение. Поиграв с кодом я понял что не важно как возможно, прядильщики находятся в приложении, источником проблемы является код, который заполняет массив контактами. Я также нашел причину медлительности: я запустил приложение на своем телефоне братьев, и там оно открылось так быстро, как и должно было. У него всего 30 контактов в телефоне, в то время как у меня около 500, большинство из них-контакты на Facebook. Итак, как я могу помочь в этой ситуации?

Вот в чем проблема, независимо от количества прядильщиков. В случае слишком большого количества контактов, это получает медленно:

 contactName = null;
        final Context context = getApplicationContext();

        ContentResolver cr = getContentResolver();
        Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
        if (cur.getCount() > 0) 
        {
            while (cur.moveToNext()) {
            String idc = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
            String namec = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));

            if (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0) 
            {
                Cursor pCur = cr.query(
                ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, 
                ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?", new String[]{idc}, null);
                while (pCur.moveToNext()) {
                    contactName  = pCur.getString(pCur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME)); 

                    myArr.add(contactName);
                } 
                pCur.close();
                }

            }
        }

        myArr.add("");
        Collections.sort(myArr);

Вот как я заполняю каждый спиннер (и заставляю их показывать ранее выбранное имя):

        Spinner sp1 = (Spinner) findViewById(R.id.Spinner01);
        ArrayAdapter<String> adapter1 = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, myArr);
        sp1.setAdapter(adapter1);
        sp1.setOnItemSelectedListener(new MyOnItemSelectedListener1());


        mprefs = PreferenceManager.getDefaultSharedPreferences(getBaseContext());
        val1 = mprefs.getString("value1", "No name");
        if (!val1.equals("No name"))  
        {
            for (int i=0; i<myArr.size(); i++)
            {
                if (val1.equals(myArr.get(i))) 
                {
                    num = i;
                }
            }
            sp1.setSelection(num);
        }
        else
        {
            sp1.setSelection(0);
        }

Решение основано на идее Джесси ван Ассена:

Оказалось, что проблема была во втором запросе. Я удалил его и создал переменную" projection " для нужных мне столбцов:

final String[] projection = new String[] {
                ContactsContract.Contacts._ID,
                ContactsContract.Contacts.DISPLAY_NAME,
                ContactsContract.Contacts.HAS_PHONE_NUMBER
        };
        String selection = ContactsContract.Contacts.HAS_PHONE_NUMBER + "='1'";

        ContentResolver cr = getContentResolver();
        Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, projection, selection, null, null);
        if (cur.getCount() > 0) 
        {
            while (cur.moveToNext()) {
            String idc = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
            String namec = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
            myArr.add(namec);
            }
        }

Итак, теперь у меня есть один запрос, который собирает только необходимые записи. Однако он был медленным даже с запросом набора данных и со вторым запросом. Реальным решением было удалить второй запрос, однако собрать меньше записей, чем вся база данных, - отличная идея.

2 2

2 ответа:

Я бы сказал, что способ, которым вы запрашиваете свои контактные данные, неверен.

Похоже, что вы извлекаете все ваши контакты со всеми данными контакта из базы данных,а затем фильтруете контакты в цикле while. Я бы предложил сделать это из запроса, что-то вроде этого (не проверено):

Cursor cur = cr.query(
    ContactsContract.Contacts.CONTENT_URI, 
    new String[] { "_ID", "DISPLAY_NAME" },
    "HAS_PHONE_NUMBER = ?", new String[] { "1" }, 
    null);

Ваши блесны заполняли бы намного быстрее , если бы вы использовали break, чтобы выпрыгнуть из вашей for-петли, как только вы назначите

num = i