Слишком много времени ушло на сохранение контакта - PullRequest
0 голосов
/ 18 января 2019

Я сохраняю около 250 контактов в телефонной книге. И каждый контакт занимает около 1 секунды, чтобы сохранить в списке контактов. В моем приложении мне может понадобиться сохранить более 10 000 контактов. Тогда потребуется несколько часов, чтобы спасти их. Итак, я хочу способ, чтобы быстро сохранить все контакты. Ваш ответ мне очень поможет:)

Вот метод, который я использую с циклом for для сохранения контакта -

public static String saveNewContact(String name, String number, ContentResolver contentResolver){
    ContentValues values = new ContentValues();
    values.put(Contacts.People.NUMBER, number);
    values.put(Contacts.People.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_CUSTOM);
    values.put(Contacts.People.LABEL, name);
    values.put(Contacts.People.NAME, name);
    Uri dataUri = contentResolver.insert(Contacts.People.CONTENT_URI, values);
    Uri updateUri = Uri.withAppendedPath(dataUri, Contacts.People.Phones.CONTENT_DIRECTORY);
    values.clear();
    values.put(Contacts.People.Phones.TYPE, Contacts.People.TYPE_MOBILE);
    values.put(Contacts.People.NUMBER, number);
    updateUri = contentResolver.insert(updateUri, values);
    return getContactID(updateUri, contentResolver);
}


public static String getContactID(Uri contactUri, ContentResolver contentResolver){
    String id = "";
    Cursor cursor = contentResolver.query(contactUri, null,
            null, null, null);
    if (cursor != null && cursor.moveToFirst()) {
        int idx = cursor.getColumnIndex(ContactsContract.Contacts._ID);
        id = cursor.getString(idx);
    }

    return id;
}

EDIT - пробовал и этот код, но результаты те же

ArrayList<ContentProviderOperation> cntProOper = new ArrayList<>();
    int contactIndex = cntProOper.size();

    cntProOper.add(ContentProviderOperation.newInsert(ContactsContract.RawContacts.CONTENT_URI)
            .withValue(ContactsContract.RawContacts.ACCOUNT_TYPE, null)
            .withValue(ContactsContract.RawContacts.ACCOUNT_NAME, null).build());

    cntProOper.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
            .withValueBackReference(ContactsContract.RawContacts.Data.RAW_CONTACT_ID, contactIndex)
            .withValue(ContactsContract.RawContacts.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE)
            .withValue(ContactsContract.CommonDataKinds.StructuredName.DISPLAY_NAME, name)
            .build());

    cntProOper.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, contactIndex)
            .withValue(ContactsContract.RawContacts.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE)
            .withValue(ContactsContract.CommonDataKinds.Phone.NUMBER, number)
            .withValue(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE).build()); //Type like HOME, MOBILE etc
    try {
        contentResolver.applyBatch(ContactsContract.AUTHORITY, cntProOper);
    } catch (RemoteException | OperationApplicationException exp) {}

1 Ответ

0 голосов
/ 19 января 2019

Хорошо, много вещей, чтобы упомянуть здесь ...

Для вашего первого кода, НИКОГДА НЕ ИСПОЛЬЗУЙТЕ Contacts.People.XX API, если серьезно, для чего угодно, убедитесь, что вы ничего не импортируете из People или не используете какой-либо из его API, это очень очень старый API, который был устарел много лет назад и даже не поддерживается некоторыми устройствами.

Относительно вашего второго кода, множества ошибок и проблем, которые я попытался исправить в своем коде ниже, но специально для вашего требования к производительности, обратите внимание, что вам не нужно applyBatch для каждого контакта, если вы Если вы создаете много контактов одновременно, это нормально, если вы поместите много операций в ваш ops ArrayList и примените их все за один раз - намного быстрее!

Примечания:

  1. Это ДОЛЖНО дать вам 100-кратное увеличение для размера кэша, равного 100, но вы можете поиграть с этим числом, просто отметьте, что, если число слишком велико, вы рискуете получить предупреждение Java «Transaction Too Large», и пакет не удастся .
  2. Всегда снабжайте значения ACCOUNT_TYPE / ACCOUNT_NAME чем-то связанным с вашим приложением. Я добавил к этому коду два постоянных значения MY_ACCOUNT_TYPE / MY_ACCOUNT_NAME, которые вам нужно определить.


ArrayList<ContentProviderOperation> ops = new ArrayList<>();
for (int i = 0; i < 10000; i++) {
    createContact(ops, name, phone);
    if (i % 100 == 0) { // experiment with different batch sizes to achieve best performance times
        try {
            contentResolver.applyBatch(ContactsContract.AUTHORITY, ops);
        } catch (RemoteException | OperationApplicationException e) {
            Log.e(TAG, "error applying batch: ", e);
        }
        ops = new ArrayList<>();
    }
}

private void createContact(ArrayList<ContentProviderOperation> ops, String name, String phone) {

    ops.add(ContentProviderOperation.newInsert(RawContacts.CONTENT_URI)
            .withValue(RawContacts.ACCOUNT_TYPE, MY_ACCOUNT_TYPE)
            .withValue(RawContacts.ACCOUNT_NAME, MY_ACCOUNT_NAME).build());

    int indexOfRawContactIdOperation = ops.size() - 1;

    ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, indexOfRawContactIdOperation)
            .withValue(ContactsContract.Data.MIMETYPE, StructuredName.CONTENT_ITEM_TYPE)
            .withValue(StructuredName.DISPLAY_NAME, name)
            .build());

    ops.add(ContentProviderOperation.newInsert(ContactsContract.Data.CONTENT_URI)
            .withValueBackReference(ContactsContract.Data.RAW_CONTACT_ID, indexOfRawContactIdOperation)
            .withValue(ContactsContract.Data.MIMETYPE, Phone.CONTENT_ITEM_TYPE)
            .withValue(Phone.NUMBER, number)
            .withValue(Phone.TYPE, Phone.TYPE_MOBILE).build());
}
...