When I click on fab to write a new SMS in my application, it is opening too slowly. When I comment readcontactData or adapter it is working Quickly. where is the problem
adapter =new ArrayAdapter<String>(this,android.R.layout.simple_dropdown_item_1line,new ArrayList<String>());
readContactData();
contactNumber.setThreshold(1);
//Set adapter to AutoCompleteTextView
contactNumber.setAdapter(adapter);
contactNumber.setOnItemClickListener(this);
private void readContactData() {
try {
ContentResolver contentResolver = getBaseContext().getContentResolver();
// Uri uri = Uri.withAppendedPath(PhoneLookup.CONTENT_FILTER_URI, Uri.encode(phoneNumber));
//Query to get contact name
Cursor cursor =contentResolver.query(ContactsContract.Contacts.CONTENT_URI,null,null,null,null);
// If data found in contacts
if (cursor.getCount() > 0) {
Log.i("AutocompleteContacts", "Reading contacts........");
int k=0;
while (cursor.moveToNext())
{
String name = cursor
.getString(cursor
.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
String id = cursor
.getString(cursor
.getColumnIndex(ContactsContract.Contacts._ID));
String hasPhone=cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER));
//Check contact have phone number
if ((Integer.parseInt(hasPhone) > 0))
{
//Create query to get phone number by contact id
Cursor pCur = contentResolver
.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID
+ " = " + id,
null,
null);
int j=0;
while (pCur.moveToNext())
{
// Sometimes get multiple data
if(j==0)
{
// Get Phone number
String phoneNumber =pCur.getString(pCur
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
// Add contacts names to adapter
adapter.add(name);
//adapter.add(phoneNumber);
// Add ArrayList names to adapter
phoneValueArr.add(phoneNumber.toString());
nameValueArr.add(name.toString());
j++;
//k++;
}
} // End while loop
pCur.close();
} // End if
} // End while loop
//} // End Cursor value check
cursor.close();
}
catch (Exception e)
{
e.printStackTrace();
Log.d("this is an error","akdjfkandkfj");
}
}**
You are loading data in Main thread. So its slow. Use Async Task for readContact.
Writing too much code in onCreate, slow the loading.
Related
I am trying to get all contact from my phone, including get all numbers from contacts with multiple numbers.
So i've build query that while not over run all over contacts, and build Contact user, and have inside query with id selection to get all numbers for each user. but since my inside query is including selection it takes a long time. any other idea?
private Cursor initPhoneCursor() {
try {
// get the contacts URI
final Uri phoneUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
// get the name column's name depending on the Android Version
final String nameColumn = Contact.COLUMN_NAME_PHONE;
// declare columns object - init later depending on version
String selection = getQuerySelectionForCursor();
String[] columns = getColumnSelectionForCursor(nameColumn);
if (mApp != null) {
// return cursor from contentresolver
return mApp.getContentResolver().query(phoneUri, columns, selection, null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME + " ASC");
}
} catch (Exception e) {
// couldn't read phone cursor
CaughtExceptionHandler.reportException(e);
}
return null;
}
private void importContactsFromCursor(Cursor cursor, boolean isSimCard) {
mCurrentContactCursor = initPhoneCursor();
// check cursor is alive
if (cursor != null && !cursor.isClosed()) {
while (cursor.moveToNext() && shouldContinueImport()) {
// // as log as we have contacts, move through them
importContact(cursor, isSimCard);
mCurrentContact++;
}
// when done - close the cursor
cursor.close();
}
}
private void importContact(Cursor cursor, boolean simCard) {
// create Contact object
Contact row = new Contact(cursor, simCard);
// mContactsTimer.onContactCreated();
if (simCard) {
// if simCard, contact must have number
// validate number and create contact
row = validateAndCheckNumber(row, cursor);
}
else {
// if not sim card (phone cursor), a contact might have no numbers,
// single or multiple phone numberss
// let's check if this contact has any numbers
if (hasPhoneNumbers(cursor)) {
// get all of the contact's phone numbers
row = importAllNumbersForContact(row);
}
}
// check if this is valid
final boolean isValidForSaving = row != null && row.hasName() && row.hasNumbers();
if (isValidForSaving && !sStopRequested) {
mContactsToSave.add(row);
}
}
private Contact importAllNumbersForContact(Contact contact) {
// uri of contact phones
Uri contentUri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
// contact_id = ?
String selection = ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?";
String[] selectionArgs = {String.valueOf(contact.getOriginalId())};
// do the query
Cursor phoneCursor = mApp.getContentResolver().query(contentUri, null, selection, selectionArgs, null);
if (phoneCursor != null) {
// save numbers if we got anything
contact = loopThroughContactNumbers(contact, phoneCursor);
// close cursor when done
phoneCursor.close();
}
return contact;
}
Go with the following solution:
Map<String,Contact> contactsMap = new TreeMap<>();
contacts = new ArrayList<>();
Cursor phones = getBaseContext().getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null,null,null, ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME+" ASC");
assert phones != null;
while (phones.moveToNext())
{
Contact contact = new Contact();
contact.setDisplayName(phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)));
contact.setPhoneNumber(phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER)));
contact.setDisplayPicture(phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.PHOTO_THUMBNAIL_URI)));
contactsMap.put(phones.getString(phones.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME)),contact);
}
contacts.addAll(contactsMap.values());
phones.close();
Modify it for all numbers of a contact. You are good to go with.
Am trying to use the ContactsProvider with my AutoCompleteTextview using a method that fetches the data (name and phone number) and stores them in a list. As expected, this method will always take time to complete as am calling the method in the onCreateView method of my Fragment class.
This is the method:
...
ArrayList<String> phoneValues;
ArrayList<String> nameValues;
...
private void readContactData() {
try {
/*********** Reading Contacts Name And Number **********/
String phoneNumber = "";
ContentResolver contentResolver = getActivity()
.getContentResolver();
//Query to get contact name
Cursor cursor = contentResolver
.query(ContactsContract.Contacts.CONTENT_URI,
null,
null,
null,
null);
// If data data found in contacts
if (cursor.getCount() > 0) {
int k=0;
String name = "";
while (cursor.moveToNext())
{
String id = cursor
.getString(cursor
.getColumnIndex(ContactsContract.Contacts._ID));
name = cursor
.getString(cursor
.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
//Check contact have phone number
if (Integer
.parseInt(cursor
.getString(cursor
.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0)
{
//Create query to get phone number by contact id
Cursor pCur = contentResolver
.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID
+ " = ?",
new String[] { id },
null);
int j=0;
while (pCur
.moveToNext())
{
// Sometimes get multiple data
if(j==0)
{
// Get Phone number
phoneNumber =""+pCur.getString(pCur
.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
// Add contacts names to adapter
autocompleteAdapter.add(name);
// Add ArrayList names to adapter
phoneValues.add(phoneNumber.toString());
nameValues.add(name.toString());
j++;
k++;
}
} // End while loop
pCur.close();
} // End if
} // End while loop
} // End Cursor value check
cursor.close();
} catch (Exception e) {
Log.i("AutocompleteContacts","Exception : "+ e);
}
}
Am sure there is a better way to accomplish this, but this method works and the suggestions are presented when I type into the AutocompleteTextview. Am just worried about the time it takes. How can I accomplish this without populating an ArrayList?
I have looked at this question: Getting name and email from contact list is very slow and applied the suggestions in the answer to my code, but now nothing is suggested when I type.How can I improve the performance of my current code?
This is how i have implemented AutoCompleteTextView and it works fine for me ..
final AutoCompleteTextView act=(AutoCompleteTextView)findViewById(R.id.autoCompleteTextView1);
ArrayList<String> alContacts = new ArrayList<String>();
ArrayList<String> alNames= new ArrayList<String>();
ContentResolver cr = this.getContentResolver(); //Activity/Application android.content.Context
Cursor cursor = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
if(cursor.moveToFirst())
{
do
{
String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
if(Integer.parseInt(cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) > 0)
{
Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?",new String[]{ id }, null);
while (pCur.moveToNext())
{
String contactNumber = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
String contactName=pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
alNames.add(contactName);
alContacts.add(contactNumber);
break;
}
pCur.close();
}
} while (cursor.moveToNext()) ;
}
String[] array=new String[alNames.size()];
array=(String[]) alNames.toArray(array);
ArrayAdapter<String> myArr= new ArrayAdapter<String>(this,android.R.layout.simple_dropdown_item_1line,array);
act.setAdapter(myArr);
act.setThreshold(1);
I got rid of the slow response by placing the method inside an AsynTask.
public class AutocompleteAsyncTask extends AsyncTask<Void, Void, Void> {
public Void doInBackground(Void...params) {
try {
/*********** Reading Contacts Name And Number **********/
String phoneNumber = "";
ContentResolver contentResolver = getActivity()
.getContentResolver();
//Query to get contact name
Cursor cursor = contentResolver
.query(ContactsContract.Contacts.CONTENT_URI,
null,
null,
null,
null);
// If data data found in contacts
if (cursor.getCount() > 0) {
int k=0;
String name = "";
while (cursor.moveToNext())
{
//...Rest of the same code as above
and then calling this in my onCreateView():
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
...
new AutocompleteAsyncTask().execute();
return rootView;
}
Now the task of inflating my view and fetching the data are separated into two different threads.
The CursorLoader option mentioned by Eugen Pechanec is kinda the best option, so I'll update this answer with that option when I can.
I am successfully storing contacts in parse.com dashboard data browser by this code.
public void readContacts(){
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI,null, null, null, null);
if (cur.getCount() > 0) {
while (cur.moveToNext()) {
String id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
String name = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
if (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) ==1) {
System.out.println(name );
ParseObject testObject = new ParseObject("Contacts");
testObject.put("names", name);
// get the phone number
Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID +" = ?",
new String[]{id}, null);
while (pCur.moveToNext()) {
String phone = pCur.getString(
pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
System.out.println( phone);
testObject.put("phonenumber", phone);
}
pCur.close();
testObject.saveInBackground();
}
}
}
}
But there is no check for the duplicate contacts !
It stores all the contacts duplicate from sim / phone memory.
How can it be avoided ?
One possible method I think is to store distinct names(contact) in local database, & then retrieving that data to store it in parse.com
Is there exists a better way ?
Thanks in advance...
An easy approach could be to load the data to a MatrixCursor with no duplicate data. For example lets assume you have a cursor c1 will many contacts, but you need a cursor with no duplicate data. Here is what you could do:
MatrixCursor mc = new MatrixCursor(new String[] {
Phone._ID,
Phone.DISPLAY_NAME_PRIMARY,
Phone.NUMBER
});
String lastNumber = "";
while(c1.moveToNext()){
String id = c1.getString(c1.getColumnIndexOrThrow(Phone._ID));
String name = c1.getString(c1.getColumnIndexOrThrow(Phone.DISPLAY_NAME_PRIMARY)));
String number = c1.getString(c1.getColumnIndexOrThrow(Phone.NUMBER));
//Some condition to check previous data is not matched and only then add row
if(!lastNumber.contains(number)){
lastNumber = number;
mc.addRow(new String[]{id, name, number});
}
}
c1.close();
Make an instance of MatrixCursor with same columns, and then load if last number or contact name does not match that of the previous contact. The condition for checking is upto you. Query data in some order so that the duplicate contacts stay together first.
Once the MatrixCursor is loaded you can fetch data from it. You could also attach it to a view through a custom CursorLoader or CursorAdapter.
Please see the below method. You will get contacts list which does not have duplicate phone numbers.
public void readContacts() {
ContentResolver cr = getContentResolver();
Cursor cur = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
ArrayList<ParseObject> contacts = new ArrayList<ParseObject>();
ArrayList<String> list = new ArrayList<String>();
if (cur.getCount() > 0) {
while (cur.moveToNext()) {
String id = cur.getString(cur.getColumnIndex(ContactsContract.Contacts._ID));
String name = cur.getString(cur.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
if (Integer.parseInt(cur.getString(cur.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER))) == 1) {
System.out.println(name);
ParseObject testObject = new ParseObject("Contacts");
testObject.put("names", name);
// get the phone number
Cursor pCur = cr.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?", new String[] { id }, null);
while (pCur.moveToNext()) {
String phone = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
System.out.println(phone);
testObject.put("phonenumber", phone);
if(!list.contains(phone)) {
contacts.add(testObject);
}
list.add(phone);
}
pCur.close();
testObject.saveInBackground();
}
}
}
}
Set is a collection in java that does not allow duplicates. You can put your data into a set with number as a key and name as value, to avoid duplicate numbers.
And later you can take them back from set and put into your testObject with name as key and number as value.
Here is the Solution that i worked out for you....
You can go through the logcat for information about how it works 100%
import java.util.ArrayList;
import android.app.Activity;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract.CommonDataKinds.Phone;
import android.provider.ContactsContract.Contacts;
public class MainActivity extends Activity {
String ClsSimPhonename = null;
String ClsSimphoneNo = null;
public static ArrayList<String> phonecontact = new ArrayList<String>();
public static ArrayList<String> simcontact = new ArrayList<String>();
public static ArrayList<String> totalcontact = new ArrayList<String>();
public static ArrayList<String> repeatedcontact = new ArrayList<String>();
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// get phone contact...
getphonecontact();
// get sim contact...
getsimcard_contact();
System.out.println("phone??? " + phonecontact);
System.out.println("sim??? " + simcontact);
System.out.println("sim_size??? " + simcontact.size());
System.out.println("phone_size??? " + phonecontact.size());
System.out.println("totalcontact_size??? " + totalcontact.size());
// filter process beigins here....
nowFilterContact();
}
private void nowFilterContact() {
// TODO Auto-generated method stub
// determine which contact have more item....
if (simcontact.size() > phonecontact.size()) {
onemorefiltermethod(simcontact.size(), simcontact, phonecontact);
} else {
onemorefiltermethod(phonecontact.size(), phonecontact, simcontact);
}
}
private void onemorefiltermethod(int size, ArrayList<String> contacts,
ArrayList<String> contact2) {
// TODO Auto-generated method stub
// compare both contact and get repeated contacts....
for (int i = 0; i < size; i++) {
try {
if (contacts.contains(contact2.get(i))) {
// add repeated contacts to array....
repeatedcontact.add(contact2.get(i));
}
} catch (Exception e) {
}
}
System.out.println("repeatedcontact_size??? " + repeatedcontact.size());
// now delete repeated contact from total contact
now_deletedrepeated_contact_from_total();
}
private void now_deletedrepeated_contact_from_total() {
// TODO Auto-generated method stub
for (int i = 0; i < totalcontact.size(); i++) {
try {
if (totalcontact.contains(repeatedcontact.get(i))) {
totalcontact.remove(repeatedcontact.get(i));
}
} catch (Exception e) {
}
}
System.out.println("Final contact size" + totalcontact.size());
System.out.println("Final contact " + totalcontact);
}
private void getsimcard_contact() {
// TODO Auto-generated method stub
try {
Uri simUri = Uri.parse("content://icc/adn");
Cursor cursorSim = this.getContentResolver().query(simUri, null,
null, null, null);
while (cursorSim.moveToNext()) {
ClsSimPhonename = cursorSim.getString(cursorSim
.getColumnIndex("name"));
ClsSimphoneNo = cursorSim.getString(cursorSim
.getColumnIndex("number"));
ClsSimphoneNo.replaceAll("\\D", "");
ClsSimphoneNo.replaceAll("&", "");
ClsSimPhonename = ClsSimPhonename.replace("|", "");
/*
* add contact from phone to array phone array and total array
*/
phonecontact.add(ClsSimphoneNo);
totalcontact.add(ClsSimphoneNo);
}
} catch (Exception e) {
e.printStackTrace();
}
}
private void getphonecontact() {
// TODO Auto-generated method stub
try {
String[] PROJECTION = new String[] { Contacts._ID,
Contacts.DISPLAY_NAME, Phone.NUMBER };
Cursor c = managedQuery(Phone.CONTENT_URI, PROJECTION, null, null,
null);
if (c.moveToFirst()) {
String ClsPhonename = null;
String ClsphoneNo = null;
do {
ClsPhonename = c.getString(c
.getColumnIndex(Contacts.DISPLAY_NAME));
ClsphoneNo = c.getString(c.getColumnIndex(Phone.NUMBER));
/*
* add contact from sim to array sim array and total array
*/
simcontact.add(ClsphoneNo);
totalcontact.add(ClsphoneNo);
ClsphoneNo.replaceAll("\\D", "");
ClsPhonename = ClsPhonename.replaceAll("&", "");
ClsPhonename.replace("|", "");
String ClsPhoneName = ClsPhonename.replace("|", "");
} while (c.moveToNext());
}
} catch (Exception e) {
}
}
}
Permission
<uses-permission android:name="android.permission.READ_CONTACTS"/>
Your output is on now_deletedrepeated_contact_from_total() method.
Check totalcontact array value for Final output
I want to make a checkable Contact List that should be stored by the application, allow the users to place checks on some contacts, and store users' preferences.
I want to know whether a preference activity can be used to list all contacts as checkboxes,
or whether a custom listview can allow me to save the users preferences for the app?
you can get contact data with following code:
Cursor cursor = getContentResolver().query(
ContactsContract.Contacts.CONTENT_URI, null, null,
null, null);
cursor.moveToFirst();
if (cursor.getCount() > 0) {
do {
try {
contactId = cursor
.getString(cursor
.getColumnIndex(ContactsContract.Contacts._ID));
Uri contactUri = ContentUris.withAppendedId(
Contacts.CONTENT_URI,
Long.parseLong(contactId));
Uri dataUri = Uri.withAppendedPath(contactUri,
Contacts.Data.CONTENT_DIRECTORY);
Cursor phones = getContentResolver()
.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null,
ContactsContract.CommonDataKinds.Phone.CONTACT_ID
+ " = " + contactId,
null, null);
if (phones.getCount() > 0) {
try {
Cursor nameCursor = getContentResolver()
.query(dataUri,
null,
Data.MIMETYPE + "=?",
new String[] { StructuredName.CONTENT_ITEM_TYPE },
null);
nameCursor.moveToFirst();
do {
String firstName = nameCursor
.getString(nameCursor
.getColumnIndex(Data.DATA2));
String displayname = cursor
.getString(cursor
.getColumnIndex(Contacts.DISPLAY_NAME_ALTERNATIVE));
lastName = nameCursor
.getString(nameCursor
.getColumnIndex(Data.DATA3));
} while (nameCursor.moveToNext());
nameCursor.close();
} catch (Exception e) {
}
}
phones.close();
}
catch (Exception t) {
}
} while (cursor.moveToNext());
}
after get list of your contact name or anything that you want you need create custom adapter to show this data, for creating the custom list see this link and this.
//////////////////////
EDIT:
you can get phone number with following code:
String number = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
I want to query the Contacts Database for phone number and if the selected contact has multiple numbers, I display the available numbers for the user to select one of them.
I have code in place that would pick up the default number of the selected contact.
Cursor cursor = null;
String phoneNumber = "";
try
{
Uri result = data.getData();
// get the contact id from the Uri
String id = result.getLastPathSegment();
// query for everything email
cursor = getContentResolver().query(Phone.CONTENT_URI,
null, Phone.CONTACT_ID + "=?", new String[] { id },
null);
int pNumberIdx = cursor.getColumnIndex(Phone.NUMBER);
// let's just get the first email
if (cursor.moveToFirst())
{
phoneNumber = cursor.getString(pNumberIdx);
}
}
catch (Exception e)
{
}
finally
{
if (cursor != null)
{
cursor.close();
}
EditText emailEntry = (EditText) findViewById(R.id.pNumber);
emailEntry.setText(phoneNumber);
if (phoneNumber.length() == 0)
{
Toast.makeText(this, "No number found for contact.",
Toast.LENGTH_LONG).show();
}
}