文章目录
- 前言
- 读取通讯录信息
- 要求
- 环境
- 具体实现
- 主页面布局(activity_main.xml)
- 关于RecyclerView库的相关问题
- 添加RecyclerView库操作
- 解决报错
- Item布局(info.xml)
- 添加访问权限
- 编写实体类(ContactInfo.java)
- 编写适配器(MyAdapter.java)
- 编写主类(MainActivity.java)
- 运行测试
前言
- 本人将所学和前人的成果和经验结合,仅供学习和参考!!!
- 本文大部分源码内容有清晰的注释,请认真阅读!
读取通讯录信息
要求
- 通过线性布局和相对布局来搭建通讯录界面,界面效果如下图所示。创建布局文件contact_item.xml、导入界面图片、放置界面控件、创建条目界面的背景文件。创建ContactInfo类、在该类中创建联系人信息的属性。申请读取手机通讯录的权限,将数据显示到通讯录界面上。在AndroidMainfest.xml文件中添加读取系统通讯录的权限。运行Contacts程序,查看通讯录界面效果。
环境
- minSdk 24
- targetSdk 33
- sourceCompatibility JavaVersion.VERSION_1_8
- targetCompatibility JavaVersion.VERSION_1_8
- gradle-7.5
- Android Studio Electric Eel | 2022.1.1 Patch 1
- 知识储备:RecyclerView布局和ContentResolver的内容学习储备
具体实现
- 记得提前将需要的头像图片导入到
drawable
目录下
主页面布局(activity_main.xml)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="50dp"
android:text="通讯录"
android:gravity="center"
android:background="#4889f4"
android:textColor="@color/white"
android:textSize="20sp"
/>
<androidx.recyclerview.widget.RecyclerView
android:layout_marginTop="10dp"
android:layout_width="match_parent"
android:id="@+id/list"
android:layout_height="wrap_content"
/>
</LinearLayout>
关于RecyclerView库的相关问题
- 建议:该本地环境中,如果可以正常使用RecyclerView布局,即可不用引入RecyclerView库依赖,好像在其他的包中已经默认包含(亲测,正常运行程序)
- 如果,要引入,请参考一下操作
添加RecyclerView库操作
com.android.support:recyclerview-v7
- 然后,可以在Android视图下,模块的
build.grade
配置文件dependencies
中看到添加的依赖
解决报错
- 在Android视图下,模块的
build.properties
配置文件中添加
android.useAndroidX=true #如果该项本来存在,则不用添加
android.enableJetifier=true
Item布局(info.xml)
<?xml version="1.0" encoding="utf-8"?>
<!--item布局文件-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:orientation="horizontal"
>
<ImageView
android:id="@+id/iv"
android:layout_width="66dp"
android:layout_height="67dp"
android:src="@drawable/contact_photo"
/>
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="10dp"
android:layout_marginTop="5dp">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="16sp"
android:textColor="#ff8f03" />
<TextView
android:id="@+id/telephoneNumber"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="20sp"
android:layout_marginTop="10dp"
android:layout_below="@+id/name"
android:textColor="#ff716c6d"
android:maxLines="2"
android:ellipsize="end"/>
</RelativeLayout>
</LinearLayout>
添加访问权限
- 在
AndroidMainfest.xml
中application
上边标签添加通讯录访问权限
<!--添加读取系统通讯录的权限-->
<uses-permission android:name="android.permission.READ_CONTACTS" />
编写实体类(ContactInfo.java)
/**
* 实体类,用于存储联系人信息
*/
public class ContactInfo {
private String name, telephoneNumber;
public String getName() {
return name;
}
public String getTelephoneNumber() {
return telephoneNumber;
}
public void setName(String name) {
this.name = name;
}
public void setTelephoneNumber(String telephoneNumber) {
this.telephoneNumber = telephoneNumber;
}
}
编写适配器(MyAdapter.java)
import android.content.Context;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import java.util.List;
/**
* 自定义类实现数据适配
*/
public class MyAdapter extends RecyclerView.Adapter<MyAdapter.MyHolder> {
private Context myContext;
private List<ContactInfo> myContactInfos;
public MyAdapter(Context context,List<ContactInfo> contactInfoList){
this.myContext=context;
this.myContactInfos=contactInfoList;
}
/**
* 加载item界面的布局文件,并将RecyclerView.ViewHolder类的对象返回
* @param parent The ViewGroup into which the new View will be added after it is bound to
* an adapter position.
* @param viewType The view type of the new View.
*
* @return
*/
@NonNull
@Override
public MyHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view=View.inflate(myContext,R.layout.info,null);
MyHolder myHolder=new MyHolder(view);
return myHolder;
}
/**
* onBindViewHolder 将获取的数据设置到对应的控件上
* @param holder The ViewHolder which should be updated to represent the contents of the
* item at the given position in the data set.
* @param position The position of the item within the adapter's data set.
*/
@Override
public void onBindViewHolder(@NonNull MyHolder holder, int position) {
ContactInfo contactInfo=myContactInfos.get(position);
holder.name.setText(contactInfo.getName());
holder.telephoneNumber.setText(contactInfo.getTelephoneNumber());
}
/**
* 获取列表条目总数
* @return
*/
@Override
public int getItemCount() {
return myContactInfos.size();
}
/**
* 创建MyHolder类,继承RecyclerView.ViewHolder类,在该类中获取Item界面上的控件
*/
class MyHolder extends RecyclerView.ViewHolder{
TextView name,telephoneNumber;
public MyHolder(@NonNull View itemView) {
super(itemView);
name=itemView.findViewById(R.id.name);
telephoneNumber=itemView.findViewById(R.id.telephoneNumber);
}
}
}
编写主类(MainActivity.java)
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
import androidx.recyclerview.widget.DividerItemDecoration;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.widget.Toast;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private RecyclerView list;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//申请权限
getPermission();
// 获取RecyclerView控件
list=findViewById(R.id.list);
// 设置item分割线
list.addItemDecoration(new DividerItemDecoration(this,DividerItemDecoration.VERTICAL));
// 设置RecyclerView的显示方式为垂直布局
list.setLayoutManager(new LinearLayoutManager(MainActivity.this,LinearLayoutManager.VERTICAL,true));
// 通过setAdapter方法将适配器对象设置到RecyclerView控件上
MyAdapter myAdapter=new MyAdapter(this,getContacts());
list.setAdapter(myAdapter);
}
/**
* 申请权限
*/
public void getPermission(){
//检查权限是否允许
if (ActivityCompat.checkSelfPermission(this,"android.permission.READ_CONTACTS")!= PackageManager.PERMISSION_GRANTED){
//请求android.permission.READ_CONTACTS权限
ActivityCompat.requestPermissions(this,new String[]{"android.permission.READ_CONTACTS"},666);
//shouldShowRequestPermissionRationale 检查是否需要展示请求权限的提示
//首次运行程序时,选择允许权限访问,之后再次打开应用就不会出现请求权限的提示
if (ActivityCompat.shouldShowRequestPermissionRationale(MainActivity.this,"android.permission.READ_CONTACTS")){
Toast.makeText(this, "需要开启联系人权限", Toast.LENGTH_SHORT).show();
}else {
ActivityCompat.requestPermissions(this,new String[]{"android.permission.READ_CONTACTS"},666);
}
}
}
/**
* 手动请求权限之后的结果回调
* @param requestCode 请求吗
* @param permissions 系统的权限数据
* @param grantResults 请求码的状态
*
*/
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode==666){
/*
判断权限数组中是否有一个状态值为android.permission.READ_CONTACTS 该状态值表示允许读取系统短信。
如果有该状态值,提示联系人权限申请成功,否则,失败
* */
for (int i=0;i<permissions.length;i++){
if(permissions[i].equals("android.permission.READ_CONTACTS") && grantResults[i]==PackageManager.PERMISSION_GRANTED){
Toast.makeText(this, "联系人权限申请成功", Toast.LENGTH_SHORT).show();
return;
}
}
Toast.makeText(this, "联系人权限申请失败", Toast.LENGTH_SHORT).show();
}
}
/**
* 通过ContactInfo类和cursor遍历获取系统通讯录的联系人信息
* @return
*/
public List<ContactInfo> getContacts(){
List<ContactInfo> contactInfos=new ArrayList<>();
Cursor cursor01=getContentResolver().query(ContactsContract.Contacts.CONTENT_URI,null,null,null,null);
while (cursor01.moveToNext()){
ContactInfo contactInfo=new ContactInfo();
String Name,phone,id;
//获取name,并存入contactInfo
Name=cursor01.getString(cursor01.getColumnIndexOrThrow(ContactsContract.Contacts.DISPLAY_NAME));
contactInfo.setName(Name);
id=cursor01.getString(cursor01.getColumnIndexOrThrow(ContactsContract.Contacts._ID));
//获取phoneNumber,并存入contactInfo
Cursor cursor02=getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,null,ContactsContract.CommonDataKinds.Phone.CONTACT_ID+"="+id,null,null);
while (cursor02.moveToNext()){
phone=cursor02.getString(cursor02.getColumnIndexOrThrow(ContactsContract.CommonDataKinds.Phone.NUMBER));
contactInfo.setTelephoneNumber(phone);
}
//将其contactInfo存入contactInfos集合中
contactInfos.add(contactInfo);
//关闭游标
cursor02.close();
}
cursor01.close();
//最终返回list集合
return contactInfos;
}
}