Android高效入門-6.0聯絡人存取權限與ListView實作

作者 | 2016-05-25

Android 6.0(API Level 23)開始,應用程式的權限有新的機制,本篇以存取聯絡人Content Provider為例,說明如何在Android 6.0中向使用者要求權限,再取得手機中的聯絡人資料並顯示在ListView中。

專案準備

在認識6.0的危險權限後,以一個存取內容供應資料的範例應用程式,實際設計一個能夠存取聯絡人與手機圖檔的專案,專案名稱為「ContentApp」,如下:

A4551

再選擇「Empty Activity」建立空白活動,如下圖:

A4965

在此範例專案中,將進一步說明如何查詢、新增、修改聯絡人記錄等功能實作方法,包括權限、存取資料、使用者介面等都是針對Android 6.0環境所設計,開發出的APP也能在6.0以下執行,包括4.1、4.2、4.3、4.4、5.0與5.1。

準備測試資料

請先開啟Android內建的聯絡人APP,事先建立幾個測試用聯絡人,方法如下:

1.  開啟Contacts應用程式

A4554

2. 按下新增聯絡人快速功能鈕

A4555

若出現Google帳號登入時,請按下「返回」後,選擇將聯絡人儲存在本地-「KEEP LOCAL」,如下圖:

A4556

3. 輸入測試資料並儲存

A4557

繼續再輸入幾筆資料,請在其中一筆只輸入名稱而不輸入電話,如下四筆,其中Jack並無任何電話資料:

A4559

權限設定

在AndroidManifest.xml中加入讀與寫入聯絡人資料的權限(uses-permission元素),分別是READ_CONTACTS與WRITE_CONTACTS,如下圖:

A4553

本專案第一個功能打算在MainActivity第一個主畫面查詢所有手機中的聯絡人,並以ListView清單元件顯示,如下圖:

A4568

因為讀取、寫入聯絡人都是「危險權限」,如果只需要在Android 6.0前的版本執行,只需要在onCreate一開始就查詢內容供應的聯絡人,但要相容於Android 6.0則必須要先檢查權限,待使用者同意後,再執行查詢的程式碼。程式設計的步驟如下:

1. 檢查危險權限

請參考Android 6.0的Permission權限設計的方法,實作檢查聯絡人讀取與寫入權限,本段需要import的項目如下:

程式碼如下:

第2行,定義一個int常數,代表向使用者要求讀取聯絡人的辨識值。

第9-10行,檢查應用程式是否已向使用者要求讀取聯絡人權限。

第11行,判斷檢查後的結果permission值。

第12-15行,若尚未取得權限,則向使用者要求允許聯絡人讀取與寫入的權限,REQUEST_CONTACTS常數未宣告則請按下Alt+Enter自動定義常數值。

第17-18行,若已允許,則執行MainActivity中的readContacts()方法,可在該指令處按下「Alt+Enter」,選擇產生readContacts方法,如下圖。

A4564

執行到此段時,若使用者未允許權限,會出現如下圖的權限提示對話框(Android 6.0):

A4567

不論使用者選擇DENY(拒絕)或ALLOW(允許),都會自動執行MainActivity中的onRequestPermissionsResult方法。

2. 覆寫onRequestPermissionsResult方法

按下快速鍵「Alt+Insert」再選擇「Override Methods」,或直接按下「Ctrl+O」覆寫onRequestPermissionsResult方法,如下圖:

A4565

在覆寫後的onRequestPermissionsResult方法內設計當使用者回覆權限要求時的程式碼:

在方法中實作判斷使用者選擇,程式碼如下:

權限相關的程式碼實作完成後,將進入下一步,在readContacts方法進行查詢相關的程式設計。

查詢聯絡人

在自行設計的readContacts方法中先取得ContentResolver物件,如下:

查詢使用的是query方法,其規格如下:

本例目的是查詢所有聯絡人資料,使用以下程式碼:

query方法的參數較多,依序說明如下:

  1. uri: 欲查詢的URI

欲查詢內容提供資料的Uri物件,即是合約類別下的CONTENT_URI,本例為:

android.provider.ContactsContract.Contacts.CONTENT_URI

  1. projection: 查詢回傳的表格欄位

回傳該表格內的欄位,資料型態為字串陣列,欄位可從合約類別中取得,本例為null,代表回傳所有欄位。

  1. selection: SQL語法的where

查詢的條件,資料型態為字串,也就是一般SQL的WHERE語法,唯不需要包含「WHERE」字串,直接使用將WHERE之後的語法放在字串中即可,例如"_ID=4"。如果是動態資料的查詢,可在selection條件字串中使用問號,待下一個參數提供問號中的值,如”_ID=?”。本例為null,代表表格中的所有筆數。

  1. selectionArgs: 當where中有參數時,參數放在此

資料型態為字串陣列,若上一個條件selection字串中有問號時,則由本參數提供值,依問號出現的數量與順序提供對應的值,本例為null,代表不需要提供條件的值。

  1. sortOrder: ASC或DESC

查詢結果排序字串,格式為:

欄位名稱 ASC|DESC

預設為”ASC”,資料由小到大,可設為”DESC”,資料則由大到小排序。

Cursor介面

上述程式碼呼叫query方法後得到查詢結果,查詢的結果回傳的是android.database.Cursor介面,它是一個抽象的資訊記錄的指標,初始會停留在第一筆資訊之前,此時並未指向任一筆資料,如下圖:

A4561

呼叫Cursor的moveToNext()方法,可將Cursor向下移動一筆,若有資料則回傳true,若無資料則回傳false,代表無任何資料。

因此,使用while迴圈設計一一拜訪所有的筆數,如下:

在while迴圈中,代表Cursor移動到某一筆資料上,可以利用Cursor的getString、getInt、getFloat等方法取得該筆資料的欄位值,如果欄位為VARCHAR、TEXT等文字資料,可使用getString()方法,若是INTEGER等整數型態,可使用getInt取得欄位的int值。

但是getXX方法都需要int整數型態的參數,代表的是該欄位在查詢結果中的索引值,稱為「Column Index」如下圖:

A4563

想得到欄位在查詢結果中的索引值,可呼叫Cursor的getColumnIndex(String name)方法,提供欄位名稱參數,即可取得該欄位的索引值,而欄位名稱請利用合約類別下所定義的字串常數取得,以下程式碼為取得資料ID的方式:

請利用以上方式在while迴圈中取得每一筆聯絡人的序號(_ID)與顯示名稱(DISPLAY_NAME),並使用Log除錯訊息,程式碼如下:

整個readContacts方法的完整程式碼如下:

第2行,取得ContentResolver物件。

第3-8行,查詢手機中的所有聯絡人,並得到cursor物件。

第9-16行,使用while迴圈依次處理查詢結果的每一筆資料,並以Log除錯訊息印出聯絡人的ID與顯示名稱。

執行結果可在LogCat中找到:

最後的while迴圈事實上只適合開發時的除錯用,仍需要一個元件展示查詢的結果,如ListView清單元件。

顯示聯絡人清單

在認識Cursor與查詢結果的處理之後,使用Cursor查詢的結果,將聯絡人名稱以ListView方式展示,步驟如下:

1. 準備畫面元件

請打開res/layout/activity_main.xml版面配置檔,並加入ListView元件,id值為list,如下:

2. 產生Adapter並設定

先將先前練習的while迴圈區塊整個註解,因為清單元件的資料來源是查詢結果Cursor物件,因此使用SimpleCursorAdapter,因為它是將資料庫查詢的結果顯示在ListView的每一列上,需要以下參數:

  1. Context context

需要Context物入,使用MainActivity,也就是this。

  1. int layout

每一列的版面配置檔的資源ID,可使用Android SDK內建的(android.R.layout.*)或自行設計(R.layout.*)。

  1. Cursor cursor

查詢內容提供者聯絡人所得到的Cursor物件。

  1. String[] from

資料查詢結果Cursor中想要顯示的欄位名稱,以字串陣列型態建立。

  1. int[] to

資料顯示的元件ID陣列,此處的ID值都應在第二個layout參數版面配置檔中找到。

  1. int flag

程式碼如下:

第1行,取得版面中的ListView元件。

第2-8行,使用cursor物件產生SimpleCursorAdapter物件,提供單列版面配置檔、cursor、資料來源欄位陣列、與其對應的顯示元件陣列。

第9行,將adapter物件設定至ListView元件list。

執行結果,顯示每一筆聯絡人的名稱,如下圖:

A4568

下一篇文章將聊到如何同時顯示聯絡人名稱與電話、使用Implcit Join、客製化SimpeCursorAdatper的顯示結果。

相關文章:

使用Facebook直接回應

發表迴響

你的電子郵件位址並不會被公開。 必要欄位標記為 *