質問

I'm developing a REST application to delete contacts (and I mean Contacts, not Raw Contacts) in bulk. It is taking me more than 3 minutes to delete a batch of ~116 contacts, it's way to much in my opinion. Sometimes it prints Contacts deleted but they are still in the phone's contact list, other times they are really deleted.

Can anyone point me out where is the problem here?

I receive a JSONArray containing the Contact's ID (and a few other details, but only the IDs are used in this method) that shall be deleted.

Here's my delete contact code:

public Boolean deleteBatchContact(final JSONArray jsonArray) throws JSONException, RemoteException, OperationApplicationException
{
    final ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
    final Long startTime = System.currentTimeMillis();

    if(jsonArray.length() != 0) // there must be something in the JSONArray
    {
        for(int i = 0; i < jsonArray.length(); i++)
        {
            final JSONObject jsonContactObject = jsonArray.getJSONObject(i);
            final String contactId = jsonContactObject.getString("id");
            Long id = Long.parseLong(contactId);

            ops.add(ContentProviderOperation.newDelete(ContentUris.withAppendedId(Contacts.CONTENT_URI, Long.parseLong(contactId)))
                    .withYieldAllowed(true)
                    .build());
        }

        try {
            final ContentProviderResult[] cpr = contentResolver.applyBatch(ContactsContract.AUTHORITY, ops);
            final Long endTimeTry = System.currentTimeMillis();
            final Integer numberOfContactsDeleted = cpr.length;

            if(numberOfContactsDeleted > 0)
            {
                Log.d(TAG, numberOfContactsDeleted + " Contacts deleted!");
                final Long totalSuccess = endTimeTry-startTime;
                Log.d(TAG, "Total Time (Sucess): " + totalSuccess);

                return true;
            }
            else 
            {
                Log.d(TAG, "Menor ou igual a zero...");
                final Long totalFailed = endTimeTry-startTime;
                Log.d(TAG, "Total Time (No deletes): " + totalFailed);
                return false;
            }

        } catch (Exception e) {
            Log.d(TAG, "deleteBatchContact: " + e.getMessage());
            return false;
        }
    }
    Long endTimeReturnFalse = System.currentTimeMillis();
    Long totalTimeReturnFalse = endTimeReturnFalse - startTime;
    Log.d(TAG, "Total time return false: " + totalTimeReturnFalse);
    return false;
}

And here is where I call the deleteBatchContact method:

else if(type.equalsIgnoreCase("delete"))
    {
        Log.d(TAG, "DELETE REQUEST");
        String strJson = request.getEntityAsText();
        int age = response.getAge();
        Log.d(TAG, "age1: " + age);
        Log.d(TAG, "is commited1? " + response.isCommitted());
        try {
            Log.d(TAG, "Try...");
            JSONArray jsonArray = new JSONArray(strJson);
            if(processDelete(jsonArray) == true)
            {
                Log.d(TAG, "Response -> Deleted with Success!");
                response.setEntity("Deleted with success!", MediaType.TEXT_ALL);
                age = response.getAge();
                Log.d(TAG, "age2: " + age);
                Log.d(TAG, "is commited2? " + response.isCommitted());
            }
            else
            {
                Log.d(TAG, "Response -> No contacts deleted...");
                response.setEntity("No contacts deleted...", MediaType.TEXT_ALL);
                age = response.getAge();
                Log.d(TAG, "age3: " + age);
                Log.d(TAG, "is commited3? " + response.isCommitted());
            }
        } catch (RemoteException e) {
            Log.d(TAG, "processDelete exception: " + e.getMessage());
            e.printStackTrace();
        } catch (JSONException e) {
            Log.d(TAG, "processDelete exception: " + e.getMessage());
            e.printStackTrace();
        } catch (OperationApplicationException e) {
            Log.d(TAG, "processDelete exception: " + e.getMessage());
            e.printStackTrace();
        }

    }

Here is the output:

02-13 01:28:04.484: D/ContactRestlet(17638): DELETE REQUEST
02-13 01:28:04.507: D/ContactRestlet(17638): age1: 0
02-13 01:28:04.507: D/ContactRestlet(17638): is commited1? false
02-13 01:28:04.507: D/ContactRestlet(17638): Try...
02-13 01:30:04.671: D/ContactRestlet(17638): DELETE REQUEST
02-13 01:30:04.671: D/ContactRestlet(17638): age1: 0
02-13 01:30:04.671: D/ContactRestlet(17638): is commited1? false
02-13 01:30:04.671: D/ContactRestlet(17638): Try...
02-13 01:31:07.468: D/ContactList(17638): 116 Contacts deleted!
02-13 01:31:07.468: D/ContactList(17638): Total Time (Sucess): 182911
02-13 01:31:07.468: D/ContactRestlet(17638): Response -> Deleted with Success!
02-13 01:31:07.472: D/ContactRestlet(17638): age2: 0
02-13 01:31:07.472: D/ContactRestlet(17638): is commited2? false
02-13 01:31:07.476: W/System.err(17638): 2014-02-13 01:31:07    -   -   -   8080    DELETE  /contacts   -   1001    21  12590   62837   http://10.17.1.72:8080  Apache-HttpClient/4.3.1 (java 1.5)  -

EDIT: As suggested by @RocketRandom, here is my new code:

    public Boolean deleteBatchContact(final JSONArray jsonArray) throws JSONException, RemoteException, OperationApplicationException
{
    final ArrayList<ContentProviderOperation> ops = new ArrayList<ContentProviderOperation>();
    final Long startTime = System.currentTimeMillis();

    if(jsonArray.length() != 0) // there must be something in the JSONArray
    {
        StringBuilder query = new StringBuilder(" in {");
        for(int i = 0; i < jsonArray.length(); i++)
        {   
            final JSONObject jsonContactObject = jsonArray.getJSONObject(i);
            final String contactId = jsonContactObject.getString("id");

            query.append(contactId).append(",");
        }
        query.deleteCharAt(query.length()-1);
        query.append("}");

        ops.add(ContentProviderOperation.newDelete(Contacts.CONTENT_URI)
        .withSelection(Contacts._ID + " in { 1 , 2 , 3 , 4 , 5, 6, 7, 8, 9}", null).build()); 

        try {
            final ContentProviderResult[] cpr = contentResolver.applyBatch(ContactsContract.AUTHORITY, ops);
            final Long endTimeTry = System.currentTimeMillis();
            final Integer numberOfContactsDeleted = cpr.length;

            if(numberOfContactsDeleted > 0)
            {
                Log.d(TAG, numberOfContactsDeleted + " Contacts deleted!");
                final Long totalSuccess = endTimeTry-startTime;
                Log.d(TAG, "Total Time (Sucess): " + totalSuccess);

                return true;
            }
            else 
            {
                Log.d(TAG, "Menor ou igual a zero...");
                final Long totalFailed = endTimeTry-startTime;
                Log.d(TAG, "Total Time (No deletes): " + totalFailed);
                return false;
            }
        } catch (Exception e) {
            Log.d(TAG, "deleteBatchContact: " + e.getMessage());
            return false;
        }
    }
    Long endTimeReturnFalse = System.currentTimeMillis();
    Long totalTimeReturnFalse = endTimeReturnFalse - startTime;
    Log.d(TAG, "Total time return false: " + totalTimeReturnFalse);
    return false;
}

And this is the output:

03-06 01:42:10.367: D/ContactList(8925): 1 Contacts deleted!
03-06 01:42:10.367: D/ContactList(8925): Total Time (Sucess): 84

Now it's not deleting any contact, can you spot where's the error? Even tho it said one contact deleted, none as deleted. All those contact ids are valid (they do exist on my contacts table, I've downloaded it from my device and check it up.)

役に立ちましたか?

解決

Edit : Removed earlier suggested solution. It does not work. (Sorry for that)

I checked the contacts provider code and bulk deletion is only supported for raw contacts. For contacts all they do in there implementation is just return and they have a a nice little "TODO" there.

Your original code is the right way to do it. What the provider does when you delete a contact (without the isCallerSyncAdapter flag) is it queries all the raw contacts with that contact id and sets there dirty flag one by one ( So that takes a while)

i tried out at my end :

03-19 13:28:11.620: D/tmp(5912): 188 Contacts deleted!

03-19 13:28:11.620: D/tmp(5912): Total Time (Sucess): 387496

i.e takes around 2 seconds per contact which is horrible. But I don't see a way to make it faster without modifying the Android Contacts ContentProvider

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top