该实验是通过ContentProvider读取手机通讯录
知识点包含了RecyclerView控件、UriMatcher、ContentResolver
先看效果,显示手机通讯录
首先是界面的布局代码
activity_main59.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"
android:orientation="vertical"
tools:context=".MainActivity59">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#42BCF3"
android:gravity="center"
android:text="通讯录"
android:textColor="#FFFFFF"
android:textSize="30dp" />
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#E4E0E0"
/>
</LinearLayout>
其次是RecyclerView的item布局代码,其中使用了CardView是为了方便快捷的弄个圆角储来
main59_item.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.cardview.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:padding="40dp"
app:cardCornerRadius="40px"
android:layout_marginTop="20dp"
android:background="@color/white">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/txlogo"/>
<LinearLayout
android:layout_marginLeft="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="姓名"
android:textSize="20dp"
android:textStyle="bold" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="号码"
android:layout_marginTop="10dp"
android:id="@+id/number"
android:textSize="20dp"/>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
一个联系人的实体类
Communication
public class Communication {
private String name;
private String number;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getNumber() {
return number;
}
public void setNumber(String number) {
this.number = number;
}
public Communication(String name, String number) {
this.name = name;
this.number = number;
}
}
RecyclerView的适配器:
Main59Adapter
import android.content.Context;
import android.database.Cursor;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
public class Main59Adapter extends RecyclerView.Adapter<Main59Adapter.MyViewHolder> {
private RecyclerView mRv;
private Context context;
private List<Communication> dataSource;
public Main59Adapter(Context context,RecyclerView recyclerView){
this.context=context;
this.dataSource=new ArrayList<>();
this.mRv=recyclerView;
}
public void setDataSource(List<Communication> dataSource) {
this.dataSource = dataSource;
notifyDataSetChanged();
}
class MyViewHolder extends RecyclerView.ViewHolder{
TextView name,number;
public MyViewHolder(@NonNull @NotNull View itemView) {
super(itemView);
name=itemView.findViewById(R.id.name);
number=itemView.findViewById(R.id.number);
}
}
@NonNull
@NotNull
@Override
public MyViewHolder onCreateViewHolder(@NonNull @NotNull ViewGroup parent, int viewType) {
return new Main59Adapter.MyViewHolder(LayoutInflater.from(context).inflate(R.layout.main59_item,parent,false));
}
@Override
public void onBindViewHolder(@NonNull @NotNull MyViewHolder holder, int position) {
holder.name.setText(dataSource.get(position).getName());
holder.number.setText(dataSource.get(position).getNumber());
}
@Override
public int getItemCount() {
return dataSource.size();
}
}
逻辑代码
MainActivity59
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import android.content.ContentResolver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.provider.ContactsContract;
import android.view.View;
import android.view.ViewGroup;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.List;
public class MainActivity59 extends AppCompatActivity {
/*
* ContentProvider
* 我们想在自己的应用中访问别的应用,或者说一些ContentProvider暴露给我们的一些数据, 比如手机联系人,短信等!我们想对这些数据进行读取或者修改,这就需要用到ContentProvider了
* 我们自己的应用,想把自己的一些数据暴露出来,给其他的应用进行读取或操作,我们也可以用 到ContentProvider,另外我们可以选择要暴露的数据,就避免了我们隐私数据的的泄露
* 并不仅仅可以查数据,根据权限 还能增删改数据
* */
RecyclerView recyclerView;
Cursor cursor;
List<Communication>communications=new ArrayList<>();
private Main59Adapter mAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main59);
//动态申请权限
getContacts();
recyclerView=findViewById(R.id.rv);
LinearLayoutManager linearLayoutManager=new LinearLayoutManager(this);
recyclerView.setLayoutManager(linearLayoutManager);
mAdapter=new Main59Adapter(this,recyclerView);
recyclerView.setAdapter(mAdapter);
mAdapter.setDataSource(communications);
}
//获取手机联系人
private void getContacts(){
//①查询raw_contacts表获得联系人的id
ContentResolver resolver = getContentResolver();
Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
//查询联系人数据
cursor = resolver.query(uri, null, null, null, null);
cursor.moveToFirst();
do
{
//获取联系人姓名,手机号码
String cName = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
String cNum = cursor.getString(cursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
communications.add(new Communication(cName,cNum));
}while (cursor.moveToNext());
cursor.close();
}
}
另外请注意在AndroidManifest.xml
添加权限:
<uses-permission android:name="android.permission.READ_CONTACTS" /> <!-- 手机联系人 -->
可以翻看资料进行静态或动态申请,也可以直接进行手机系统将手机通讯录权限给APP
这里给出一个例子:
点击按钮没有权限申请权限,有权限跳转通讯录界面,注意:这只是个例子需要你修改,
一般报错如下是这个原因:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mk.zhengtailai.PersonalBankManager/com.mk.zhengtailai.PersonalBankManager. TXLActivity}: java.lang.SecurityException: Permission Denial: opening provider com.android.providers.contacts. ContactsProvider2 from ProcessRecord{85e7d40 8538:com.mk.zhengtailai. PersonalBankManager/u0a124} (pid=8538, uid=10124) requires android.permission. READ_CONTACTS or android.permission.WRITE_CONTACTS
view.findViewById(R.id.button5).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(ContextCompat.checkSelfPermission(getContext(), Manifest.permission.READ_CONTACTS)
!= PackageManager.PERMISSION_GRANTED){
ActivityCompat.requestPermissions(getActivity(),new String[]{Manifest.permission.READ_CONTACTS},1);
}else {
Intent intent=new Intent(getContext(),TXLActivity.class);
startActivity(intent);
}
}
});
今天又写了一遍发现,手机没有通讯录的话会报错:
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.mk.zhengtailai.PersonalBankManager/com.mk.zhengtailai.PersonalBankManager. TXLActivity}: android.database.CursorIndexOutOfBoundsException: Index 0 requested, with a size of 0
所以我就随便加个try处理一下:
try {
Intent intent=new Intent(getContext(),TXLActivity.class);
startActivity(intent);
}catch (Exception e){
Toast.makeText(getContext(), "通讯录无联系人", Toast.LENGTH_SHORT).show();
}