【问题标题】:contacts are not loading into my list view android联系人没有加载到我的列表视图android中
【发布时间】:2019-06-03 04:47:50
【问题描述】:

我正在尝试将手机中的联系人加载到 Android 应用程序的列表视图中,但它没有加载我的联系人。我有一个对话框来允许或拒绝权限,当我按下允许时,它向我显示一个空白屏幕

我使用联系人提取器类来检索联系人。当我拒绝权限时,它按预期显示吐司,但未将联系人显示为列表视图

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();
}

这是我的 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;
}

【问题讨论】:

  • new String[]{Manifest.permission.READ_CONTACTS}, PERMISSIONS_REQUEST_READ_CONTACTS 有错字吗?它应该是new String[]{Manifest.permission.READ_CONTACTS, PERMISSIONS_REQUEST_READ_CONTACTS},其中大括号应该在第二个字符串之外。
  • @Edric - 不应该。第二个常量是请求代码。
  • 哎呀,没看到!感谢您指出这一点。

标签: android listview android-contacts contactscontract


【解决方案1】:

您遇到的具体问题是假设loadInBackground 立即返回一个包含所有数据的游标,但这不是它的工作原理。

但通常CursorLoader 不是将内容加载到 UI 的推荐模式。 您应该采取不同的做法,例如在 AsyncTask 中查询数据,然后在 onPostExecute 中提供结果。

对于现有代码的最简单更改,我会将fetchAll 更改为阻塞方法,如下所示:

public ArrayList<Contact> fetchAll() {
    String[] projectionFields = new String[]{
            ContactsContract.Contacts._ID,
            ContactsContract.Contacts.DISPLAY_NAME,
    };
    ArrayList<Contact> listContacts = new ArrayList<>();
    Cursor c = context.getContentResolver().query(Contacts.CONTENT_URI,projectionFields,null,null,null);

    final Map<String, Contact> contactsMap = new HashMap<>(c.getCount());

    if (c.moveToFirst()) {
        ... // same code
    }
    c.close();
    matchContactNumbers(contactsMap);
    return listContacts;
}

并从 AsyncTask 调用 if,这样它就不会在 UI 线程上运行任何繁重的代码,如下所示:

new AsyncTask<Void, Void, ArrayList<Contact>>() {
    @Override
    protected ArrayList<Contact> doInBackground(Void... params) {
        return new ContactFetcher(this).fetchAll();
    }
    @Override
    protected void onPostExecute(ArrayList<Contact> listContacts) {
        ContactsAdapter adapterContacts = new ContactsAdapter(this, listContacts);
        lvContacts.setAdapter(adapterContacts);         
    }
}.execute();

【讨论】:

  • 我应该在 mainActivity 中提及 Asyntask 吗?如果是这样,我应该在哪里检查请求权限条件?
  • 您可以将 AsyncTask 代码作为新方法 fetchContactsAsync 放入主活动中,并从 showContactsonRequestPermissionsResult 调用它,而不是当前调用 fetchAll 的代码(这 3 行)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-07-12
  • 1970-01-01
  • 2012-02-08
  • 2023-03-22
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多