利用ContentProvider讀取系統應用的資訊(簡訊和聯絡人)
阿新 • • 發佈:2018-12-17
上面兩篇我們講了ContentProvider如何使用
Android進階:步驟2:ContentProvider初體驗
Content Provider 解析URI的方法 UriMatcher的用法和自帶的解析方法
1.現在我們將如何通過某一個應用讀系統短訊息
系統簡訊箱的Uri分成以下幾個部分
- content://sms 簡訊箱
- content://sms/inbox 收信箱
- content://sms/sent 發信箱
- content://sms/draft 草稿箱
可以跟你你想要拿的信箱加以區分
讀取信箱分成以下三個步驟:
在內容處理者(ContentResolver)中處理
1.配置檔案中新增讀寫信箱的許可權,和android6.0後動態申請許可權
2.獲取內容處理者物件
3.查詢方法返回Cursor物件
4.解析Cursor
程式碼:
AndroidManifest.xml中新增讀資訊的許可權
<uses-permission android:name="android.permission.READ_SMS"/>
android6.0後要動態申請許可權
MainActivity.java
public class MainActivity extends AppCompatActivity { private ContentResolver contentResolver; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //1.申請許可權 在配置檔案中寫還有動態申請 checkPermission(this); //2拿的內容處理者物件 contentResolver = getContentResolver(); findViewById(R.id.sms_btn).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { //拿的發信箱的uri Uri uri = Uri.parse("content://sms/sent"); //引數1:uri //引數2:查詢指定列範圍,null為查詢所有 //引數3:查詢條件,不指定 //引數4:查詢條件陣列,和引數2搭配使用,不指定 //引數5:排序 Cursor c = contentResolver.query(uri, null, null, null, null); //3.解析Uri //遍歷Cursor while (c.moveToNext()) { String msg = ""; // //顯示每條發信箱的內容 // //遍歷該行的列 // for(int i=0;i<c.getColumnCount();i++){ // msg+=c.getString(i)+" "; // } //如果只有拿接收者號碼和資訊內容 //系統指定的列名分別為 address body String address = c.getString(c.getColumnIndex("address")); String body = c.getString(c.getColumnIndex("body")); msg = address + " " + body; Log.e("TAG", "msg=" + msg); } } }); } //android6.0之後要動態獲取許可權 private void checkPermission(Activity activity) { // Storage Permissions final int REQUEST_EXTERNAL_STORAGE = 1; String[] PERMISSIONS_STORAGE = { Manifest.permission.READ_SMS, }; try { //檢測是否有讀簡訊箱的許可權 int permission = ActivityCompat.checkSelfPermission(MainActivity.this, "android.permission.READ_SMS"); if (permission != PackageManager.PERMISSION_GRANTED) { // 沒有讀簡訊箱的許可權,去申請寫的許可權,會彈出對話方塊 ActivityCompat.requestPermissions(MainActivity.this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE); } } catch (Exception e) { e.printStackTrace(); } } }
Log列印結果:
這是我發信箱的簡訊
拿到的簡訊:
E/TAG: msg=95559 66666
msg=10086 ???
2.讀取聯絡人
讀取聯絡人和讀取簡訊的類似
但稍微有點複雜,因為聯絡人的姓名和電話號碼是放在不同的兩個表的,需要進行兩次查詢
聯絡人姓名是主表,id是主鍵,電話號碼所在的表是從表,可以通過主表的id主鍵來查到對應從表的電話號碼
步驟:
1.新增許可權
2.查詢操作,返回Cursor
3.解析Cursor
程式碼:
1.新增許可權
<uses-permission android:name="android.permission.READ_CONTACTS"/>
6.0後動態申請許可權寫在一起了後面就不寫了
//android6.0之後要動態獲取許可權
private void checkPermission(Activity activity) {
// Storage Permissions
final int REQUEST_EXTERNAL_STORAGE = 1;
String[] PERMISSIONS_STORAGE = {
Manifest.permission.READ_SMS,
Manifest.permission.READ_CONTACTS,
Manifest.permission.WRITE_CONTACTS
};
try {
//檢測是否有讀簡訊箱的許可權
int permission = ActivityCompat.checkSelfPermission(MainActivity.this,
"android.permission.READ_SMS");
//檢查是否有讀聯絡人的許可權
int permission2 = ActivityCompat.checkSelfPermission(MainActivity.this,
"android.permission.READ_CONTACTS");
//檢查是否有寫聯絡人的許可權
int permission3 = ActivityCompat.checkSelfPermission(MainActivity.this,
"android.permission.WRITE_CONTACTS");
if (permission != PackageManager.PERMISSION_GRANTED ||
permission2!= PackageManager.PERMISSION_GRANTED ||
permission3 != PackageManager.PERMISSION_GRANTED) {
// 沒有某一個許可權,去申請相應許可權,會彈出對話方塊
ActivityCompat.requestPermissions(MainActivity.this, PERMISSIONS_STORAGE, REQUEST_EXTERNAL_STORAGE);
}
} catch (Exception e) {
e.printStackTrace();
}
}
findViewById(R.id.read_contact_btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//對應聯絡人而言,他們的儲存方式是將姓名和其他內容(電話號碼)由不同的ContentProvider操作的
//首先想象聯絡人和其他內容屬於不同的表
//而姓名所在的表示主表,其他內容位於從表
//而主表的主鍵id在從表中作為外來鍵使用
//1.查姓名的uri
Uri uri1 = ContactsContract.Contacts.CONTENT_URI;
Cursor c1 = contentResolver.query(uri1, null, null, null, null);
while (c1.moveToNext()) {
//姓名的列
// ContactsContract.Contacts.DISPLAY_NAME;
// //主鍵id的列
// ContactsContract.Contacts._ID;
//同樣可以遍歷所有列,但這裡只要看姓名和電話
String name = c1.getString(c1.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
String id = c1.getString(c1.getColumnIndex(ContactsContract.Contacts._ID));
//繼續訪問下一個Uri拿到對應從表的電話號碼
//2.查詢電話的Uri
Uri uri2 = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
//在從表外來鍵id的查詢條件
String selection = ContactsContract.CommonDataKinds.Phone.CONTACT_ID + "=?";
//通過這個外來鍵找到相應的電話號碼
Cursor c2 = contentResolver.query(uri2,
null,
selection,//查詢條件
new String[]{id},//查詢條件的值
null);
//每一id(一個人)都可以有多個電話號碼
//還有要將每個電話號碼拿出來
while (c2.moveToNext()) {
//取出電話號碼的列
String number = c2.getString(c2.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
name += " 電話:" + number;
}
Log.e("TAG", "姓名是:" + name + " id是:" + id);
}
}
});
輸出結果:
E/TAG: 姓名是:Cmcc 電話:1 387-891-2345 id是:1
E/TAG: 姓名是:Love 電話:1 827-891-2345 電話:1 527-891-2345 id是:2
如果僅僅查詢某個人的電話
更改一個查詢的語句,新增上查詢條件
Cursor c1 = contentResolver.query(
uri1,
null,
ContactsContract.Contacts.DISPLAY_NAME+"=?",//查詢條件
new String[]{"Love"},//查詢條件值陣列
null);
就會只顯示Love的電話
E/TAG: 姓名是:Love 電話:1 827-891-2345 電話:1 527-891-2345 id是:2
3.新增聯絡人
上面許可權的就不寫了,在上一個獲取聯絡人
findViewById(R.id.add_contact_btn).setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
//1.往一個ContentProvider中插入一條空資料,獲取新的id
//2.利用剛剛生成的id分別組合姓名和電話號碼往另一個ContentProvider插入資料
ContentValues values=new ContentValues();
//拿到插入空資料的uri
Uri uri=ContactsContract.RawContacts.CONTENT_URI;
//返回的uri後面追加有id
Uri returnUri=contentResolver.insert(uri,values);
//獲取這個id
long id= ContentUris.parseId(returnUri);
//插入姓名
//獲取插入姓名的Uri
Uri nameUri=ContactsContract.Data.CONTENT_URI;
//放姓名的列名
values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME,"新聯絡人");
//放id的列名
values.put(ContactsContract.Data.RAW_CONTACT_ID,id);
//指定新增的新增的資料型別(在ContentProvider 有一個獲取型別的方法)
values.put(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
contentResolver.insert(nameUri,values);
//插入電話號碼
//先清空之前的資料
values.clear();
//插電話號碼
values.put(ContactsContract.CommonDataKinds.Phone.NUMBER,"13878999999");
//放id的列名
values.put(ContactsContract.Data.RAW_CONTACT_ID,id);
//指定資料型別
values.put(ContactsContract.Data.MIMETYPE,
ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
//對於電話號碼,可能是手機號或者是座機號碼
//所以要指定電話號碼的型別是行動電話
values.put(ContactsContract.CommonDataKinds.Phone.TYPE,ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE);
contentResolver.insert(ContactsContract.Data.CONTENT_URI,values);
}
});
效果演示