一、读取通讯录联系人
public class ReadContacts extends AppCompatActivity implements View.OnClickListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_read_contacts);
findViewById(R.id.query).setOnClickListener(this);
}
@Override
public void onClick(View v) {
readContacts(getContentResolver());
}
@SuppressLint("Range")
private void readContacts(ContentResolver resolver) {
//先查询让raw_contacts表,再根据让raw_contacts_id查data表
Cursor cursor = resolver.query(ContactsContract.RawContacts.CONTENT_URI,new String[]{ContactsContract.RawContacts._ID},
null,null);
while(cursor.moveToNext()){
int rawContactId=cursor.getInt(0);
Uri uri = Uri.parse("content://com.android.contacts/contacts/"+rawContactId+"/data");
Cursor datacursor = resolver.query(uri,new String[]{Contacts.Data.MIMETYPE,Contacts.Data.DATA1,Contacts.Data.DATA2},
null,null);
Contact contact=new Contact();
while(datacursor.moveToNext()){
String data1=datacursor.getString(datacursor.getColumnIndex(Contacts.Data.DATA1));
String mimeType=datacursor.getString(datacursor.getColumnIndex(Contacts.Data.MIMETYPE));
Log.i("mimeType",mimeType);
switch (mimeType){
case CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE:
contact.name=data1;
break;
case CommonDataKinds.Phone.CONTENT_ITEM_TYPE:
contact.phone=data1;
break;
case CommonDataKinds.Email.CONTENT_ITEM_TYPE:
contact.email=data1;
break;
}
}
datacursor.close();;
if(contact.name!=null)
Log.i("联系人",contact.toString());
}
cursor.close();
}
class Contact{
String name; //姓名
String phone; //电话
String email; //邮箱
@Override
public String toString() {
return "Contact{" +
"姓名='" + name + '\'' +
", 电话='" + phone + '\'' +
", 邮箱='" + email + '\'' +
'}';
}
}
}
raw_contacts
表:
data表:
记录了用户的通讯录所有数据,包括手机号,显示名称等,但是里面的mimetype_id表示不同的数据类型,这与表mimetypes表中的id相对应,raw_contact_id 与下面的 raw_contacts表中的 id 相对应。
mimetypes表:
二、监听短信
ContentResolver获取数据采用的是主动查询方式,有查询就有数据,没查询就没数据。然而有时不但 要获取以往的数据,还要实时获取新增的数据,最常见的业务场景是短信验证码。电商App
经常在用户 注册或付款时发送验证码短信,为了替用户省事,App
通常会监控手机刚收到的短信验证码,并自动填 写验证码输入框。这时就用到了内容观察器ContentObserver
,事先给目标内容注册一个观察器,目标 内容的数据一旦发生变化,就马上触发观察器的监听事件,从而执行开发者预先定义的代码。
内容观察器的用法与内容提供器类似,也要从ContentObserver派生一个新的观察器,然后通过ContentResolver对象调用相应的方法注册或注销观察器。下面是内容解析器与内容观察器之间的交互方法说明。
- registerContentObserver:内容解析器要注册内容观察器。
- unregisterContentObserver:内容解析器要注销内容观察器。
- notifyChange:通知内容观察器发生了数据变化,此时会触发观察器的onChange方法。
public class MonitorSMS extends AppCompatActivity {
private TextView tv_text;
private SmsGetObserver smsGetObserver;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_monitor_sms);
tv_text = findViewById(R.id.tv_text);
// 给指定Uri注册内容观察器,一旦发生数据变化,就触发观察器的onChange方法
Uri uri= Uri.parse("content://sms");
// notifyForDescendents:
// false :表示精确匹配,即只匹配该Uri,true :表示可以同时匹配其派生的Uri
// 假设UriMatcher 里注册的Uri共有一下类型:
// 1.content://AUTHORITIES/table
// 2.content://AUTHORITIES/table/#
// 3.content://AUTHORITIES/table/subtable
// 假设我们当前需要观察的Uri为content://AUTHORITIES/student:
// 如果发生数据变化的 Uri 为 3。
// 当notifyForDescendents为false,那么该ContentObserver会监听不到,但是当notifyForDescendents 为ture,能捕捉该Uri的数据库变化。
smsGetObserver = new SmsGetObserver(this);
getContentResolver().registerContentObserver(uri,true, smsGetObserver);
}
@Override
protected void onDestroy() {
super.onDestroy();
getContentResolver().unregisterContentObserver(smsGetObserver);
}
class SmsGetObserver extends ContentObserver{
private final Context mContext;
public SmsGetObserver(Context context) {
super(new Handler(Looper.getMainLooper()));
this.mContext=context;
}
@SuppressLint("Range")
@Override
public void onChange(boolean selfChange,Uri uri) {
super.onChange(selfChange,uri);
// onChange会多次调用,收到一条短信会调用两次onChange
// mUri===content://sms/raw/20
// mUri===content://sms/inbox/20
// 安卓7.0以上系统,点击标记为已读,也会调用一次
// mUri===content://sms
// 收到一条短信都是uri后面都会有确定的一个数字,对应数据库的_id,比如上面的20
if(uri==null)
return;
//因为调用三次,那么我们排除两种情况,保留'content://sms/inbox/xxx'这种情况
if(uri.toString().contains("content://sms/raw")||
uri.toString().equals("content://sms"))
return;
// 通过内容解析器获取符合条件的结果集游标,时间戳降序获得最新的一条短信
Cursor cursor=mContext.getContentResolver().query(uri,new String[]{"address","body","date"},
null,null,"date DESC");
if(cursor.moveToNext()){
//发送人的号码
String sender=cursor.getString(cursor.getColumnIndex("address"));
//短信内容
String content=cursor.getString(cursor.getColumnIndex("body"));
//时间戳
String date=cursor.getString(cursor.getColumnIndex("date"));
tv_text.setText("发送人:"+sender+"\n内容:"+content+"\ndate:"+date);
}
cursor.close();
}
}
}