Android ContentProvider(二)

上一篇文章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ù)期的效果一樣。


Android 5.0

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

部分log

后來(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

修改代碼之后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)步!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容