联系人没有加载到我的列表视图android中

Posted

技术标签:

【中文标题】联系人没有加载到我的列表视图android中【英文标题】:contacts are not loading into my list view 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 - 不应该。第二个常量是请求代码。 哎呀,没看到!感谢您指出这一点。 【参考方案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 行)

以上是关于联系人没有加载到我的列表视图android中的主要内容,如果未能解决你的问题,请参考以下文章

将联系人的图片加载到列表视图中,而不是默认?

如何在android上的listview中快速加载联系人

列表视图上的 Android 联系人

列表视图上的 Android 联系人

列表视图中的Android联系人图像占位符

带有光标适配器滚动问题的android列表视图