0

I'm trying to populate a ListView from the phone contacts, but the result is just wrong.

I created a list of contacts:

List<Contact> contacts = getContactNames();

and my adapter is:

ArrayAdapter<Contact> adapter = new ArrayAdapter<>(this, R.layout.contacts_list, R.id.contactName, contacts);
listView.setAdapter(adapter);

but when I run my application, I have the name of my package in the textView contactName and Description in textView contactNumber

I have three files, AcitivityMain.class, contacts_list.xml and Contact.class:

ActivityMain

public class MainActivity extends AppCompatActivity {
    private ListView listView;
    private static final int PERMISSIONS_REQUEST_READ_CONTACTS = 100;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Find the list view
        this.listView = (ListView) findViewById(R.id.listView);

        // Read and show the contacts
        showContacts();
    }

    /**
     * Show the contacts in the ListView.
     */
    private void showContacts() {
        // Check the SDK version and whether the permission is already granted or not.
        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 {
            // Android version is lesser than 6.0 or the permission is already granted.
            List<Contact> contacts = getContactNames();
            ArrayAdapter<Contact> adapter = new ArrayAdapter<>(this, R.layout.contacts_list, R.id.contactName, contacts);
            listView.setAdapter(adapter);
        }
    }

    @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
                showContacts();
            } else {
                Toast.makeText(this, "Until you grant the permission, we cannot display the names", Toast.LENGTH_SHORT).show();
            }
        }
    }

    /**
     * Read the name of all the contacts.
     *
     * @return a list of names.
     */
    private List<Contact> getContactNames() {
        List<Contact> contacts = new ArrayList<>();
        Contact contact = new Contact();
        // Get the ContentResolver
        ContentResolver cr = getContentResolver();
        // Get the Cursor of all the contacts
        Cursor cursor = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);

        if (cursor.getCount() > 0) {
            while (cursor.moveToNext()) {
                String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
                String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
                contact.setContactName(name);
                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 number = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                        contact.setContactNumber(number);
                        contacts.add(contact);
                    }
                    pCur.close();
                }
            }
        }
        return contacts;
    }
}

Contact class

public class Contact {
    private String contactName;
    private String contactNumber;

    public Contact() {}

    public Contact(String name, String number) {
        this.contactName = name;
        this.contactNumber = number;
    }

    public String getContactName() {
        return contactName;
    }

    public void setContactName(String contactName) {
        this.contactName = contactName;
    }

    public String getContactNumber() {
        return contactNumber;
    }

    public void setContactNumber(String contactNumber) {
        this.contactNumber = contactNumber;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Contact)) return false;

        Contact contact = (Contact) o;

        if (getContactName() != null ? !getContactName().equals(contact.getContactName()) : contact.getContactName() != null)
            return false;
        return getContactNumber() != null ? getContactNumber().equals(contact.getContactNumber()) : contact.getContactNumber() == null;

    }

    @Override
    public int hashCode() {
        int result = getContactName() != null ? getContactName().hashCode() : 0;
        result = 31 * result + (getContactNumber() != null ? getContactNumber().hashCode() : 0);
        return result;
    }
}

contacts_list

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="?android:attr/listPreferredItemHeight"
android:padding="6dip" >

<ImageView
    android:id="@+id/icon"
    android:layout_width="wrap_content"
    android:layout_height="fill_parent"
    android:layout_alignParentBottom="true"
    android:layout_alignParentTop="true"
    android:layout_marginRight="6dip"
    android:contentDescription="TODO"
    android:src="@mipmap/ic_launcher" />

<TextView
    android:id="@+id/contactNumber"
    android:layout_width="fill_parent"
    android:layout_height="26dip"
    android:layout_alignParentBottom="true"
    android:layout_alignParentRight="true"
    android:layout_toRightOf="@id/icon"
    android:ellipsize="marquee"
    android:singleLine="true"
    android:text="Description"
    android:textSize="12sp" />

<TextView
    android:id="@+id/contactName"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_above="@id/contactNumber"
    android:layout_alignParentRight="true"
    android:layout_alignParentTop="true"
    android:layout_alignWithParentIfMissing="true"
    android:layout_toRightOf="@id/icon"
    android:gravity="center_vertical"
    android:text="Example application"
    android:textSize="16sp" />

</RelativeLayout>

and the result is: enter image description here

TylerH
  • 20,799
  • 66
  • 75
  • 101
Terai
  • 311
  • 1
  • 4
  • 13
  • If you want to show more that one text in the item of a listview you must use a custom adapter instead http://stackoverflow.com/questions/8166497/custom-adapter-for-list-view in your case the contact name and the number – diedu Dec 09 '16 at 19:46

2 Answers2

1

First things first. Array adapter only works with one TextView per layout. It cannot inflate both the contact name and phone number. This means the phone number textView will remain as it was in the xml layout, in this case "Decription".

As for the package name issue

The ArrayAdapter documentation says

However the TextView is referenced, it will be filled with the toString() of each object in the array. You can add lists or arrays of custom objects. Override the toString() method of your objects to determine what text will be displayed for the item in the list.

So you need to override the toString method in Contact and return the contact name.

Although this would work I'll suggest using another sort of adapter, since ideally the toString method should represent the object and all it's fields

Olumide
  • 758
  • 13
  • 31
  • Thanks for the explanation I found how to make appear the name but it remains to me how to adapt it to make display two elements or more in my listview – Terai Dec 09 '16 at 19:49
  • @Torai for that you need a custom adapted. See this answer http://stackoverflow.com/a/8166802/2057884 – Olumide Dec 09 '16 at 19:51
  • @Torai Simply `toString() { return name + " " + number; }` – OneCricketeer Dec 09 '16 at 19:51
0

Here in this method your are not initializing your contact variable again

Please add this line

Contact contact = new Contact();

inside your while loop like this

private List<Contact> getContactNames() {
    List<Contact> contacts = new ArrayList<>();
    // Get the ContentResolver
    ContentResolver cr = getContentResolver();
    // Get the Cursor of all the contacts
    Cursor cursor = cr.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);

    if (cursor.getCount() > 0) {
        while (cursor.moveToNext()) {
            Contact contact = new Contact();
            String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
            String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
            contact.setContactName(name);
            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 number = pCur.getString(pCur.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
                    contact.setContactNumber(number);
                    contacts.add(contact);
                }
                pCur.close();
            }
        }
    }
    return contacts;
}

and in your Contact class define a toString() function

@Override
public void toString(){
   return name + "  " + number;
}

I hope it will solve your problem

Tabish Hussain
  • 852
  • 5
  • 13