Android_通過ContentObserver監聽簡訊資料變化,contentobserver

來源:互聯網
上載者:User

Android_通過ContentObserver監聽簡訊資料變化,contentobserver
1.簡介

在小米等一些機型,無法接收系統發出的簡訊廣播。只能通過觀察者ContentObserver,去監聽簡訊資料的變化

2.SMS資料介紹

content://sms/inbox        收件匣 
content://sms/sent        已發送 
content://sms/draft        草稿 
content://sms/outbox        寄件匣 
content://sms/failed        發送失敗 
content://sms/queued        待發送列表

在模擬器上Outbox沒有查詢到資料,在模擬器上找了老半天也沒找到寄件匣,很鬱悶。    
資料庫中sms相關的欄位如下:    
_id               一個自增欄位,從1開始 
thread_id    序號,同一發信人的id相同 
address      寄件者手機號碼 
person        連絡人清單裡的序號,陌生人為null 
date            發件日期 
protocol      協議,分為: 0 SMS_RPOTO, 1 MMS_PROTO  
read           是否閱讀 0未讀, 1已讀  
status         狀態 -1接收,0 complete, 64 pending, 128 failed 
type 
    ALL    = 0; 
    INBOX  = 1; 
    SENT   = 2; 
    DRAFT  = 3; 
    OUTBOX = 4; 
    FAILED = 5; 
    QUEUED = 6; 
body                     簡訊內容 
service_center     簡訊服務中心號碼編號 
subject                  簡訊的主題 
reply_path_present     TP-Reply-Path 
locked

檢索資料方法很簡單:  
Uri uri = Uri.parse("content://sms/inbox");         
Cursor cur = this.managedQuery(uri, null, null, null, null);         
if (cur.moveToFirst()) {         
    do{     
    for(int j = 0; j < cur.getColumnCount(); j++){     
            info = "name:" + cur.getColumnName(j) + "=" + cur.getString(j); 
            Log.i("====>", info); 
        } 
    }while(cur.moveToNext());      
}

managedQuery最終也要將參數轉換為SQL語句向SQLite發送訊息,因此參數跟SQL語句很類似,所以可以在查詢欄位中加入SQL函數,
比如new String[] projection = new String[]{"count(*) as count"}等等。       
managedQuery中的參數依次為uri,        
查詢欄位          查詢欄位數組,也可以將所有需要查詢的欄位放入一個字元內    
                      比如new projection[]{"_id", "thread_id"}和new projection[]{"_id,thread_id"}是一致的。    
                      跟SQL一樣,欄位名不區分大小寫    
條件                不帶Where的SQL 條件字元,如果有參數則用?替代,比如"_id=? And thread_id = ? Or type = '1'"    
條件中的參數   參數字元數組,跟上述的條件一一對應    
排序                不帶Order by排序字串,比如_id desc, type    
如果參數為null,SQL中查詢欄位為“*”,相關的條件為空白

還可以用getContentResolver()獲得一個ContentResolver,    
getContentResolver().query()同樣返回一個Cursor對象,參數跟managedQuery一致。    
不過用ContentResolver對象去更新、刪除和插入一條資料時報SecurityException。看來沒有許可權,在Manifest.xml中加入許可權: 
<uses-permission android:name="android.permission.WRITE_SMS"></uses-permission> 
然後刪除簡訊: 
this.getContentResolver().delete(Uri.parse("content://sms"), "_id=?", new String[]{"3"}); 
刪除成功。
Url中content://sms 替換成content://sms/ 也成功,但是其它url時程式報錯,比如content://sms/inbox

看了一下android的原始碼,sms支援的協議有:
sURLMatcher.addURI("sms", null, SMS_ALL); 
sURLMatcher.addURI("sms", "#", SMS_ALL_ID); 
sURLMatcher.addURI("sms", "inbox", SMS_INBOX); 
sURLMatcher.addURI("sms", "inbox/#", SMS_INBOX_ID); 
sURLMatcher.addURI("sms", "sent", SMS_SENT); 
sURLMatcher.addURI("sms", "sent/#", SMS_SENT_ID); 
sURLMatcher.addURI("sms", "draft", SMS_DRAFT); 
sURLMatcher.addURI("sms", "draft/#", SMS_DRAFT_ID); 
sURLMatcher.addURI("sms", "outbox", SMS_OUTBOX); 
sURLMatcher.addURI("sms", "outbox/#", SMS_OUTBOX_ID); 
sURLMatcher.addURI("sms", "undelivered", SMS_UNDELIVERED); 
sURLMatcher.addURI("sms", "failed", SMS_FAILED); 
sURLMatcher.addURI("sms", "failed/#", SMS_FAILED_ID); 
sURLMatcher.addURI("sms", "queued", SMS_QUEUED); 
sURLMatcher.addURI("sms", "conversations", SMS_CONVERSATIONS); 
sURLMatcher.addURI("sms", "conversations/*", SMS_CONVERSATIONS_ID); 
sURLMatcher.addURI("sms", "raw", SMS_RAW_MESSAGE); 
sURLMatcher.addURI("sms", "attachments", SMS_ATTACHMENT); 
sURLMatcher.addURI("sms", "attachments/#", SMS_ATTACHMENT_ID); 
sURLMatcher.addURI("sms", "threadID", SMS_NEW_THREAD_ID); 
sURLMatcher.addURI("sms", "threadID/*", SMS_QUERY_THREAD_ID); 
sURLMatcher.addURI("sms", "status/#", SMS_STATUS_ID); 
sURLMatcher.addURI("sms", "sr_pending", SMS_STATUS_PENDING); 
sURLMatcher.addURI("sms", "sim", SMS_ALL_SIM); 
sURLMatcher.addURI("sms", "sim/#", SMS_SIM);

其中,delete方法中支援的協議為:
SMS_ALL               根據參數中的條件刪除sms表資料 
SMS_ALL_ID         根據_id刪除sms表資料 
SMS_CONVERSATIONS_ID     根據thread_id刪除sms表資料,可以帶其它條件 
SMS_RAW_MESSAGE              根據參數中的條件刪除 raw表 
SMS_STATUS_PENDING         根據參數中的條件刪除 sr_pending表 
SMS_SIM                                 從Sim卡上刪除資料

試一下SMS_CONVERSATIONS_ID:"content://sms/conversations/3 ",刪除thread_id="3", _id="5"的資料        
在eclipse中的Emulator Control中,以13800給模擬器發送三條資料,然後以13900發送一條        
this.getContentResolver().delete(Uri.parse("content://sms/conversations/3"), "_id=?", new String[]{"5"});  
成功刪除一條資料。   
在資料庫中每個寄件者的thread_id雖然一樣,但不是固定的,如果把一個寄件者的全部資料刪除掉,        
然後換一個新號碼傳送簡訊時,thread_id是以資料庫中最大的id+1賦值的。   

update支援的協議有很多:
SMS_RAW_MESSAGE    
SMS_STATUS_PENDING    
SMS_ALL    
SMS_FAILED    
SMS_QUEUED    
SMS_INBOX    
SMS_SENT    
SMS_DRAFT    
SMS_OUTBOX    
SMS_CONVERSATIONS    
SMS_ALL_ID    
SMS_INBOX_ID    
SMS_FAILED_ID    
SMS_SENT_ID    
SMS_DRAFT_ID    
SMS_OUTBOX_ID    
SMS_CONVERSATIONS_ID    
SMS_STATUS_ID

以SMS_INBOX_ID測試一下:    
ContentValues cv = new ContentValues();    
cv.put("thread_id", "2");    
cv.put("address", "00000");    
cv.put("person", "11");    
cv.put("date", "11111111");    
this.getContentResolver().update(Uri.parse("content://sms/inbox/4"), cv, null, null);    
太強了,連thread_id都可以修改。   

insert支援的協議:
SMS_ALL    
SMS_INBOX    
SMS_FAILED    
SMS_QUEUED    
SMS_SENT    
SMS_DRAFT    
SMS_OUTBOX    
SMS_RAW_MESSAGE    
SMS_STATUS_PENDING    
SMS_ATTACHMENT    
SMS_NEW_THREAD_ID 

向sms表插入資料時,type是根據協議來自動化佈建,    
如果傳入的資料中沒有設定date時,自動化佈建為當前系統時間;非SMS_INBOX協議時,read標誌設定為1    
SMS_INBOX協議時,系統會自動查詢並設定PERSON    
threadId為null或者0時,系統也會自動化佈建   

一直為造不了"發送失敗"的郵件而發愁,現在來做一個:    
content://sms/failed   
ContentValues cv = new ContentValues();    
cv.put("_id", "99");    
cv.put("thread_id", "0");    
cv.put("address", "9999");    
cv.put("person", "888");    
cv.put("date", "9999"); 
cv.put("protocol", "0"); 
cv.put("read", "1"); 
cv.put("status", "-1"); 
//cv.put("type", "0"); 
cv.put("body", "@@@@@@@@@"); 
this.getContentResolver().insert(Uri.parse("content://sms/failed"), cv); 
type被設定成了5,thread_id設定為1

看看能不能再挖掘一下sms的功能。先來做一個錯誤的查詢:
getContentResolver().query( Uri.parse("content://sms/") , new String[]{"a"}, "b", null, null);
log輸出錯誤的SQL語句:
SELECT a FROM sms WHERE (b) ORDER BY date DESC
query方法中沒有Group by,如果想對簡訊做統計,對Cursor進行遍曆再統計也太慢了。
在SQL語言中group by在Where後面,那就在條件參數中想想辦法:
Android組織SQL語句時將條件兩端加(),那就拼一個group by出來吧:
getContentResolver().query( Uri.parse("content://sms/") , new String[]{"count(*) as count, thread_id"}, "1=1) group by (thread_id", null, null);
那麼輸出的SQL= SELECT count(*) as count, thread_id FROM sms WHERE ( 1=1) group by (thread_id ) ORDER BY date DESC
如果想查詢URI沒有對應的表怎麼辦呢,比如想知道 mmssms.db資料庫中有哪些表,
查詢的表是URI定的,再在條件參數中拼湊肯定是不行。
那我們把目光往前移,看看在欄位參數中能不能湊出來。
要查詢其它表,關鍵要去掉系統固定添加的FROM sms,
用用SQL中的注釋吧,
getContentResolver().query(Uri.parse("content://sms/"), new String[]{" * from sqlite_master WHERE type = 'table' -- "}, null, null, null);
那麼輸出的SQL=SELECT * from sqlite_master WHERE type = 'table' -- FROM sms ORDER BY date DESC 居然能夠運行。
得寸進尺,再進一步,如果加入“;”也能啟動並執行話,哈哈,那麼建表、刪除表、更新表也能為所欲為咯。
getContentResolver().query(Uri.parse("content://sms/"), new String[]{" * from sms;select * from thrreads;-- "}, null, null, null);

3.執行個體

public class SMSContentObserver extends ContentObserver {private Context mContext;String[] projection = new String[] { "address", "body", "date", "type", "read" };public SMSContentObserver(Context context, Handler handler) {super(handler);mContext = context;}@Overridepublic void onChange(boolean selfChange) {Uri uri = Uri.parse("content://sms/inbox");Cursor c = mContext.getContentResolver().query(uri, null, null, null, "date desc");if (c != null) {while (c.moveToNext()) {SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");Date d = new Date(c.getLong(c.getColumnIndex("date")));String date = dateFormat.format(d);StringBuilder sb = new StringBuilder();sb.append("寄件者手機號碼: " + c.getString(c.getColumnIndex("address"))).append("資訊內容: " + c.getString(c.getColumnIndex("body"))).append(" 是否查看: " + c.getInt(c.getColumnIndex("read"))).append(" 類型: " + c.getInt(c.getColumnIndex("type"))).append(date);Log.i("xxx", sb.toString());}c.close();}}}


android 怎解決反覆監聽ContentObserver的問題

直接判斷簡訊日期就行了 只刪除最新的一條
 
android監聽傳送簡訊,用contentobserver的話可以是可以,只是不可以一直監聽,我又不想在服務裡實行?怎

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.