1 ContentProvider组件
1.1 简介
Android系统自带了一些应用,对应的数据库分别存储了联系人信息、音乐文件和短信息等。出于安全性考虑,不允许用户编程直接操作上述数据库(如删除数据表、修改表结构等),而是提供了相应的内容提供者组件,通过相应的Uri来实现信息检索——ContentProvider。
ContentProvider是实现应用程序间数据共享最标准的方式,是Android四大组件中的一个。应用程序通过ContentResolver对象访问ContentProvider中的数据,该对象提供了持久层数据的CRUD方法。
1.2 一些应用的Uri
手机联系人:ContactsContract.Contacts.CONTENT_URI;
音频: MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
短信:Uri.parse(“content://sms”);
图片:MediaStore.Images.Media.EXTERNAL_CONTENT_UR;
视频:MediaStore.Video.Media.EXTERNAL_CONTENT_URI
2 实践
2.1 要求:
读取手机联系人中的信息,并在RecyclerView中显示出来。
2.2 手机联系人信息
手机联系人信息存储位置:
手机系统目录data/data下的包com.android.providers.contacts里,存放手机联系人数据库contacts2.db。
手机联系人信息存储结构
数据库contacts2.db里包含表raw_contacts,联系人id存放在字段contact_id里。
表data存放了联系人的具体信息。
表contacts存放了联系人的其它信息。
2.3 实际操作
(1)在Fragment对应的布局文件中添加RecyclerView组件以及相应的.xml文件
主布局文件
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:id="@+id/textView"
android:layout_width="match_parent"
android:layout_height="60dp"
android:background="@android:color/holo_green_dark"
android:gravity="center"
android:text="这是微信联系人界面"
android:textSize="25sp"
android:textStyle="bold" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rcv_contacts"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1" />
</LinearLayout>
RecyclerView使用的布局文件:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/LLName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_Name1"
android:layout_width="90dp"
android:layout_height="wrap_content"
android:padding="8dp"
android:text="姓名"
android:textColor="@android:color/background_dark"
android:textSize="18sp" />
<TextView
android:id="@+id/tv_Name2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="8dp"
android:text="TextView"
android:textColor="@android:color/background_dark"
android:textSize="18sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/LLPhone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/darker_gray"
android:orientation="horizontal">
<TextView
android:id="@+id/tv_Phone1"
android:layout_width="90dp"
android:layout_height="wrap_content"
android:padding="8dp"
android:text="电话号码"
android:textColor="@android:color/background_dark"
android:textSize="18sp" />
<TextView
android:id="@+id/tv_Phone2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:text="TextView"
android:textColor="@android:color/background_dark"
android:textSize="18sp" />
</LinearLayout>
</LinearLayout>
(2)编写RecyclerView适配器
public class ContactsAdapter extends RecyclerView.Adapter<ContactsAdapter.ContactsViewHolder> {
private List<ContactsAccount> contactsAccounts;
private Context mContext;
public ContactsAdapter(Context context, List<ContactsAccount> contactsAccounts) {
mContext=context;
this.contactsAccounts = contactsAccounts;
}
@Override
public ContactsViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(mContext).inflate(R.layout.tab03_recyclerview_item, parent, false);
return new ContactsViewHolder(view);
}
@Override
public void onBindViewHolder(@NonNull ContactsViewHolder holder, int position) {
holder.tv_Name2.setText(contactsAccounts.get(position).getName());
holder.tv_Phone2.setText(contactsAccounts.get(position).getPhoneNumber());
}
@Override
public int getItemCount() {
return contactsAccounts.size();
}
class ContactsViewHolder extends RecyclerView.ViewHolder {
LinearLayout LLName,LLPhone;
TextView tv_Name1, tv_Name2,tv_Phone1,tv_Phone2;
public ContactsViewHolder(@NonNull View itemView) {
super(itemView);
LLName=itemView.findViewById(R.id.LLName);
LLPhone=itemView.findViewById(R.id.LLPhone);
tv_Name1=itemView.findViewById(R.id.tv_Name1);
tv_Name2=itemView.findViewById(R.id.tv_Name2);
tv_Phone1=itemView.findViewById(R.id.tv_Phone1);
tv_Phone2=itemView.findViewById(R.id.tv_Phone2);
}
}
}
(3)联系人实体类
public class ContactsAccount {
private String Name;
private String PhoneNumber;
public String getName() {
return Name;
}
public void setName(String name) {
Name = name;
}
public String getPhoneNumber() {
return PhoneNumber;
}
public void setPhoneNumber(String phoneNumber) {
PhoneNumber = phoneNumber;
}
}
(4)在Fragment中编写读取联系人信息和显示代码
public class contactFragment extends Fragment {
private ContentResolver contentResolver;//=getContext().getContentResolver();
private View view;
private RecyclerView recyclerView;
private List<ContactsAccount> contactsAccountList=new ArrayList<>();
private ContactsAdapter contactsAdapter;
public contactFragment() {
// Required empty public constructor
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
if (ContextCompat.checkSelfPermission(getContext(), Manifest.permission.READ_CONTACTS) != PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(this.getActivity(),new String[]{Manifest.permission.READ_CONTACTS},1);
}
// Inflate the layout for this fragment
view= inflater.inflate(R.layout.tab03, container, false);
return view;
}
@Override
public void onActivityCreated(@Nullable Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
ImageButton imageButton=(ImageButton)getActivity().findViewById(R.id.btn_contacts_img);
imageButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
fun();
}
});
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
public void fun(){
recyclerView=(RecyclerView)getActivity().findViewById(R.id.rcv_contacts);
//获取手机联系人的Uri,相当于提供了一个公共的数据库链接
Uri uri= ContactsContract.Contacts.CONTENT_URI;//内部类静态成员
//android.content.Context提供了抽象方法getContentResolver()方法
//通过内容(数据)解析器使用抽象类android.content.ContentResolver提供了query()等方法
Cursor cursor=getContext().getContentResolver().query(uri, null, null, null, null); //得到记录集
while(cursor.moveToNext()){
//先获取联系人_id字段的索引号后再获取_id值
int idFieldIndex=cursor.getColumnIndex("_id");//法一
//int idFieldIndex=cursor.getColumnIndex(ContactsContract.Contacts._ID);//法二
int id=cursor.getInt(idFieldIndex);
//先获取联系人姓名字段的索引号后再获取姓名字段值
int nameFieldIndex = cursor.getColumnIndex("display_name");
//int nameFieldIndex=cursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME);
String name=cursor.getString(nameFieldIndex);
int numCountFieldIndex=cursor.getColumnIndex(ContactsContract.Contacts.HAS_PHONE_NUMBER);
int numCount=cursor.getInt(numCountFieldIndex); //获取联系人的电话号码个数
String phoneNumber="";
if(numCount>0){ //联系人有至少一个电话号码
//在类ContactsContract.CommonDataKinds.Phone中根据id查询相应联系人的所有电话;
Cursor phonecursor=getContext().getContentResolver().query(
ContactsContract.CommonDataKinds.Phone.CONTENT_URI,
null, ContactsContract.CommonDataKinds.Phone.CONTACT_ID+"=?",
new String[]{Integer.toString(id)}, null);
if(phonecursor.moveToFirst()){ //仅读取第一个电话号码
int numFieldIndex=phonecursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER);
phoneNumber=phonecursor.getString(numFieldIndex);
}
}
ContactsAccount contactsAccount=new ContactsAccount();
contactsAccount.setName(name);
contactsAccount.setPhoneNumber(phoneNumber);
contactsAccountList.add(contactsAccount);
}
contactsAdapter=new ContactsAdapter(getContext(),contactsAccountList);
recyclerView.setAdapter(contactsAdapter);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
// recyclerView.setHasFixedSize(true);
}
}
注意点
(1)ImgButton的点击监听方法不能写在public View onCreateView()方法中,需写在public void onActivityCreated()方法中。
(2)联系人实体类对象必须在循环中创建,否则会覆盖。
ContactsAccount contactsAccount=new ContactsAccount();
contactsAccount.setName(name);
contactsAccount.setPhoneNumber(phoneNumber);
contactsAccountList.add(contactsAccount);
(3) 在Fragment中,使用getContentResolver()方法时需注上下文对象,即getContext()。
Cursor cursor=getContext().getContentResolver().query(uri, null, null, null, null);
(4)由于该应用需要读取手机联系人信息,需要在清单文件里注册读取联系人权限,代码如下:
<uses-permission android:name="android.permission.READ_CONTACTS"/>
2.4项目结果演示
查询前:
查询后:
该项目主要通过getContext().getContentResolver()获取ContentResolver对象,在通过ContentResolver获取ContentProvider提供的数据。最终将查询到的数据显示在RecyclerView上。
项目源码链接