为什么我的联系人查询给出了具有不同 ID 的联系人?
Why is my contacts query giving a contact with a different id?
我有一个 Activity 允许用户 select 联系人。完成后,selected 联系人的 ID 将在回复 Intent 中传递。在处理结果的地方,要读取 selected 联系人的详细信息。
问题在于,在处理结果时,读取的详细信息与 select 编辑的联系人不同。
我不知道为什么。在我的例子中,用户只有 select 一个联系人。
我已经阅读了大量文档和其他有关阅读联系人的问题,但没有看到任何对我的案例有帮助的内容。
从 Activity 获取用户 selection 来自联系人:
@Override
protected void onCreate (Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_select_from_contacts);
m_view = findViewById(R.id.lv_contactsSelect);
m_view.setVisibility(View.VISIBLE);
getListView().setItemsCanFocus(false);
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
Cursor cursor = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,
new String[]{ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME},
null, null, "UPPER(" + ContactsContract.Contacts.DISPLAY_NAME + ") ASC");
setListAdapter(new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_multiple_choice,
cursor,
new String[]{ContactsContract.Contacts.DISPLAY_NAME},
new int[]{android.R.id.text1},
0));
Button btn = findViewById(R.id.btn_get_contacts);
btn.setOnClickListener((View view) -> {
Intent replyIntent = new Intent();
ArrayList<Long> ids = pickContacts();
replyIntent.putExtra(Activities.ARG_SELECTED, ids);
setResult(Activities.RESULT_CONTACTS_SELECTED, replyIntent);
finish();
});
}
/** Viewer for list of contacts */
private ListView m_view;
private ListView getListView ()
{ return m_view; }
private CursorAdapter mAdapter;
private void setListAdapter (@NonNull CursorAdapter adapter)
{
mAdapter = adapter;
m_view.setAdapter(adapter);
}
// return id for each selected contact
private ArrayList<Long> pickContacts ()
{
SparseBooleanArray a = getListView().getCheckedItemPositions();
ArrayList<Long> contacts = new ArrayList<>();
for (int i = 0; i < a.size(); i++)
{
if (a.valueAt(i))
{
Cursor c = (Cursor)mAdapter.getItem(a.keyAt(i));
// TODO use RawContacts or Contacts? Currently the result is the same.
//Long idContact = c.getLong(c.getColumnIndex(ContactsContract.Contacts._ID));
Long idRaw = c.getLong(c.getColumnIndex(ContactsContract.RawContacts._ID));
contacts.add(idRaw);
}
}
return contacts;
}
正在处理结果:
@Override
protected void onActivityResult (int requestCode, int resultCode, Intent data)
{
if (resultCode == Activities.RESULT_CONTACTS_SELECTED)
{
ArrayList<Long> ids = (ArrayList<Long>)data.getSerializableExtra(Activities.ARG_SELECTED);
for (long id : ids)
{
getContactDetails(id);
}
}
}
/**
* As mentioned in https://developer.android.com/reference/android/provider/ContactsContract.RawContacts
* the best way to read a raw contact along with associated data is by using the Entity directory.
*/
// FIXME: The id from the received result matches what was selected,
// but this function reads details for a different contact.
private void getContactDetails (long rawContactId)
{
System.out.println("Get contact with id " + rawContactId);
Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
Uri entityUri = Uri.withAppendedPath(rawContactUri, Entity.CONTENT_DIRECTORY);
// For example, this output can be "Get contact from entity uri content://com.android.contacts/raw_contacts/615/entity"
// (Where 615 is the id for the selected contact.)
System.out.println("Get contact from entity uri " + entityUri);
Cursor c = getContentResolver().query(entityUri,
new String[]{RawContacts.SOURCE_ID, Entity.DATA_ID, Entity.MIMETYPE, Entity.DATA1}, // projection
null, null, null);
if (c == null)
return;
try
{
while (c.moveToNext())
{
// In this example I'm just dumping data to the console.
if (!c.isNull(1))
{
String mimeType = c.getString(2);
String data = c.getString(3);
System.out.println("mimeType = " + mimeType);
System.out.println("data = " + data);
}
}
}
finally
{
c.close();
}
}
例如,处理程序的控制台输出包括:
mimeType = vnd.android.cursor.item/name
data = A name
联系人姓名与 selected 不同 selection activity。
在方法pickContacts
中,改成Contacts._ID
,偶然发现了一个ID,因为RawContacts._ID
和Contacts._ID
都是字符串"_id ",但这完全是错误的。
接下来,由于您实际上是在获取联系人 ID,因此您需要修改 getContactDetails
以接受 ContactId
而不是 RawContactId
。
不确定为什么需要涉及 Entity
这样的 API,如果您只需要查询该联系人的数据,请执行以下操作:
private void getContactDetails (long contactId) {
Log.i("Contacts", "Get contact with id " + contactId);
String[] projection = new String[]{Data.DISPLAY_NAME, Data.MIMETYPE, Data.DATA1};
String selection = Data.CONTACT_ID + "=" + contactId;
Cursor c = getContentResolver().query(Data.CONTENT_URI, projection, selection, null, null);
if (c == null) {
return;
}
try {
while (c.moveToNext()) {
String name = c.getString(0);
String mimeType = c.getString(1);
String data = c.getString(2);
Log.i("Contacts", contactId + ", " + name + ", " + mimetype + ", " + data);
}
} finally {
c.close();
}
}
我有一个 Activity 允许用户 select 联系人。完成后,selected 联系人的 ID 将在回复 Intent 中传递。在处理结果的地方,要读取 selected 联系人的详细信息。 问题在于,在处理结果时,读取的详细信息与 select 编辑的联系人不同。 我不知道为什么。在我的例子中,用户只有 select 一个联系人。
我已经阅读了大量文档和其他有关阅读联系人的问题,但没有看到任何对我的案例有帮助的内容。
从 Activity 获取用户 selection 来自联系人:
@Override
protected void onCreate (Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_select_from_contacts);
m_view = findViewById(R.id.lv_contactsSelect);
m_view.setVisibility(View.VISIBLE);
getListView().setItemsCanFocus(false);
getListView().setChoiceMode(ListView.CHOICE_MODE_MULTIPLE);
Cursor cursor = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,
new String[]{ContactsContract.Contacts._ID,
ContactsContract.Contacts.DISPLAY_NAME},
null, null, "UPPER(" + ContactsContract.Contacts.DISPLAY_NAME + ") ASC");
setListAdapter(new SimpleCursorAdapter(this,
android.R.layout.simple_list_item_multiple_choice,
cursor,
new String[]{ContactsContract.Contacts.DISPLAY_NAME},
new int[]{android.R.id.text1},
0));
Button btn = findViewById(R.id.btn_get_contacts);
btn.setOnClickListener((View view) -> {
Intent replyIntent = new Intent();
ArrayList<Long> ids = pickContacts();
replyIntent.putExtra(Activities.ARG_SELECTED, ids);
setResult(Activities.RESULT_CONTACTS_SELECTED, replyIntent);
finish();
});
}
/** Viewer for list of contacts */
private ListView m_view;
private ListView getListView ()
{ return m_view; }
private CursorAdapter mAdapter;
private void setListAdapter (@NonNull CursorAdapter adapter)
{
mAdapter = adapter;
m_view.setAdapter(adapter);
}
// return id for each selected contact
private ArrayList<Long> pickContacts ()
{
SparseBooleanArray a = getListView().getCheckedItemPositions();
ArrayList<Long> contacts = new ArrayList<>();
for (int i = 0; i < a.size(); i++)
{
if (a.valueAt(i))
{
Cursor c = (Cursor)mAdapter.getItem(a.keyAt(i));
// TODO use RawContacts or Contacts? Currently the result is the same.
//Long idContact = c.getLong(c.getColumnIndex(ContactsContract.Contacts._ID));
Long idRaw = c.getLong(c.getColumnIndex(ContactsContract.RawContacts._ID));
contacts.add(idRaw);
}
}
return contacts;
}
正在处理结果:
@Override
protected void onActivityResult (int requestCode, int resultCode, Intent data)
{
if (resultCode == Activities.RESULT_CONTACTS_SELECTED)
{
ArrayList<Long> ids = (ArrayList<Long>)data.getSerializableExtra(Activities.ARG_SELECTED);
for (long id : ids)
{
getContactDetails(id);
}
}
}
/**
* As mentioned in https://developer.android.com/reference/android/provider/ContactsContract.RawContacts
* the best way to read a raw contact along with associated data is by using the Entity directory.
*/
// FIXME: The id from the received result matches what was selected,
// but this function reads details for a different contact.
private void getContactDetails (long rawContactId)
{
System.out.println("Get contact with id " + rawContactId);
Uri rawContactUri = ContentUris.withAppendedId(RawContacts.CONTENT_URI, rawContactId);
Uri entityUri = Uri.withAppendedPath(rawContactUri, Entity.CONTENT_DIRECTORY);
// For example, this output can be "Get contact from entity uri content://com.android.contacts/raw_contacts/615/entity"
// (Where 615 is the id for the selected contact.)
System.out.println("Get contact from entity uri " + entityUri);
Cursor c = getContentResolver().query(entityUri,
new String[]{RawContacts.SOURCE_ID, Entity.DATA_ID, Entity.MIMETYPE, Entity.DATA1}, // projection
null, null, null);
if (c == null)
return;
try
{
while (c.moveToNext())
{
// In this example I'm just dumping data to the console.
if (!c.isNull(1))
{
String mimeType = c.getString(2);
String data = c.getString(3);
System.out.println("mimeType = " + mimeType);
System.out.println("data = " + data);
}
}
}
finally
{
c.close();
}
}
例如,处理程序的控制台输出包括:
mimeType = vnd.android.cursor.item/name
data = A name
联系人姓名与 selected 不同 selection activity。
在方法pickContacts
中,改成Contacts._ID
,偶然发现了一个ID,因为RawContacts._ID
和Contacts._ID
都是字符串"_id ",但这完全是错误的。
接下来,由于您实际上是在获取联系人 ID,因此您需要修改 getContactDetails
以接受 ContactId
而不是 RawContactId
。
不确定为什么需要涉及 Entity
这样的 API,如果您只需要查询该联系人的数据,请执行以下操作:
private void getContactDetails (long contactId) {
Log.i("Contacts", "Get contact with id " + contactId);
String[] projection = new String[]{Data.DISPLAY_NAME, Data.MIMETYPE, Data.DATA1};
String selection = Data.CONTACT_ID + "=" + contactId;
Cursor c = getContentResolver().query(Data.CONTENT_URI, projection, selection, null, null);
if (c == null) {
return;
}
try {
while (c.moveToNext()) {
String name = c.getString(0);
String mimeType = c.getString(1);
String data = c.getString(2);
Log.i("Contacts", contactId + ", " + name + ", " + mimetype + ", " + data);
}
} finally {
c.close();
}
}