Search code examples
androidoptimizationandroid-asynctaskrealmcontacts

Loading contacts and saving to realm taking a very long time


In my app, I am attempting to save all contacts in the local store upon opening. My code works great when there aren't too many contacts to access. Though, when there are 100+ contacts, it takes forever to save them all. I am using Realm-- a DB framework, to turn each contact into a model object. This is the async task that runs when my app first opens

private class AppOpeningAsyncTask extends AsyncTask<Void,Void,Void> {

    // Operations performed in the background.
    @Override
    protected Void doInBackground(Void... params) {

        // Retrieving and saving users contacts
        Cursor phones = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
        while (phones.moveToNext())
        {
            String name=phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
            String phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
            Contact.createOrUpdateWithNameAndNumber(name, phoneNumber, (RoofActivity) mContext);
        }
        phones.close();

        return null;
    }

    // Operations performed on UI thread.
    @Override
    protected void onPostExecute(Void aVoid) {
        super.onPostExecute(aVoid);

        enterApp();

    }
}

And here is my Contact realm object:

public class Contact extends RealmObject {

private String name;

@PrimaryKey
private String number;

public static void createOrUpdateWithNameAndNumber(final String name, final String number, final RoofActivity activity){

    ((Activity)activity).runOnUiThread(new Runnable() {
        @Override
        public void run() {

            Realm realm = activity.getRealmInstance();
            Contact contact = realm
                    .where(Contact.class)
                    .equalTo("name", name)
                    .equalTo("number", number)
                    .findFirst();

            if (contact == null) {
                contact = new Contact();
            }

            realm.beginTransaction();

            contact.setName(name);
            contact.setNumber(number);

            realm.copyToRealmOrUpdate(contact);
            realm.commitTransaction();
        }
    });
}

public String getName() {
    return name;
}

public void setName(String name) {
    this.name = name;
}

public String getNumber() {
    return number;
}

public void setNumber(String number) {
    this.number = number;
}

}

It's important to note that I am only trying to save MOBILE numbers. Is there any way that I can optimize this code? Or are there any other approaches to retrieving this information more efficiently. Venmo seems to accomplish this pretty seamlessly.


Solution

  • You should be using a single write transaction for all of your updates rather than one per insertion, and you should not be dispatching your updates to the UI thread.

    Realm has some per-transaction overhead, and when you're inserting just a single object per transaction this overhead will be massively larger than the time spent actually inserting that object. Inserting 100 objects in a single transaction will probably take less time than two transactions which each insert just a single object.

    Dispatching your updates to the UI thread is the exact opposite of what you want to do; you should be trying to avoid performing write transaction on the UI thread, not going out of your way to do so when there's no reason to.