android菜鳥學習筆記23----ContentProvider(三)利用內建ContentProvider監聽簡訊及查看連絡人,contentprovider

來源:互聯網
上載者:User

android菜鳥學習筆記23----ContentProvider(三)利用內建ContentProvider監聽簡訊及查看連絡人,contentprovider

要使用一個ContentProvider,必須要知道的是它所能匹配的Uri及其資料存放區的表的結構。

首先想辦法找到訪問簡訊及連絡人資料的ContentProvider能接受的Uri:

到github上找對應ContentProvider的源碼:https://github.com/android

 

有好多個,哪一個才是簡訊資料的ContentProvider呢?

在filters輸入框:輸入telephony。

 

現在只有一個了,開啟:

 

裝有git的話,可以選擇clone到本地,沒有的話,就選擇下載zip包就行了。

 

進入src目錄中,SmsProvider.java就是簡訊資料的ContentProvider了。查看原始碼,搜尋UriMatcher:

 1 private static final UriMatcher sURLMatcher = 2  3             new UriMatcher(UriMatcher.NO_MATCH); 4  5   6  7     static { 8  9         sURLMatcher.addURI("sms", null, SMS_ALL);10 11         sURLMatcher.addURI("sms", "#", SMS_ALL_ID);12 13         sURLMatcher.addURI("sms", "inbox", SMS_INBOX);14 15         sURLMatcher.addURI("sms", "inbox/#", SMS_INBOX_ID);16 17         sURLMatcher.addURI("sms", "sent", SMS_SENT);18 19         sURLMatcher.addURI("sms", "sent/#", SMS_SENT_ID);20 21         sURLMatcher.addURI("sms", "draft", SMS_DRAFT);22 23         sURLMatcher.addURI("sms", "draft/#", SMS_DRAFT_ID);24 25         sURLMatcher.addURI("sms", "outbox", SMS_OUTBOX);26 27         sURLMatcher.addURI("sms", "outbox/#", SMS_OUTBOX_ID);

可以看到跟之前自己定義ContentProvider的類似的靜態代碼塊,其實是模仿它的源碼寫的。

從上面的addURI()方法,可以知道擷取全部簡訊資料的URI就是:”content://sms”

這樣,我們就可以訪問到所有的簡訊內容了。

為了有簡訊給我們看,需要在模擬器上收發下簡訊:

 

在window->show view->other->找到Emulator Control,類比110傳送簡訊:

hello, you are wanted.

在模擬器中可以回複簡訊,現在模擬器中,有如下三條簡訊:

 

查看簡訊代碼如下:

 1 protected void onCreate(Bundle savedInstanceState) { 2  3         super.onCreate(savedInstanceState); 4  5         setContentView(R.layout.main_layout); 6  7         Uri uri = Uri.parse("content://sms"); 8  9         Cursor cursor = getContentResolver().query(uri, null, null, null, null);10 11         if(cursor == null){12 13               return;14 15         }16 17         while(cursor.moveToNext()){18 19               Log.i(TAG,cursor.getString(cursor.getColumnIndex("body")));20 21         }22 23         Log.i(TAG,cursor.getCount()+"");24 25 }

要查看簡訊內容是需要許可權的:

在Manifest.xml聲明使用許可權:

<uses-permission android:name="android.permission.READ_SMS"/>

 

運行結果:

 

可見,取出了簡訊的總數及每條簡訊的內容。

但是,怎樣才能知道簡訊實際儲存呢?

可以在File Explorer中,找到/data/data/com.android.providers.telephony/databases/mmssms.db,該資料庫存放的就由簡訊的資料表,將其匯出到電腦,可以用Sqlite Expert查看sms表:

 

可知,address欄位為收件者或寄件者號碼,date為簡訊接收或發送的時間戳記,type是簡訊的類型,1表示接收的簡訊,2表示發送的簡訊,body是簡訊的內容,所以,我們就可以根據這些個欄位擷取我們比較關心的資訊了。

修改代碼如下:

 1 protected void onCreate(Bundle savedInstanceState) { 2  3         super.onCreate(savedInstanceState); 4  5         6  7         setContentView(R.layout.main_layout); 8  9         Uri uri = Uri.parse("content://sms");10 11         Cursor cursor = getContentResolver().query(uri, new String[]{"date","address","type","body"}, null, null, null);12 13         if(cursor == null){14 15           return;16 17         }18 19         while(cursor.moveToNext()){20 21           Log.i(TAG,DateFormat.format("yyyy-MM-dd hh:mm", cursor.getLong(0)).toString());22 23           Log.i(TAG,cursor.getInt(2) == 1 ? "收到":"發送給");24 25           Log.i(TAG,cursor.getString(1)+"的簡訊:");26 27           Log.i(TAG,cursor.getString(3));28 29         }30 31         Log.i(TAG,cursor.getCount()+"");32 33        34 35     }

運行結果:

 

可以利用前面學習的解析XML的內容,將簡訊備份到XML檔案中,這裡就不再贅述了。

下面簡單說明下使用ContentObserver監聽簡訊的方法:

建立自己的ContentObserver:

 1 class MyObserver extends ContentObserver{ 2  3   4  5         public MyObserver(Handler handler) { 6  7              super(handler); 8  9         }10 11  12 13         @Override14 15         public void onChange(boolean selfChange) {16 17              // TODO Auto-generated method stub18 19              Toast.makeText(MainActivity.this, "您有新的簡訊,請注意查收", Toast.LENGTH_SHORT).show();20 21         }22 23 }

在MainActivity註冊ContentObserver:

getContentResolver().registerContentObserver(uri, true, new MyObserver(new Handler()));

使用Emulator Controller向模擬器發送一條簡訊:

 

運行結果:

 

注意,在上面的uri後添加上inbox或者outbox可以觀察收件匣及寄件匣中的簡訊。在此,就不一一說明了。

 

查看連絡人資料的ContentProvider的源碼也可以從github上找到,在filters輸入框中輸入contacts即可:

開啟,然後clone或者打包下載到本地

在src目錄中找到:

ContactsProvider2.java,這個就是了。

搜尋addURI()方法,發現authority內容是:ContactsContract.AUTHORITY

在協助手冊中,尋找ContactsContract類,可以找到其中定義的常量AUTHORITY的值為:”com.android.contacts”

這樣一來,就可以構造uri了。

在File Exploer中查看有關連絡人資料的表結構:

為了讓表中有資料,先添加幾個連絡人。

找到/data/data/com.android.providers.contacts/databases/contacts2.db

匯出到電腦中,然後使用Sqlite Expert查看,發現有很多張表的。

 

重點關注raw_contacts、data、mimetypes這三張表。

新增連絡人...過程其實是先向raw_contacts添加一個id,然後把這個id連同該連絡人資料中的某項資料作為一條記錄插入到data表中,該連絡人資料有多少項資料,就在data表中插入多少條資料。

 

如,我在模擬器中添加了兩個連絡人,每個連絡人都添加了3項資料,分別為姓名、手機號和郵箱。則在raw_contacts中產生兩條記錄,id分別為1、2。然後在data表中產生了6條記錄,每個連絡人3條,都是在raw_contact_id和data1欄位存入我所添加的資料內容。

所以,我們要擷取連絡人資訊時,可以到data表中根據raw_contact_id分組進行擷取每個連絡人的所有資訊。

注意到data表中有個欄位名為mimetype_id存放的是每條記錄中data1的類型,如1表示郵箱,7表示姓名等,可以查看mimetypes表:

 

Uri raw_uri = Uri.parse("content://com.android.contacts/raw_contacts");

Uri data_uri = Uri.parse("content://com.android.contacts/data");

注意,在通過data_uri擷取資訊時,若指定要查詢的欄位mimetype_id,會發現,找不到該欄位。這是因為,這個ContentProvider內部幫我們做了表串連查詢,我們查看的實際上是串連查詢的視圖,裡面存放的是mimetype這個欄位,而不再有mimetype_id欄位。

修改MainActivity擷取連絡人資訊:

 1 Uri raw_uri = Uri.parse("content://com.android.contacts/raw_contacts"); 2 Uri data_uri = Uri.parse("content://com.android.contacts/data"); 3         Cursor raw_cursor = getContentResolver().query(raw_uri, new String[]{"_id"}, null, null, null); 4  5         6  7         if(raw_cursor == null){ 8  9               return ;10 11         }12 13         Log.i(TAG,raw_cursor.getCount()+"");14 15         while(raw_cursor.moveToNext()){16 17               String id = raw_cursor.getString(0);18 19               Cursor data_cursor = getContentResolver().query(data_uri, new String[]{"mimetype","data1"}, "raw_contact_id = ?", new String[]{id}, null);20 21               if(data_cursor == null){22 23                   return ;24 25             }26 27               Log.i(TAG,"連絡人"+id);28 29               while(data_cursor.moveToNext()){30 31                    String type = data_cursor.getString(0);32 33                    if(type.equals("vnd.android.cursor.item/name")){34 35                          Log.i(TAG,"姓名:"+data_cursor.getString(1));36 37                    }else if(type.equals("vnd.android.cursor.item/phone_v2")){38 39                          Log.i(TAG,"手機號:"+data_cursor.getString(1));40 41                    }else if(type.equals("vnd.android.cursor.item/email_v2")){42 43                          Log.i(TAG,"郵箱:"+data_cursor.getString(1));44 45                    }46 47               }48 49  }

讀取連絡人資訊是需要許可權的:

<uses-permission android:name="android.permission.READ_CONTACTS"/>

 

運行結果:

 

關於這兩個ContentProvider還有其他的增刪改操作這裡就不一一說明,跟自己定義的ContentProvider的用法基本相同,只要懂得原理,到每個具體的ContentProvider基本上都是大同小異了。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.