
上一篇文章Android ContentProvider(一)初步介紹了ContentProvider的用法,這篇就通過(guò)獲取系統(tǒng)聯(lián)系人來(lái)了解ContentProvider的具體使用方法。
創(chuàng)建ContactsTest項(xiàng)目
因?yàn)槟M器中并沒(méi)有聯(lián)系人,所以需要給模擬器添加幾個(gè)聯(lián)系人數(shù)據(jù),然后開(kāi)始創(chuàng)建ContactsTest項(xiàng)目。項(xiàng)目已上傳Github
項(xiàng)目布局只有一個(gè)ListView,代碼就不用貼出來(lái)了。主要還是看MainActivity的代碼。
public class MainActivity extends AppCompatActivity {
ListView contactsView;
ArrayAdapter<String> adapter;
List<String> contactsList = new ArrayList<String>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
contactsView = (ListView) findViewById(R.id.contacts_view);
getContacts();
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, contactsList);
contactsView.setAdapter(adapter);
}
private void getContacts() {
Cursor cursor = null;
//查詢(xún)聯(lián)系人數(shù)據(jù)
cursor = getContentResolver().query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, null, null, null);
if (cursor != null) {
while (cursor.moveToNext()) {
//獲取聯(lián)系人姓名
String displayName = cursor.getString(cursor.getColumnIndex(
ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME));
//獲取聯(lián)系人手機(jī)號(hào)
String number = cursor.getString(cursor.getColumnIndex(
ContactsContract.CommonDataKinds.Phone.NUMBER));
contactsList.add(displayName + "\n" + number);
}
cursor.close();
}
}
}
onCreate()方法中,首先獲取了ListView控件,然后調(diào)用getContacts()方法獲取聯(lián)系人數(shù)據(jù),然后再給ListView設(shè)置Adapter。主要看一下getContacts()方法,可以看到,這里使用了ContentResolver的query()方法來(lái)查詢(xún)系統(tǒng)的聯(lián)系人數(shù)據(jù)。不過(guò)傳入的Uri并沒(méi)有調(diào)用Uri.parse()方法去解析一個(gè)內(nèi)容URI字符串,這是因?yàn)镃ontactsContract.CommonDataKinds.Phone類(lèi)已經(jīng)幫我們做好了封裝,提供了一個(gè)CONTENT_URI常量,而這個(gè)常量就是使用Uri.parse()方法解析出來(lái)的結(jié)果。接著對(duì)Cursor對(duì)象進(jìn)行遍歷,將聯(lián)系人姓名和手機(jī)號(hào)這些數(shù)據(jù)逐個(gè)取出,聯(lián)系人姓名這一列對(duì)應(yīng)的常量是ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME,聯(lián)系人手機(jī)號(hào)這一列對(duì)應(yīng)的常量是ContactsContract.CommonDataKinds.Phone.NUMBER。兩個(gè)數(shù)據(jù)都取出之后,將它們進(jìn)行拼接,并且中間加上換行符,然后將拼接后的數(shù)據(jù)添加到ListView里。然后不要忘記將Cursor對(duì)象關(guān)閉掉。
最后不要忘了在AndroidManifest.xml添加權(quán)限
<uses-permission android:name="android.permission.READ_CONTACTS"/>
運(yùn)行ContactsTest
運(yùn)行在Android 5.0的效果如下,與預(yù)期的效果一樣。

運(yùn)行在Android 6.0之后的版本就會(huì)報(bào)錯(cuò)

后來(lái)通過(guò)查詢(xún)了解到Android M開(kāi)始就增加了運(yùn)行時(shí)權(quán)限Runtime Permission,不清楚的話(huà)可以到Android官方培訓(xùn)課程(需要文明上網(wǎng)) 學(xué)習(xí)。了解到問(wèn)題所在之后就要開(kāi)始解決問(wèn)題。
解決問(wèn)題
- 修改代碼
public class MainActivity extends AppCompatActivity {
private static final int PERMISSIONS_REQUEST_READ_CONTACTS = 100;
……
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
contactsView = (ListView) findViewById(R.id.contacts_view);
showContacts();
}
private void showContacts() {
// 檢查SDK版本并判斷權(quán)限是否授權(quán)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M
&& checkSelfPermission(Manifest.permission.READ_CONTACTS) !=
PackageManager.PERMISSION_GRANTED) {
//請(qǐng)求權(quán)限,之后會(huì)回調(diào)onRequestPermissionsResult()
requestPermissions(new String[]{Manifest.permission.READ_CONTACTS}, PERMISSIONS_REQUEST_READ_CONTACTS);
} else {
//Android版本小于6.0或者已經(jīng)授權(quán)
getContacts();
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, contactsList);
contactsView.setAdapter(adapter);
}
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
if(requestCode == PERMISSIONS_REQUEST_READ_CONTACTS){
if (grantResults[0] == PackageManager.PERMISSION_GRANTED){
//權(quán)限同意授權(quán),然后重新調(diào)用showContacts()
showContacts();
}else{
//不同意授權(quán),用Toast提示用戶(hù)
Toast.makeText(this,"Until you grant the permission, we canot display the contacts", Toast.LENGTH_SHORT).show();
}
}
}
private void getContacts() {
……
}
}
代碼相同的部分用……表示,這里主要看一下showContacts()方法,首先判斷Android版本與權(quán)限是否授權(quán),如果是Android M之后的版本并且還沒(méi)有授權(quán)相應(yīng)的權(quán)限就會(huì)調(diào)用requestPermissions()請(qǐng)求權(quán)限授權(quán),然后回調(diào)onRequestPermissionsResult()通過(guò)requestCode監(jiān)聽(tīng)相應(yīng)權(quán)限的授權(quán)狀態(tài),再作相應(yīng)的處理。
- 重新運(yùn)行程序

修改代碼之后Android 6.0也可以運(yùn)行了,并且可以從圖中看出同意與不同意授權(quán)的區(qū)別。
這篇文章就到這里,關(guān)于Android M的權(quán)限問(wèn)題也可以看一下微信公眾號(hào)的這篇文章Android 6.0權(quán)限適配,比你想的還要簡(jiǎn)單(實(shí)踐篇)
如果文章對(duì)你有所幫助,那么請(qǐng)您點(diǎn)一下?
由于本人水平有限,如有錯(cuò)誤,歡迎大家指正。如果你在操作過(guò)程中發(fā)現(xiàn)一些沒(méi)有講到的錯(cuò)誤或者問(wèn)題,歡迎在評(píng)論留言,一起探討,共同學(xué)習(xí)進(jìn)步!