获取通讯录内容,并对其进行增删改操作

2022-07-29,,,,

获取通讯录内容,并对其进行增删操作

  • 案例效果
  • 案例效果图
  • 思路分析
  • 模块分析
    • 主界面的功能
      • 初始化界面initView()
      • 初始化数据
        • 动态权限申请
        • 获取数据
  • 添加或者修改界面
    • 数据初始化
    • 根据Boolean值判断执行何种操作
      • 添加数据
      • 三级标题
  • 全部代码

案例效果

1.回顾recycler View控件的使用
2.实现ContentResolver的相关API
3.熟悉安卓系统中通讯录的几个关键表之间的关联

案例效果图

思路分析

1.主界面由一个recyclerView控件和一个Button控件构成。
2.长按recyclerView控件会弹出一个编辑菜单。
3.用ContentResolver来获取通信录中的数据。

模块分析

主界面的功能

1.初始化界面
2.获取数据
注意:要动态的申请权限
由于每次回到该页面,都会执行onResume()方法,故将数据的初始化和获取,写在这个函数里,就可以实时地更新数据。

初始化界面initView()

实现长按item弹出菜单,要对recycler View对象进行注册。
registerForContextMenu(rvContract);

private void initView() {
    rvContract = (RecyclerView) findViewById(R.id.rvContract);
    btn_add = (Button) findViewById(R.id.btn_add);
    //传入线性布局
    rvContract.setLayoutManager(new LinearLayoutManager(this));
    mList = new ArrayList<>();
    mAdapter = new ContactAdapter(this, mList);
    rvContract.setAdapter(mAdapter);
    //实现长按item弹出菜单
    registerForContextMenu(rvContract);
    btn_add.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            Intent intent = new Intent(MainActivity.this, AddOrModifyActivity.class);
            intent.putExtra(IS_ADD_KEY, true);
            startActivity(intent);
        }
    });

}

初始化数据

动态权限申请

 int readContacts = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_CONTACTS);
    int writeContacts = ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_CONTACTS);
    if (readContacts == PackageManager.PERMISSION_GRANTED && writeContacts ==
            PackageManager.PERMISSION_GRANTED) {
        //开始获取数据
        getData();
    } else {
        ActivityCompat.requestPermissions(this, contactPermissions, CONTACT_REQUEST_CODE);
    }
}

获取权限后回调

/**
 * 用户回复后,都会回调这个函数
 *
 * @param requestCode
 * @param permissions
 * @param grantResults 授权的结果保存在此
 */
@RequiresApi(api = Build.VERSION_CODES.O)
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    super.onRequestPermissionsResult(requestCode, permissions, grantResults);
    switch (requestCode) {
        case CONTACT_REQUEST_CODE:
            int length = contactPermissions.length;
            boolean flag = true;
            for (int i = 0; i < length; i++) {
                //PERMISSION_DENIED为被拒绝的权限集
                if (grantResults[i] == PackageManager.PERMISSION_DENIED) {
                    flag = false;
                    break;
                }
                if (flag) {
                    getData();
                }
            }
    }
}

获取数据

/**
 * ContactsContract.RawContacts.CONTENT_URI是指原始表的URI
 */
@RequiresApi(api = Build.VERSION_CODES.O)
private void getData() {
    mList.clear();//清空之前的查询结果
    Cursor cursor = resolver.query(ContactsContract.RawContacts.CONTENT_URI, null, null,
            null);
    while (cursor.moveToNext()) {
        //新建一个Bean来存储数据
        ContactBean bean = new ContactBean();
        int id = cursor.getInt(cursor.getColumnIndex(ContactsContract.RawContacts._ID));
        String name = cursor.getString(cursor.getColumnIndex(ContactsContract.Data.DISPLAY_NAME));
        //一个用户的手机号可能有多个,故手机号是一个集合。,取第一个手机号
        String phone = null;
        Cursor phoneCursor = resolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
                null, ContactsContract.Data.RAW_CONTACT_ID + "=?", new String[]{
                        String.valueOf(id)}, null);
        if (phoneCursor.moveToFirst()) {
            phone = phoneCursor.getString(phoneCursor.getColumnIndex(ContactsContract.
                    CommonDataKinds.Phone.NUMBER));
        }
        phoneCursor.close();
        bean.setId(id);
        bean.setName(name);
        bean.setPhone(phone);
        mList.add(bean);
    }
    cursor.close();
    mAdapter.notifyDataSetChanged();//recyclerView里的数据刷新。
}

添加或者修改界面

1.获取EditView上的数据
2.新建一个ContentValue对象,将数据封装在里面
3.调用ContentResolver进行添加和修改操作
对于安卓如何封装和解析通讯录数据表的内容
参考使用ContentResolver来对通讯录进行增删改查

数据初始化

private void initData() {
    Intent intent = getIntent();
    is_add = intent.getBooleanExtra(IS_ADD_KEY,true);
    resolver = getContentResolver();
    bean = intent.getParcelableExtra(BEAN_KEY);//如果之前没有传入,就是null.
    if (bean !=null){
        //将数据显示出来
       etName.setText(bean.getName());
       etPhone.setText(bean.getPhone());
    }
}

根据Boolean值判断执行何种操作

is_add是是否为添加事件的判断。

public void onViewClicked() {
    name = etName.getText().toString();
    phone = etPhone.getText().toString();
    if (TextUtils.isEmpty(name)){
        toastShow("请输入联系人姓名");
    }else if (TextUtils.isEmpty(phone)){
        toastShow("请输入联系人电话");
    }else {
        if (is_add){
            insertContact();
        }else {
            updateContact();
        }
    }

添加数据

private void insertContact() {
    /**
     * 首先向row_contact表中插入一条既然,目的是为了获取raw_contact_id字段
     */
    ContentValues values = new ContentValues();
    Uri rawContactUri = resolver.insert(ContactsContract.RawContacts.CONTENT_URI,values);
    //ContentUris一个uri相关的工具类
    long rawContactId = ContentUris.parseId(rawContactUri);//通过uri获取id
    /**
     * 在row_contact中的一条数据是对应DAta表中的两条数据,古要单独插入。
     * 插入姓名
     */
    values.clear();
    values.put(ContactsContract.Data.RAW_CONTACT_ID,rawContactId);
    //MIMETYPE是指文件类型,eg.html...
    values.put(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.
            StructuredName.CONTENT_ITEM_TYPE);
    values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME,name);
    Uri nameUri = resolver.insert(ContactsContract.Data.CONTENT_URI, values);
    /**
     * 插入手机号
     */
    values.clear();
    values.put(ContactsContract.Data.RAW_CONTACT_ID,rawContactId);
    //MIMETYPE是指文件类型,eg.html...
    values.put(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.
           Phone.CONTENT_ITEM_TYPE);
    values.put(ContactsContract.CommonDataKinds.Phone.NUMBER,phone);
    Uri phoneUri = resolver.insert(ContactsContract.Data.CONTENT_URI, values);

    if (nameUri !=null && phoneUri!= null){
        toastShow("保存成功");
    }else {
        toastShow("保存失败");
    }
    finish();//结束该界面
}

三级标题

private void updateContact() {
    ContentValues values = new ContentValues();
    values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, name);
    values.put(ContactsContract.CommonDataKinds.Phone.NUMBER,phone);
    Log.d("updateContact", "values已经产生");
    int result = resolver.update(ContactsContract.Data.CONTENT_URI, values,
            ContactsContract.Data.RAW_CONTACT_ID +"=?",new String[]{
        String.valueOf(bean.getId())});
    if (result > 0){
        toastShow("修改成功");
    }else {
        toastShow("修改失败");
    }
    finish();//关闭当前页面
}

全部代码

mainActivity

package com.example.contentproviderdemo.activity;

import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import com.example.contentproviderdemo.R;

import Bean.ContactBean;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

public class AddOrModifyActivity extends AppCompatActivity {

    @BindView(R.id.et_name)
    EditText etName;
    @BindView(R.id.et_phone)
    EditText etPhone;
    @BindView(R.id.btn_save)
    Button btnSave;

    private static final String IS_ADD_KEY = "IS_ADD_KEY";
    private static final String BEAN_KEY= "BEAN_KEY";

    private boolean is_add;//null
    private ContentResolver resolver;//null
    private String name;//null
    private String phone;//null
    private ContactBean bean;//null


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add_or_modify);
        ButterKnife.bind(this);
        initData();

    }

    private void initData() {
        Intent intent = getIntent();
        is_add = intent.getBooleanExtra(IS_ADD_KEY,true);
        resolver = getContentResolver();
        bean = intent.getParcelableExtra(BEAN_KEY);//如果之前没有传入,就是null.
        if (bean !=null){
            //将数据显示出来
           etName.setText(bean.getName());
           etPhone.setText(bean.getPhone());
        }
    }

    @OnClick(R.id.btn_save)
    public void onViewClicked() {
        name = etName.getText().toString();
        phone = etPhone.getText().toString();
        if (TextUtils.isEmpty(name)){
            toastShow("请输入联系人姓名");
        }else if (TextUtils.isEmpty(phone)){
            toastShow("请输入联系人电话");
        }else {
            if (is_add){
                insertContact();
            }else {
                updateContact();
            }
        }


    }

    private void updateContact() {
        ContentValues values = new ContentValues();
        values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, name);
        values.put(ContactsContract.CommonDataKinds.Phone.NUMBER,phone);
        Log.d("updateContact", "values已经产生");
        int result = resolver.update(ContactsContract.Data.CONTENT_URI, values,
                ContactsContract.Data.RAW_CONTACT_ID +"=?",new String[]{
            String.valueOf(bean.getId())});
        if (result > 0){
            toastShow("修改成功");
        }else {
            toastShow("修改失败");
        }
        finish();//关闭当前页面
    }

    private void insertContact() {
        /**
         * 首先向row_contact表中插入一条既然,目的是为了获取raw_contact_id字段
         */
        ContentValues values = new ContentValues();
        Uri rawContactUri = resolver.insert(ContactsContract.RawContacts.CONTENT_URI,values);
        //ContentUris一个uri相关的工具类
        long rawContactId = ContentUris.parseId(rawContactUri);//通过uri获取id
        /**
         * 在row_contact中的一条数据是对应DAta表中的两条数据,古要单独插入。
         * 插入姓名
         */
        values.clear();
        values.put(ContactsContract.Data.RAW_CONTACT_ID,rawContactId);
        //MIMETYPE是指文件类型,eg.html...
        values.put(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.
                StructuredName.CONTENT_ITEM_TYPE);
        values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME,name);
        Uri nameUri = resolver.insert(ContactsContract.Data.CONTENT_URI, values);
        /**
         * 插入手机号
         */
        values.clear();
        values.put(ContactsContract.Data.RAW_CONTACT_ID,rawContactId);
        //MIMETYPE是指文件类型,eg.html...
        values.put(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.
               Phone.CONTENT_ITEM_TYPE);
        values.put(ContactsContract.CommonDataKinds.Phone.NUMBER,phone);
        Uri phoneUri = resolver.insert(ContactsContract.Data.CONTENT_URI, values);

        if (nameUri !=null && phoneUri!= null){
            toastShow("保存成功");
        }else {
            toastShow("保存失败");
        }
        finish();//结束该界面
    }

    private void toastShow(String s) {
        Toast.makeText(this,s,Toast.LENGTH_SHORT).show();
    }
}

recyclerView的适配器代码
其中viewHolder要手动实现监听内容菜单的接口,

static class ContractViewHolder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener

并且在类的构造器中进行设置。

itemView.setOnCreateContextMenuListener(this);

全部代码

package com.example.contentproviderdemo;

import android.content.Context;
import android.content.Intent;
import android.view.ContextMenu;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.example.contentproviderdemo.activity.MainActivity;

import java.util.List;

import Bean.ContactBean;

/**
 * @ 功能适配器中必须要有实体类,也是bean
 * 1.数据的绑定,2.创建viewHolder--布局加载器--上下文对象
 * Ctreate by barry on 2020/9/20.
 */
public class ContactAdapter extends RecyclerView.Adapter<ContactAdapter.ContractViewHolder> {
    private Context mContext;//null
    private List<ContactBean> mList;//null
    private LayoutInflater mInflater;//null

    private static final String POSITION_KEY ="POSITION_KEY";

    public ContactAdapter(Context mContext, List<ContactBean> mList) {
        this.mContext = mContext;
        this.mList = mList;
        mInflater = LayoutInflater.from(mContext);
    }

    /**
     * 创建ViewHolder实例,并将item布局加载进入
     * @param parent
     * @param viewType
     * @return
     */
    @NonNull
    @Override
    public ContractViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        //加载item布局
        View view = mInflater.inflate(R.layout.recyclerview_item_contact,parent,false);
        ContractViewHolder viewHolder = new ContractViewHolder(view);
        return viewHolder;
    }

    /**
     * 对vieholder对象进行数据赋值
     * @param holder
     * @param position
     */
    @Override
    public void onBindViewHolder(@NonNull ContractViewHolder holder, int position) {
        ContactBean contact = mList.get(position);
        holder.tvName.setText(contact.getName());
        holder.tvPhone.setText(contact.getPhone());

    }

    /**
     * 统计item个数
     * @return
     */
    @Override
    public int getItemCount() {
        return mList.size();
    }

    static class ContractViewHolder extends RecyclerView.ViewHolder implements View.OnCreateContextMenuListener{
        private TextView tvName;//null
        private TextView tvPhone;//null

        public ContractViewHolder(@NonNull View itemView) {
            super(itemView);
            tvName = (TextView)itemView.findViewById(R.id.tv_name);
            tvPhone = (TextView)itemView.findViewById(R.id.tv_phone);
            //由于recycleView没有实现长按弹出菜单的接口,要在ViewHolder中自己实现该接口
            //setOnCreateContextMenuListener(OnCreateContextMenuListener l)
            // 由于ContractViewHolder已经实现该接口,故直接传入this
            itemView.setOnCreateContextMenuListener(this);

        }
        //创建响应的菜单

        @Override
        public void onCreateContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo) {
            //获取当前所按的item的下标,回传到MainActivity中供onContextItemSelected使用。
            int position = getAdapterPosition();
            Intent intent = new Intent();//这里不需要使用intent,来跳转
            intent.putExtra(POSITION_KEY,position);

            menu.setHeaderTitle("编剧");
            //菜单的选项时通过add来直接添加,通过setIntent(),让每一个MenuItem自带了一个intent
            menu.add(0,0,0,"修改").setIntent(intent);
            menu.add(0,1,0,"删除").setIntent(intent);

        }
    }
}

实体类的代码—为了在活动之间进行传输,要实现序列化

package Bean;

import android.os.Parcel;
import android.os.Parcelable;

/**由于要在不同的活动之间进行传递,该类必须实现序列化1.seriable 2.Parcelable
 * @ 功能
 * Ctreate by barry on 2020/9/22.
 */
public class ContactBean implements Parcelable {
    private int id;
    private String name;
    private String phone;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }


    @Override
    public int describeContents() {
        return 0;
    }

    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeInt(this.id);
        dest.writeString(this.name);
        dest.writeString(this.phone);
    }

    public ContactBean() {
    }

    protected ContactBean(Parcel in) {
        this.id = in.readInt();
        this.name = in.readString();
        this.phone = in.readString();
    }

    public static final Parcelable.Creator<ContactBean> CREATOR = new Parcelable.Creator<ContactBean>() {
        @Override
        public ContactBean createFromParcel(Parcel source) {
            return new ContactBean(source);
        }

        @Override
        public ContactBean[] newArray(int size) {
            return new ContactBean[size];
        }
    };
}

添加修改界面的代码

package com.example.contentproviderdemo.activity;

import android.content.ContentResolver;
import android.content.ContentUris;
import android.content.ContentValues;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;

import androidx.appcompat.app.AppCompatActivity;

import com.example.contentproviderdemo.R;

import Bean.ContactBean;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnClick;

public class AddOrModifyActivity extends AppCompatActivity {

    @BindView(R.id.et_name)
    EditText etName;
    @BindView(R.id.et_phone)
    EditText etPhone;
    @BindView(R.id.btn_save)
    Button btnSave;

    private static final String IS_ADD_KEY = "IS_ADD_KEY";
    private static final String BEAN_KEY= "BEAN_KEY";

    private boolean is_add;//null
    private ContentResolver resolver;//null
    private String name;//null
    private String phone;//null
    private ContactBean bean;//null


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_add_or_modify);
        ButterKnife.bind(this);
        initData();

    }

    private void initData() {
        Intent intent = getIntent();
        is_add = intent.getBooleanExtra(IS_ADD_KEY,true);
        resolver = getContentResolver();
        bean = intent.getParcelableExtra(BEAN_KEY);//如果之前没有传入,就是null.
        if (bean !=null){
            //将数据显示出来
           etName.setText(bean.getName());
           etPhone.setText(bean.getPhone());
        }
    }

    @OnClick(R.id.btn_save)
    public void onViewClicked() {
        name = etName.getText().toString();
        phone = etPhone.getText().toString();
        if (TextUtils.isEmpty(name)){
            toastShow("请输入联系人姓名");
        }else if (TextUtils.isEmpty(phone)){
            toastShow("请输入联系人电话");
        }else {
            if (is_add){
                insertContact();
            }else {
                updateContact();
            }
        }


    }

    private void updateContact() {
        ContentValues values = new ContentValues();
        values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, name);
        values.put(ContactsContract.CommonDataKinds.Phone.NUMBER,phone);
        Log.d("updateContact", "values已经产生");
        int result = resolver.update(ContactsContract.Data.CONTENT_URI, values,
                ContactsContract.Data.RAW_CONTACT_ID +"=?",new String[]{
            String.valueOf(bean.getId())});
        if (result > 0){
            toastShow("修改成功");
        }else {
            toastShow("修改失败");
        }
        finish();//关闭当前页面
    }

    private void insertContact() {
        /**
         * 首先向row_contact表中插入一条既然,目的是为了获取raw_contact_id字段
         */
        ContentValues values = new ContentValues();
        Uri rawContactUri = resolver.insert(ContactsContract.RawContacts.CONTENT_URI,values);
        //ContentUris一个uri相关的工具类
        long rawContactId = ContentUris.parseId(rawContactUri);//通过uri获取id
        /**
         * 在row_contact中的一条数据是对应DAta表中的两条数据,古要单独插入。
         * 插入姓名
         */
        values.clear();
        values.put(ContactsContract.Data.RAW_CONTACT_ID,rawContactId);
        //MIMETYPE是指文件类型,eg.html...
        values.put(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.
                StructuredName.CONTENT_ITEM_TYPE);
        values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME,name);
        Uri nameUri = resolver.insert(ContactsContract.Data.CONTENT_URI, values);
        /**
         * 插入手机号
         */
        values.clear();
        values.put(ContactsContract.Data.RAW_CONTACT_ID,rawContactId);
        //MIMETYPE是指文件类型,eg.html...
        values.put(ContactsContract.Data.MIMETYPE,ContactsContract.CommonDataKinds.
               Phone.CONTENT_ITEM_TYPE);
        values.put(ContactsContract.CommonDataKinds.Phone.NUMBER,phone);
        Uri phoneUri = resolver.insert(ContactsContract.Data.CONTENT_URI, values);

        if (nameUri !=null && phoneUri!= null){
            toastShow("保存成功");
        }else {
            toastShow("保存失败");
        }
        finish();//结束该界面
    }

    private void toastShow(String s) {
        Toast.makeText(this,s,Toast.LENGTH_SHORT).show();
    }
}

清单文件–两个权限的申请


<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.WRITE_CONTACTS" />

本文地址:https://blog.csdn.net/Barryjacket/article/details/108821453

《获取通讯录内容,并对其进行增删改操作.doc》

下载本文的Word格式文档,以方便收藏与打印。