APP跨進程數據通信-訪問手機聯繫人

来源:http://www.cnblogs.com/joahyau/archive/2017/08/27/7440869.html
-Advertisement-
Play Games

1. 簡述 在實際開發中,常常需要進行不同應用程式之間的數據通信,例如讀取聯繫人列表等等,ContentProvider就是Android提供的用於實現不同進程之間進行數據通信的類。 ContentProvider的作用是對外提供對本應用的數據進行“增刪改查”的介面,而後在其它程式可通過Conten ...


1. 簡述

在實際開發中,常常需要進行不同應用程式之間的數據通信,例如讀取聯繫人列表等等,ContentProvider就是Android提供的用於實現不同進程之間進行數據通信的類。

ContentProvider的作用是對外提供對本應用的數據進行“增刪改查”的介面,而後在其它程式可通過ContentResolver類訪問提供的介面,從而實現跨應用數據通信。

2. ContentProvider類

首先,ContentProvider與其它幾個組件一樣也是一個抽象類,使用時必須實現一些方法,並且也需要在manifest中進行註冊。

另外,如果學過SQLite的操作,你會發現增刪改查幾個方法與SQLite資料庫的幾個操作方法極為相似。

註冊:

<provider
    android:name=".MyContentProvider"
    android:authorities="com.studying.myprovider"
    android:enabled="true"
    android:exported="true" />

PS:provider標簽寫在application中,與activity同級。

實現的方法:

boolean onCreate():在創建ContentProvider時會調用,在這裡完成一些初始化的操作,註意要返回true。

Uri insert(Uri uri, ContentValues values):添加方法。

關於Uri:參數中的uri是數據接收方指定哪一個ContentProvider的依據,格式為"content://authorities[/path]",authorities即manifest中註冊provider時的屬性,命名規則類似Java的包名,path則為路徑,可以沒有,例如"content://com.studying.myprovider"。(關於Uri的解析後面會介紹)

第二個參數values則是插入的值包,其中key值需與資料庫中的列名保持一致。另外,insert()方法的返回值為一個Uri,可以在傳入的Uri後加上成功插入的記錄的ID值作為返回的Uri,可用於判斷是否插入成功。添加ID與取出ID的方法為:

ContentUris.withAppendedId(Uri contentUri, long id)// 把id追加到contentUri後面
ContentUris.parseId(Uri uri)// 將id取出

int delete(Uri uri, String selection, String[] selectionArgs):selection為條件,selectionArgs為條件值,返回值為受操作影響的行數,例如刪除了1行,則返回1。

int update(Uri uri, ContentValues values, String selection, String[] selectionArgs):返回值同delete()方法。

Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder):projection為查詢的列,sortOrder為排序方法,query()方法返回一個Cursor對象。

String getType(Uri uri):返回數據的MIME類型,這個方法一般用不到,詳情可參考:ContentProvider資料庫共用之——MIME類型與getType()

3. ContentResolver類:

應用程式提供數據共用的介面時使用ContentProvider類,而需要訪問其它應用共用的數據時,則需要使用ContentResolver類。

獲取ContentResolver對象的方法:在Activity中直接getContentResolver()方法即返回一個ContentResolver對象。

使用方法非常簡單,調用ContentResolver對象中的insert()等方法會調用Uri匹配到的ContentProvider中的相應方法。

簡單例子:

ContentValues values = new ContentValues();
values.put("name", name);
values.put("age", age);
values.put("sex", sex);
Uri returnUri = resolver.insert(Uri.parse("content://com.studying.myprovider"), values);
long newItemId = ContentUris.parseId(returnUri);
Toast.makeText(this, "添加成功,新增加的學生ID為" + newItemId, Toast.LENGTH_SHORT).show();

4. URI的解析

URI即Uniform Resource Identifier 統一資源標識符,在這裡可以標識訪問哪一個ContentProvider,除此之外,還可以傳遞參數,以及通過匹配UriMatcher類制定的不同匹配規則進行相應處理。

(1)UriMatcher類:

UriMatcher類可以制定URI的匹配規則,然後可以通過在使用resolver對象時傳入不同格式的URI,使ContentProvider類做出不同的處理。

a)創建匹配規則:matcher.addURI(authorities, path, code),path為路徑,可使用#表示任意數字,*表示任意字元;code則為匹配碼。

b)在對應方法中匹配:int code = matcher.match(uri),返回的code即為匹配碼。

簡單例子:

首先在ContentProvider的onCreate()方法中制定規則:

matcher = new UriMatcher(UriMatcher.NO_MATCH);// 當所有匹配情況都無法匹配到時,則返回UriMatcher.NO_MATCH
matcher.addURI("com.studying.myprovider", "test1/#", 1001);
matcher.addURI("com.studying.myprovider", "test2/*", 1002);

然後在處理方法中做不同處理:

int columnCount = 0;
switch (matcher.match(uri)) {
    case 1001:
        Log.e("TAG", "匹配成功!匹配形式為:test1 + 任意數字");
        break;
    case 1002:
        Log.e("TAG", "匹配成功!匹配形式為:test2 + 任意字元串");
        break;
    default:
        columnCount = db.delete(TABLE_NAME, selection, selectionArgs);
        Log.e("TAG", "刪除成功!");
        break;
}

最後通過ContentResolver傳入需要的Uri進行使用:

ContentResolver resolver = getContentResolver();
resolver.delete(Uri.parse("content://com.studying.myprovider/test1/132"), null, null); // 匹配到1001
resolver.delete(Uri.parse("content://com.studying.myprovider/test2/1ac2"), null, null); // 匹配到1002
resolver.delete(Uri.parse("content://com.studying.myprovider/12"), null, null); // 匹配不到,則為UriMatcher.NO_MATCH

(2)Uri自帶解析方法

除了UriMatcher類,還可以通過Uri類自帶的解析方法進行傳值,傳遞參數的方法是:在Uri末尾加上“?”,而後後面加上參數,多個參數之間以“&”連接,例如"content://com.studying.myprovider?name=Tim&age=22"。

在Uri傳遞到ContentProvider之後,通過以下方法取出需要的部分:

uri.getAuthorities():獲取authorities部分。

uri.getPath():獲取path部分。

uri.getQuery():獲取“?”後面的全部字元串。

uri.getQueryParameter(parameterName):傳入相應參數名,獲取該參數值。例如String name = uri.getQueryParameter("name");

5. 訪問手機簡訊箱

訪問簡訊箱的方式非常簡單,跟上面例子的步驟基本一致,只需要額外到manifest中添加訪問短消息的許可權即可。

讀取許可權:android.permission.READ_SMS

寫入:android.permission.WRITE_SMS

Uri:

簡訊箱(全部短消息,包括發送的、接收的以及草稿):content://sms

收件箱:content://sms/inbox

發件箱:content://sms/sent

草稿箱:content://sms/draft

ContentResolver resolver = getContentResolver();
Uri smsUri = Uri.parse("content://sms/inbox");
Cursor c = resolver.query(smsUri, null, null, null, null);
while (c != null && c.moveToNext()) {
    // 3和13分別是號碼和短消息內容所在的列的索引
    Log.e("TAG", c.getString(3) + " " + c.getString(13));
}

6. 讀取聯繫人列表

與短消息不同,安卓中存儲聯繫人的方式相對比較複雜,聯繫人的姓名和號碼是分開存儲的。簡單地理解,可以想象成是資料庫的形式,姓名和號碼分別存放在兩張數據表中,而互相之間通過一個唯一的ID值進行標識。因此,讀取聯繫人需要先獲取姓名和ID,再通過ID去獲取號碼。

許可權:android.permission.READ_CONTACTS

姓名所在的ContentProvider的URI:ContactsContract.Contacts.CONTENT_URI

姓名列的列名常量:ContactsContract.Contacts.DISPALY_NAME

ID列的列名常量:ContactsContract.Contacts._ID (PS:切勿遺漏了下劃線)

號碼所在ContentProvider的URI:ContactsContract.CommonDataKinds.Phone.CONTENT_URI

號碼外鍵列的列名常量:ContactsContract.CommonDataKinds.Phone.CONTACT_ID

號碼列的列名常量:ContactsContract.CommonDataKinds.Phone.NUMBER

// 首先獲取姓名和ID
ContentResolver resolver = getContentResolver();
Cursor nameCursor = resolver.query(ContactsContract.Contacts.CONTENT_URI, null, null, null, null);
while (nameCursor != null && nameCursor.moveToNext()) {
    String name = nameCursor.getString(nameCursor.getColumnIndex(ContactsContract.Contacts.DISPLAY_NAME));
    String _id = nameCursor.getString(nameCursor.getColumnIndex(ContactsContract.Contacts._ID));

    // 再通過ID獲取相應的號碼
    String selections = ContactsContract.CommonDataKinds.Phone.CONTACT_ID + " = ?";
    Cursor numberCursor = resolver.query(ContactsContract.CommonDataKinds.Phone.CONTENT_URI, null, selections, new String[] {_id}, null);
    String result = "";
    while (numberCursor != null && numberCursor.moveToNext()) {
        String number = numberCursor.getString(numberCursor.getColumnIndex(ContactsContract.CommonDataKinds.Phone.NUMBER));
        result += name + " " + number + " ";
    }

    Log.e("RESULT", result);
}

7. 添加聯繫人

讀取聯繫人時需要分開讀取,那麼寫入當然也要分開寫入。首先向一個存儲了一些其它數據的ContentProvider中插入一個空數據,從而獲取到一個新的ID,再通過這個ID分別插入姓名和號碼(因為每次插入時都需要指定插入數據的類型,因此需要分開插入)。

許可權:android.permission.WRITE_CONTACTS

Uri

獲取ID的URI:ContactsContract.RawContacts.CONTENT_URI

插入數據的URI:ContactsContract.Data.CONTENT_URI

需要使用的常量

姓名的列名:ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME

ID的列名:ContactsContract.Data.RAW_CONTACT_ID

電話號碼的列名:ContactsContract.CommonDataKinds.Phone.NUMBER

指定MIME類型的列名:ContactsContract.Data.MIMETYPE

姓名的MIME類型:ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE

電話號碼的MIME類型:ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE

電話號碼類型的列名:ContactsContract.CommonDataKinds.Phone.TYPE

手機號碼:ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE

住宅號碼:ContactsContract.CommonDataKinds.Phone.TYPE_HOME

PS:常量非常多,要留意其所在的包,共用的一些常量位於ContactsContract.Data包下,例如ID、數據類型等,姓名相關的則在ContactsContract.CommonDataKinds.StructuredName包下,電話號碼相關的則在ContactsContract.CommonDataKinds.Phone包下,理清之後就容易記住了。

ContentResolver resolver = getContentResolver();

// 獲取一個新的ID
ContentValues values = new ContentValues();
Uri idUri = resolver.insert(ContactsContract.RawContacts.CONTENT_URI, values);
long id = ContentUris.parseId(idUri);

// 插入姓名
values.put(ContactsContract.Data.RAW_CONTACT_ID, id);
values.put(ContactsContract.CommonDataKinds.StructuredName.GIVEN_NAME, "Jay");
// 需要指定姓名的數據類型,也就是getType()方法將來返回的值
values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.StructuredName.CONTENT_ITEM_TYPE);
resolver.insert(ContactsContract.Data.CONTENT_URI, values);

// 插入號碼
values.clear();
values.put(ContactsContract.Data.RAW_CONTACT_ID, id);
values.put(ContactsContract.CommonDataKinds.Phone.NUMBER, "13511223344");
// 指定聯繫號碼的類型,如手機號碼、住宅號碼等
values.put(ContactsContract.CommonDataKinds.Phone.TYPE, ContactsContract.CommonDataKinds.Phone.TYPE_MOBILE);
values.put(ContactsContract.Data.MIMETYPE, ContactsContract.CommonDataKinds.Phone.CONTENT_ITEM_TYPE);
resolver.insert(ContactsContract.Data.CONTENT_URI, values);

您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 參考資料:https://github.com/sunyardTime/React-Native-CodeStyle 感謝情書哥無私奉獻 ##一、編程規約 ###(一) 命名規約 【強制】 代碼中命名均不能以下劃線或美元符號開始,也不能以下劃線或美元符號結束; 【強制】 代碼中命名嚴禁使用拼音與英文 ...
  • ...
  • Notification的幾種基本使用方法,大家肯定都已經爛熟於心,我也不必多說.給一個鏈接:https://zhuanlan.zhihu.com/p/25841482 接下來我想說的是android5.0 後的彈出通知, 網上的方法是: 但上面的做法並不能在android5.0以下的設備上使通知彈 ...
  • 因為項目中需要用到頭像上傳的功能,所以就下個Ddmo先來實現下。 demo我是類似仿微信的,在一個GridView中展示所有的圖片,其中第一個item可以去照相;獲取到圖片後再進行剪切。 圖片的剪切是從網上找的感覺不錯就用,暫時也沒有測試。 獲取圖片可以用:https://github.com/lo ...
  • 效果 源碼 https://github.com/YouXianMing/Animations 說明 1. TwoLevelLinkageView封裝了兩個tableView,左邊tableView中的cell以及右邊tableView中的cell以及header都可以定製 2. TwoLevelL ...
  • 利用SQLite在android上實現增刪改查 方法: 一、直接利用database.execSQL()方法輸入完整sql語句進行操作 這種方法適用於複雜的sql語句,比如多表查詢等等 這裡適合於增刪改,這個方法沒有返回值,而查需要返回數據,故不適用 增實例: database.execSQL("i ...
  • 轉載自:http://blog.csdn.net/bwf_erg/article/details/70858865 數組是由一組類型相同的元素構成的有序數據集合。數組中的集合元素是有 序的,而且可以重覆出現。 1 數組創建 在Swift語言中,數組的類型格式為: Array<ElementType> ...
  • 利用SQLite在android上創建資料庫 方法: 1、創建我們的資料庫類繼承SQLiteOpenHelper類 完成相關函數的重寫和資料庫對象的初始化 public MySQLiteOpenHelper(Context context,int version) super(context, "f ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...