How to Read Contacts in Android Using Realm

How to read contacts in Android using Realm?

Create RealmObject, read the data from content provider, save data to RealmObject, save data in Realm:

// background thread
Realm realm = null;
try {
realm = Realm.getDefaultInstance();
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
RealmContact realmContact = new RealmContact();
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));
realmContact.setName(name);
realmContact.setPhoneNumber(phoneNumber);
realm.insertOrUpdate(realmContact);
}
}
});
} finally {
if(realm != null) {
realm.close();
}
}

EDIT: okay, here's a trick to merging data and removing all data that's not in the list you've saving

public class RealmContract extends RealmObject {
@PrimaryKey
private long id;

@Index
private String name;

@Index
private String phoneNumber;

@Index
private boolean isBeingSaved;

//getters, setters
}

Then merge:

// background thread
Realm realm = null;
try {
realm = Realm.getDefaultInstance();
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
RealmContact realmContact = new RealmContact();
Cursor phones = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
while (phones.moveToNext()) {
String id = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds._ID));
String name = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String phoneNumber = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
realmContact.setId(id);
realmContact.setName(name);
realmContact.setPhoneNumber(phoneNumber);
realmContact.setIsBeingSaved(true);
realm.insertOrUpdate(realmContact);
}
realm.where(RealmContact.class)
.equalTo(RealmContactFields.IS_BEING_SAVED, false) // compile 'dk.ilios:realmfieldnameshelper:1.0.0'
.findAll()
.deleteAllFromRealm(); // delete all non-saved data
for(RealmContact realmContact : realm.where(RealmContact.class).findAll()) { // realm 0.89.0+
realmContact.setIsBeingSaved(false); // reset all save state
}
}
});
} finally {
if(realm != null) {
realm.close();
}
}

EDIT: Refer to OP's other question for reading contact data reliably (because there's something up with the Contact LOOKUP_ID and making sure the IDs are correct): Obtaining contacts from content provider without duplicates or invalid contacts, and save to Realm

Obtaining contacts from content provider without duplicates or invalid contacts, and save to Realm

Okay, after quite long searching I found that there was a typo:

        /** merge mechanism */
realm.where(Contact.class)
.equalTo("isBeingSaved", false)
.findAll()
.deleteAllFromRealm(); // delete all non-saved data
for(Contact contact : realm.where(Contact.class).findAll()) {
realmContact.setIsBeingSaved(false); <- here it is
}

It's realmContact when in fact it should be contact so it refers to contact iterated by for loop.

So, basically, it was setting Contact realmContact = new Contact(); to false. So the proper version is:

           /** merge mechanism */
realm.where(Contact.class)
.equalTo("isBeingSaved", false)
.findAll()
.deleteAllFromRealm(); // delete all non-saved data
for(Contact contact : realm.where(Contact.class).findAll()) {
contact.setIsBeingSaved(false);
}

How to read data from Realm

You're doing an asynchronous network call before accessing your data. The network call has not completed yet, therefore your data is empty. Put your data access code in the onSuccess() callback.

public class MainActivity extends AppCompatActivity {

...

public void onLogin() {

...

RequestHandle post = client.post(
"https://example.com/api/v1/auth",
rp,
new JsonHttpResponseHandler() {

@Override
public void onSuccess(
int statusCode,
Header[] headers,
JSONObject response) {
try {
String tokenString = response.getString("token");

mRealm.beginTransaction();
Config myConfig = mRealm.createObject(Config.class);
myConfig.name = "token";
myConfig.tokenValue = tokenString;
mRealm.commitTransaction();

populateData();
} catch (NullPointerException e) {
e.printStackTrace();
} catch (JSONException e) {
e.printStackTrace();
}
}

@Override
public void onFailure(
int statusCode,
Header[] headers,
String res,
Throwable t) {
// called when response HTTP status is "4XX" (eg. 401, 403, 404)
}
});
}

private void populateData() {
TextView tvHello = (TextView)findViewById(R.id.tvHello);
try {
RealmResults User =
mRealmInstance.where(Config.class).equalTo("name", "token").findAll();
if (User.size() > 0) {

String nameOfUser = User.get(0).toString();
tvHello.setText(nameOfUser);

} else if (User.size() == 0) {
Log.e("query","query size is "+User.size());
}
} catch (Exception e) {
e.printStackTrace();
}
}

Also note that you should use findAll() instead of findAllAsync(). Read the documentation for more information on the difference: https://realm.io/blog/realm-java-0-84-0/

Direct field access in Realm for Android

Emanuele from Realm here. Realm has been supporting public fields with no accessors since 0.88.0 https://realm.io/news/realm-java-0.88.0/

Loading contacts and saving to realm taking a very long time

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.

Error while reading data from Realm in android

You should be passing a RealmConfiguration to Realm.getInstance() not getApplicationContext(). It should look something like this.

RealmConfiguration config = new RealmConfiguration.Builder(context)
.name("myrealm.realm")
.build();
Realm realm = Realm.getInstance(config);

use realm instance across different activities which using predefined realm database

To be able to get a default, you have to set a default:

RealmConfiguration config1 = new RealmConfiguration.Builder(this)
.name("test")
.schemaVersion(1)
.migration(new Migration())
.build();

Realm.setDefaultConfiguration(config1); // <-- here

Now you can get it with

Realm.getDefaultInstance();

Realm in an Android Background Service

In an IntentService, you're supposed to treat the onHandleIntent method like the doInBackground method of an AsyncTask.

So it runs on the background thread and you should make sure you close the Realm in a finally block.

public class PollingService extends IntentService {
@Override
public void onHandleIntent(Intent intent) {
Realm realm = null;
try {
realm = Realm.getDefaultInstance();
// go do some network calls/etc and get some data
realm.executeTransaction(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
realm.createAllFromJson(Customer.class, customerApi.getCustomers()); // Save a bunch of new Customer objects
}
});
} finally {
if(realm != null) {
realm.close();
}
}
}
// ...
}

onCreate runs on the UI thread, so your initialization of the Realm happens on a different thread, which is a no-go.



Related Topics



Leave a reply



Submit