I am trying to load the contacts in my phone into list view of an android app, but it doesn't loading my contacts. I got a dailog box to allow or deny permissions, when i pressed allow, its showing me a blank screen
I used contact fetcher class to retrieve the contacts. when i DENY permissions, its showing toast as expected but not showing contacts as list view
public class ContactFetcher {
private final Context context;
public ContactFetcher(Context c) {
this.context = c;
}
public ArrayList<Contact> fetchAll() {
String[] projectionFields = new String[]{
ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME,
};
ArrayList<Contact> listContacts = new ArrayList<>();
CursorLoader cursorLoader = new CursorLoader(context,
ContactsContract.Contacts.CONTENT_URI,
projectionFields, // the columns to retrieve
null, // the selection criteria (none)
null, // the selection args (none)
null // the sort order (default)
);
Cursor c = cursorLoader.loadInBackground();
final Map<String, Contact> contactsMap = new HashMap<>(c.getCount());
if (c.moveToFirst()) {
int idIndex = c.getColumnIndex(ContactsContract.Contacts._ID);
int nameIndex =
c.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
do {
String contactId = c.getString(idIndex);
String contactDisplayName = c.getString(nameIndex);
Contact contact = new Contact(contactId, contactDisplayName);
contactsMap.put(contactId, contact);
listContacts.add(contact);
} while (c.moveToNext());
}
c.close();
matchContactNumbers(contactsMap);
return listContacts;
}
public void matchContactNumbers(Map<String, Contact> contactsMap) {
// Get numbers
final String[] numberProjection = new String[]{
Phone.NUMBER,
Phone.TYPE,
Phone.CONTACT_ID,
};
Cursor phone = new CursorLoader(context,
Phone.CONTENT_URI,
numberProjection,
null,
null,
null).loadInBackground();
if (phone.moveToFirst()) {
final int contactNumberColumnIndex =
phone.getColumnIndex(Phone.NUMBER);
final int contactTypeColumnIndex =
phone.getColumnIndex(Phone.TYPE);
final int contactIdColumnIndex = phone.getColumnIndex(Phone.CONTACT_ID);
while (!phone.isAfterLast()) {
final String number = phone.getString(contactNumberColumnIndex);
final String contactId = phone.getString(contactIdColumnIndex);
Contact contact = contactsMap.get(contactId);
if (contact == null) {
continue;
}
final int type = phone.getInt(contactTypeColumnIndex);
String customLabel = "Custom";
CharSequence phoneType = ContactsContract.CommonDataKinds.Phone.getTypeLabel(context.getResources(), type, customLabel);
contact.addNumber(number, phoneType.toString());
phone.moveToNext();
}
}
phone.close();
}
here is my mainActivity...
private static final int PERMISSIONS_REQUEST_READ_CONTACTS=100;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lvContacts = (ListView) findViewById(R.id.lvContacts);
showContacts();
}
private void showContacts(){
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && checkSelfPermission(Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED) {
requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, PERMISSIONS_REQUEST_READ_CONTACTS);
//After this point you wait for callback in onRequestPermissionsResult(int, String[], int[]) overriden method
} else {
listContacts = new ContactFetcher(this).fetchAll();
ContactsAdapter adapterContacts = new ContactsAdapter(this, listContacts);
lvContacts.setAdapter(adapterContacts);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions,
int[] grantResults) {
if (requestCode == PERMISSIONS_REQUEST_READ_CONTACTS) {
if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
// Permission is granted
listContacts = new ContactFetcher(this).fetchAll();
ContactsAdapter adapterContacts = new ContactsAdapter(this, listContacts);
lvContacts.setAdapter(adapterContacts);
} else {
Toast.makeText(this, "Until you grant the permission, we canot display the names", Toast.LENGTH_SHORT).show();
}
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
The specific issue you have there is assuming that
loadInBackgroundimmediately returns a cursor with all the data in hand, that's not how it works.But in general
CursorLoaderis not a recommended pattern to load stuff onto UI. You should do it differently, by querying for data inside anAsyncTaskfor example, and then delivering the results in theonPostExecute.For the simplest changes from your existing code, I would change
fetchAllto be a blocking method, like so:and call if from an AsyncTask so it won't run any heavy code on the UI thread, like so: