一、实现方法
思路:
朝着实验要求和目的去想,要想访问系统中的联系人,可以利用 ContentResolver 类来访问,使用ContentResolver
类可以访问别的应用程序通过 ContentProvider 提供的数据,这里可以用 Android 系统提供的标准的
ContentProvider 来对手机联系人进行访问。
还有要想实现长按联系人姓名会弹出菜单显示,在Android的菜单分两种:options menu 、context menu
。(也有分三种的:options menu 、context menu、sub menu)其中options
menu是和Activity相关联的,context menu 是和View关联。我们需要点击控件出现的菜单属于context menu
;但是context menu
只能通过setOnCreateContextMenuListener来进行关联。在这里可以用上下文菜单context
menu,在创建的时候要重写父类的onCreateContextMenu(ContextMenu menu, View
v,ContextMenu.ContextMenuInfo menuInfo) 方法,其中长按事件,context menu
是和View关联。我们需要点击控件出现的菜单属于context menu ;但是context menu
只能通过setOnCreateContextMenuListener来进行关联。
…………………………………………………………………
过程
在MainActivity中的init( ) 方法中,程序根据 getContentResolver( ) 获取系统的联系人 id、姓名和电话号码,设置到 listView 中列表显示。同时通过setOnCreateContextMenuListener()方法为listView关联上下文菜单,在菜单项中通过switch语句来对点击菜单事件进行定,当在 listView 的item上长按时,会弹出上下文菜单。点击 “添加” 选项会通过Toast提示当前选择的联系人姓名;单击“删除”按钮,调用自定义deleteContact()函数根据id删除联系人的电话号码,同时删除联系人的姓名信息;单击“拨号”按钮,通过Intent调用Intent.ACTION_CALL的系统action,从而实现拨号功能。
还要在AndroidManifest.xml文件中注册联系人的访问权限和拨号权限。
…………………………………………………………………
二、最终效果
三、代码实现
3.1 布局文件
Activity_main.xml
1. <?xml version="1.0" encoding="utf-8"?>
2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
3. xmlns:app="http://schemas.android.com/apk/res-auto"
4. xmlns:tools="http://schemas.android.com/tools"
5. android:layout_width="match_parent"
6. android:layout_height="match_parent"
7. tools:context=".MainActivity">
8. <ListView
9. android:id="@+id/list_view"
10. android:layout_width="wrap_content"
11. android:layout_height="wrap_content"
12. android:divider="#D1BD11"
13. android:dividerHeight="2dp">
14. </ListView>
15. </RelativeLayout>
view_list_item.xml
17. <?xml version="1.0" encoding="utf-8"?>
18. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
19. android:orientation="horizontal" android:layout_width="match_parent"
20. android:layout_height="match_parent">
21. <!--头像图标显示区域布局设定-->
22. <ImageView
23. android:id="@+id/lvew_img"
24. android:layout_width="48dp"
25. android:layout_height="48dp"
26. android:layout_margin="8dp"
27. />
28. <!--联系人显示区域布局-->
29. <TextView
30. android:id="@+id/lvew_name"
31. android:layout_width="wrap_content"
32. android:layout_height="wrap_content"
33. android:textSize="19sp"
34. android:text="aaaSFVSsdf"
35. android:textColor="#E6175D"
36. android:paddingTop="17dp"
37. android:paddingBottom="10dp"
38. android:paddingLeft="10dp"/>
39. </LinearLayout>
3.2 程序文件
MainActivity.java
1. package com.example.myapplication;
2.
3. import androidx.annotation.NonNull;
4. import androidx.annotation.RequiresApi;
5. import androidx.appcompat.app.AlertDialog;
6. import androidx.appcompat.app.AppCompatActivity;
7. import androidx.core.app.ActivityCompat;
8. import androidx.core.content.ContextCompat;
9.
10. import android.Manifest;
11. import android.content.ContentResolver;
12. import android.content.DialogInterface;
13. import android.content.Intent;
14. import android.content.pm.PackageManager;
15. import android.database.Cursor;
16. import android.net.Uri;
17. import android.os.Build;
18. import android.os.Bundle;
19. import android.provider.ContactsContract;
20. import android.provider.Settings;
21. import android.view.ContextMenu;
22. import android.view.MenuItem;
23. import android.view.View;
24. import android.widget.AdapterView;
25. import android.widget.ListView;
26. import android.widget.Toast;
27.
28. import java.lang.ref.ReferenceQueue;
29. import java.util.ArrayList;
30. import java.util.List;
31.
32. public class MainActivity extends AppCompatActivity {
33. private ListViewAdapter mAdapter;
34.
35. @Override
36. protected void onCreate(Bundle savedInstanceState) {
37. super.onCreate(savedInstanceState);
38. setContentView(R.layout.activity_main);
39. mAdapter = new ListViewAdapter(this);
40. init();
41. ListView listView = (ListView) findViewById(R.id.list_view);
42. listView.setAdapter(mAdapter);
43. listView.setOnCreateContextMenuListener(new View.OnCreateContextMenuListener() {
44. @Override
45. public void onCreateContextMenu(ContextMenu menu, View v,
46. ContextMenu.ContextMenuInfo menuInfo) {
47. menu.setHeaderTitle("选择操作");
48. menu.add(0, 0, 0, "添加");
49. menu.add(0, 1, 0, "删除");
50. menu.add(0, 2, 0, "拨号");
51. }
52. });
53. }
54.
55. private void init() {
56. List<Contact> contacts = new ArrayList<Contact>();
57. Cursor cursor = getContentResolver().query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null); //查询联系人的数据
58. while (cursor.moveToNext()) //遍历
59. {
60. //获取数据的id
61. String id = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts._ID));
62. //获取联系人的显示姓名
63. String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
64. //根据Id查询联系人的电话号码
65. Cursor c = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, ContactsContract.CommonDataKinds.Phone._ID + "=" + id, null, null);
66. List<String> phones = new ArrayList<String>();
67. while (c.moveToNext()) //遍历取出联系人的电话号码
68. {
69. String phone = c.getString(c.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
70. phones.add(phone);
71. }
72. contacts.add(new Contact(id, name, phones));
73. }
74. mAdapter.updateContacts(contacts);
75. }
76. @RequiresApi(api = Build.VERSION_CODES.M)
77. @Override
78. public boolean onContextItemSelected(MenuItem item) {
79. AdapterView.AdapterContextMenuInfo menuInfo = (AdapterView.AdapterContextMenuInfo) item.getMenuInfo();
80. //info.id得到 listview 中选择的条目绑定的id
81. int position = menuInfo.position;
82. Contact contact = mAdapter.getItem(position);
83. switch (item.getItemId()) {
84. case 0:
85. Toast.makeText(this, "add:" + contact.getContactName(), Toast.LENGTH_SHORT).show();
86. return true;
87. case 1:
88. deleteContact(contact);
89. return true;
90. case 2:
91. if (ContextCompat.checkSelfPermission(this,Manifest.permission.CALL_PHONE) != PackageManager.PERMISSION_GRANTED){
92. //首先判断否获取了权限
93. if (ActivityCompat.shouldShowRequestPermissionRationale( this,Manifest.permission.CALL_PHONE)) {
94. //让用户手动授权
95. Toast.makeText(this, "请授权!", Toast.LENGTH_LONG).show();
96. Intent intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
97. Uri uri = Uri.fromParts("package", getPackageName(), null);
98. intent.setData(uri);
99. startActivity(intent);
100. }else{
101. ActivityCompat.requestPermissions( this,new String[]{Manifest.permission.CALL_PHONE},1);
102. }
103. }else {
104. Intent intent = new Intent(Intent.ACTION_CALL);
105. Uri data = Uri.parse("tel:" + contact.getPhone().get(0));
106. intent.setData(data);
107. startActivity(intent);
108.
109. }
110. /*Intent intent = new Intent(Intent.ACTION_CALL);
111. Uri data = Uri.parse("tel:" + contact.getPhone().get(0));
112. intent.setData(data);
113.
114. startActivity(intent);
115. return true;*/
116. default:
117. return super.onContextItemSelected(item);
118. }
119. }
120. private void deleteContact(Contact contact)
121. {
122. ContentResolver resolver = getContentResolver();
123. //删除Contacts表中的数据
124. resolver.delete(ContactsContract.Contacts.CONTENT_URI, ContactsContract.Contacts._ID + " =?", new String[]{String.valueOf(contact.getContactId())});
125. //删除RawContacts表的数据
126. resolver.delete(ContactsContract.RawContacts.CONTENT_URI, ContactsContract.RawContacts.CONTACT_ID + " =?", new String[]{String.valueOf(contact.getContactId())});
127. //删除姓名
128. resolver.delete(ContactsContract.RawContacts.CONTENT_URI, "display_name=?", new String[]{contact.getContactName()});
129. }
130. }
ListViewAdapter.java
1. package com.example.myapplication;
2.
3. import android.content.Context;
4. import android.view.LayoutInflater;
5. import android.view.View;
6. import android.view.ViewGroup;
7. import android.widget.BaseAdapter;
8. import android.widget.ImageView;
9. import android.widget.TextView;
10. import java.util.ArrayList;
11. import java.util.List;
12.
13. public class ListViewAdapter extends BaseAdapter {
14. private LayoutInflater flater;
15. private List<Contact> mDatas;
16. public ListViewAdapter(Context context)
17. {
18. flater = LayoutInflater.from(context);
19. mDatas = new ArrayList<Contact>();
20. }
21. public void updateContacts(List<Contact> contacts)
22. {
23. mDatas.clear();
24. mDatas.addAll(contacts);
25. }
26.
27. public int getCount() {
28. return (null == mDatas || mDatas.isEmpty()) ? 0 : mDatas.size();
29. }
30. @Override
31. public Contact getItem(int pos) {
32. if(null != mDatas && pos < mDatas.size())
33. {
34. return mDatas.get(pos);
35. }
36. return null;
37. }
38. @Override
39. public long getItemId(int position) {
40. return 0;
41. }
42. @Override
43. public View getView(int position, View convertView, ViewGroup parent) {
44. if(null == convertView)
45. {
46. //为每一个子项加载布局
47. convertView = flater.inflate(R.layout.view_list_item, null);
48. }
49. //获取子item布局文件中的控件
50. ImageView imageView = (ImageView) convertView.findViewById(R.id.lvew_img);
51. TextView txtTitle = (TextView)convertView.findViewById(R.id.lvew_name);
52.
53. Contact contact = getItem(position); //根据position获取数据
54. if(null != contact)
55. {
56. imageView.setImageResource(R.drawable.touxiang);
57. txtTitle.setText(contact.getContactName());
58. }
59. return convertView;
60. }
61. }
Contact.java
1. package com.example.myapplication;
2.
3. import java.util.List;
4.
5. public class Contact {
6. private String contactId;
7. private String contactName;
8. private List<String> phone;
9.
10. public Contact(String contactId, String contactName, List<String> phone) {
11. super();
12. this.contactId = contactId;
13. this.contactName = contactName;
14. this.phone = phone;
15. }
16. public String getContactId() {
17. return contactId;
18. }
19. public void setContactId(String contactId) {
20. this.contactId = contactId;
21. }
22. public String getContactName() {
23. return contactName;
24. }
25. public void setContactName(String contactName) {
26. this.contactName = contactName;
27. }
28. public List<String> getPhone() {
29. return phone;
30. }
31. public void setPhone(List<String> phone) {
32. this.phone = phone;
33. }
34. }
AndroidManifest.xml
1. <uses-permission android:name="android.permission.GET_ACCOUNTS" />
2. <uses-permission android:name="android.permission.READ_CONTACTS" />
3. <uses-permission android:name="android.permission.WRITE_CONTACTS" />
4. <uses-permission android:name="android.permission.CALL_PHONE" />
四、特别注意
在Android 6.0以后开始,对于部分敏感的“危险”权限,需要在应用运行时向用户申请,只有用户允许的情况下这个权限才会被授予给应用。即获取权限也还是要动态获取。添加如下代码:
注:Android 第三次实验