I can't find any solutions to read contacts from Android and save them in Realm. Anyone done that before?
I know that I will have to use Contacts Provider, but this is all I know. AFAIK, Realm doesn't support Cursor so...what else?
edit:
realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
Contact realmContact = new Contact();
String filter = "" + ContactsContract.Contacts.HAS_PHONE_NUMBER + " > 0 and "
+ ContactsContract.CommonDataKinds.Phone.TYPE +"="
+ ContactsContract.CommonDataKinds.Phone.TYPE_MAIN;
Cursor phones = getActivity()
.getContentResolver()
.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, filter, null, null);
while (phones.moveToNext()) {
String id = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone._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.setNumber(phoneNumber);
realmContact.setIsBeingSaved(true);
realm.insertOrUpdate(realmContact);
}
/** 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); // reset all save state
}
Contact.class
public class Contact extends RealmObject{
#PrimaryKey
private String id;
#Index
private String name;
#Index
private String number;
#Index
private boolean isBeingSaved;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
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;
}
public boolean getIsBeingSaved() {
return isBeingSaved;
}
public void setIsBeingSaved(boolean beingSaved) {
isBeingSaved = beingSaved;
}
}
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
You can create a Model Class to store desired data from contact
then using Cursor get data and set data in model class.
Save the cursor data in list of model object.
Then insert all model object in single transaction as per object transaction has overhead and slow our app
Related
I am working with android device contacts. if android device contacts more than five thousand,Fetch data from contacts take too much time with blank screen. I have used bellow code to fetch data
private void fetchContacts1() {
String order = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, order);
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String phonenumber = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
}
cursor.close();
}
I show all the contacts to recycle view.There are some devices which has more than ten thousand contacts. can you suggest me how to handle it.
Use the Async task to load your contacts in the background. after loading for first-time store your list of contacts to your local database
below following links may help you
https://developer.android.com/guide/components/loaders
https://stackoverflow.com/a/40017905/10239870
class ContactLoader extends AsyncTask<Void, Void, List<Contact>> {
#Override
protected void onPreExecute() {
super.onPreExecute();
//visible your progress bar here
}
#Override
protected List<Contact> doInBackground(Void... voids) {
List<Contact> contacts = new ArrayList<>();
String order = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC";
Cursor cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, order);
while (cursor.moveToNext()) {
String name = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String phonenumber = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
contacts.add(new Contact(name, phonenumber));
}
cursor.close();
return contacts;
}
#Override
protected void onPostExecute(List<Contact> contactList) {
super.onPostExecute(contactList);
//set list to your adapter
}
}
class Contact {
String name;
String number;
public Contact(String name, String number) {
this.name = name;
this.number = number;
}
public String getName() {
return name;
}
public String getNumber() {
return number;
}
public void setName(String name) {
this.name = name;
}
public void setNumber(String number) {
this.number = number;
}
}
I can't find any solutions to read contacts from Android and save them in Realm. Anyone done that before?
I know that I will have to use Contacts Provider, but this is all I know. AFAIK, Realm doesn't support Cursor so...what else?
edit:
realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
Contact realmContact = new Contact();
String filter = "" + ContactsContract.Contacts.HAS_PHONE_NUMBER + " > 0 and "
+ ContactsContract.CommonDataKinds.Phone.TYPE +"="
+ ContactsContract.CommonDataKinds.Phone.TYPE_MAIN;
Cursor phones = getActivity()
.getContentResolver()
.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, filter, null, null);
while (phones.moveToNext()) {
String id = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone._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.setNumber(phoneNumber);
realmContact.setIsBeingSaved(true);
realm.insertOrUpdate(realmContact);
}
/** 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); // reset all save state
}
Contact.class
public class Contact extends RealmObject{
#PrimaryKey
private String id;
#Index
private String name;
#Index
private String number;
#Index
private boolean isBeingSaved;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
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;
}
public boolean getIsBeingSaved() {
return isBeingSaved;
}
public void setIsBeingSaved(boolean beingSaved) {
isBeingSaved = beingSaved;
}
}
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
You can create a Model Class to store desired data from contact
then using Cursor get data and set data in model class.
Save the cursor data in list of model object.
Then insert all model object in single transaction as per object transaction has overhead and slow our app
What is the best way to save data read from SQLiteDatabase Android, and access them using row number or column name?
Hi Below is my code that I am using to fetch the data but I want to store the rows in some kind of dataset so that i can fetch the data using column number or name . I want to dynamically show these data in a grid in android.
MyDatabaseSQLHelper myDatabaseSQLHelper = new MyDatabaseSQLHelper(this);
SQLiteDatabase mySQLiteDatabase = myDatabaseSQLHelper.getReadableDatabase();
String[] projection = {
Items._ID,
Items.COL_ITEM_NAME,
Items.COL_ITEM_PRICE,
Items.COL_ITEM_QUANTITY,
Items.COL_ITEM_AMOUNT
};
Cursor cursor = mySQLiteDatabase.query(Items.TABLE_NAME,projection,null,null,null,null,null);
To store all rows fetch from database you can store it in Array list of type modal class. for you your modal class could be like this
ItemBeen.java
public class ItemBeen {
String id,itemName,itemPrice,itemQty,itemAmount;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getItemName() {
return itemName;
}
public void setItemName(String itemName) {
this.itemName = itemName;
}
public String getItemPrice() {
return itemPrice;
}
public void setItemPrice(String itemPrice) {
this.itemPrice = itemPrice;
}
public String getItemQty() {
return itemQty;
}
public void setItemQty(String itemQty) {
this.itemQty = itemQty;
}
public String getItemAmount() {
return itemAmount;
}
public void setItemAmount(String itemAmount) {
this.itemAmount = itemAmount;
}
}
then now in your class make method for get data from database and it store all record to array list and return that array list , like this.
public ArrayList<ItemBeen> getItemList() {
Cursor cur;
ArrayList<itemBeen> itemList = new ArrayList<>();
SQLiteDatabase db = this.getReadableDatabase();
cur = db.query(Items.TABLE_NAME.TBL_ITEM, projection, null, null, null, null, null);
if (cur != null) {
if (cur.moveToFirst()) {
do {
ItemBeen bean = new ItemBeen();
bean.setId(cur.getString(cur.getColumnIndex(DBConstant.TBL_ITEM.KEY_ID)));
bean.setItemName(cur.getString(cur.getColumnIndex(DBConstant.TBL_ITEM.KEY_ITEM_NAME)));
bean.setItemPrice(cur.getBlob(cur.getColumnIndex(DBConstant.TBL_ITEM.KEY_ITEM_PRICE)));
bean.setItemQty(cur.getString(cur.getColumnIndex(DBConstant.TBL_ITEM.KEY_ITEM_TQY)));
bean.setItemAmount(cur.getInt(cur.getColumnIndex(DBConstant.TBL_ITEM.KEY_ITEM_AMT)));
itemList.add(bean);
} while (cur.moveToNext());
}
}
return itemList;
}
Now in that class in which you want all item list in that class call this method.declare array list and fetch data.
ArrayList<ItemBeen> itemList = new ArrayList<ItemBeen>();
itemList = DBConstant.dbHelper.getItemList();
and this way in itemList contains all records.
I have this code (thankfully provided by #EpicPandaForce) and I have problem with deletion. When I add new contact it works like a charm while when I delete contact (or number from that contact if there are two of them) it stays persisted in Realm. How can I get it working properly?
realm.executeTransaction(new Realm.Transaction() {
#Override
public void execute(Realm realm) {
Contact realmContact = new Contact();
String filter = "" + ContactsContract.Contacts.HAS_PHONE_NUMBER + " > 0 and "
+ ContactsContract.CommonDataKinds.Phone.TYPE +"="
+ ContactsContract.CommonDataKinds.Phone.TYPE_MAIN;
Cursor phones = getActivity()
.getContentResolver()
.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, filter, null, null);
while (phones.moveToNext()) {
String id = phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone._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.setNumber(phoneNumber);
realmContact.setIsBeingSaved(true);
realm.insertOrUpdate(realmContact);
}
/** 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); // reset all save state
}
Contact.class
public class Contact extends RealmObject{
#PrimaryKey
private String id;
#Index
private String name;
#Index
private String number;
#Index
private boolean isBeingSaved;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
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;
}
public boolean getIsBeingSaved() {
return isBeingSaved;
}
public void setIsBeingSaved(boolean beingSaved) {
isBeingSaved = beingSaved;
}
}
EDIT - working code:
Contact realmContact = new Contact();
Uri uri = Contacts.CONTENT_URI;
String selection = "((" + CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY + " NOTNULL) AND ("
+ Contacts.HAS_PHONE_NUMBER + "=1) AND ("
+ CommonDataKinds.Phone.DISPLAY_NAME_PRIMARY + " != '' ))";
Cursor phones = getActivity()
.getContentResolver()
.query(uri, null, selection, null, null);
String phoneNumber = "";
while (phones.moveToNext()) {
String id = phones.getString(phones.getColumnIndex(ContactsContract.Contacts.LOOKUP_KEY));
String name = phones.getString(phones.getColumnIndex(Contacts.DISPLAY_NAME_PRIMARY));
String lastTimeContacted = phones.getString(phones.getColumnIndex(Contacts.LAST_TIME_CONTACTED));
if(Integer.parseInt(phones.getString(phones.getColumnIndex(Contacts.HAS_PHONE_NUMBER))) > 0){
Cursor pCur = getActivity().getContentResolver().query(
CommonDataKinds.Phone.CONTENT_URI,
null,
CommonDataKinds.Phone.LOOKUP_KEY +" = ?",
new String[]{id}, null);
while (pCur.moveToNext()) {
phoneNumber += "/" + pCur.getString(pCur.getColumnIndex(CommonDataKinds.Phone.NUMBER));
realmContact.setNumber(phoneNumber);
}
phoneNumber = "";
pCur.close();
} else {
realmContact.setNumber("1234");
}
realmContact.setId(id);
realmContact.setName(lastTimeContacted);
realmContact.setIsBeingSaved(true);
realm.insertOrUpdate(realmContact);
}
Log.i("asd-size", realm.where(Contact.class).findAll().size() + "");
/** 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); // reset all save state
}
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);
}
I am trying to implement search on user input. The serach results will be shown after searching the relevant option from database.
I have made this method to display the results
public Cursor getBooksBySearch(String query) {
// TODO Auto-generated method stub
String[] args={query};
return(getReadableDatabase().rawQuery("SELECT _id,chapter FROM chapters WHERE chapter LIKE '%" + query + "%", args));
}
Here the query is coming from an activity SearchResultAcitvity.java
Intent intent = getIntent();
if (Intent.ACTION_SEARCH.equals(intent.getAction())) {
String query = intent.getStringExtra(SearchManager.QUERY);
ListView myListView = (ListView)findViewById(R.id.txt_query);
dbBookHelper = new BooklistHelper(this);
ourCursor = dbBookHelper.getBooksBySearch(query);
startManagingCursor(ourCursor);
adapter = new BookAdapter(ourCursor);
myListView.setAdapter(adapter);
myListView.setOnItemClickListener(onListClick);
}
I want to match this coming query string to get the results from my chapter table.
Can I just match the query string m getting in String query = intent.getStringExtra(SearchManager.QUERY) with the data in my database.
Using list view to display.
Please help me in this.
Let me know if you want more information
Thanks in Advance :)
This will return list of data search by keyword
public ArrayList<ObjectType> getSearchData(String keyword)
{
ArrayList<ObjectType> objectTypeList = new ArrayList<ObjectType>();
SQLiteDatabase db = getWritableDatabase();
String checkEntry="SELECT id,firstname,lastname FROM abc_table WHERE firstname like '%"+ keyword +"%'" +" or "+ "p.lastname like '%"+ keyword +"%'";
Cursor cursor = db.rawQuery(checkEntry, null);
try
{
//If entry exist then update
if (cursor.moveToFirst())
{
do
{
ObjectType objectType = new ObjectType();
int PID=cursor.getInt(0);
String fname = cursor.getString(1);
String LastName = cursor.getString(2);
objectType.setFirstName(fname);
objectType.setLastName(LastName);
objectTypeList.add(objectType);
}
while(cursor.moveToNext());
}
}
finally
{
if(cursor != null)
cursor.close();
}
return objectTypeList;
}
ObjectType is class
public class ObjectType {
int id;
String firstName;
String lastName;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}
}
Hope this ll help you.. :)