使用ContentObserver實現簡訊提醒功能

使用ContentObserver實現簡訊提醒功能

通過查詢語句:Cursor cursor = mContext.getContentResolver().query(Uri.parse(“content://sms”), null, “type = 1 and read = 0”, null, null);列印可以看到資料庫中所有的列欄位

String names[] = cursor.getColumnNames();
name = _id i = 0        //短訊息序號自動遞增 如100
name = thread_id i = 1  //序號,同一發信人的id相同
name = address i = 2    //發件人地址,手機號.如:10086 
name = person i = 3     //發件人,返回一個數字就是聯絡人列表裡的序號,陌生人為null
name = date i = 4       //日期,long型
name = date_sent i = 5
name = protocol i = 6   //協議 0 SMS_RPOTO, 1 MMS_PROTO 
name = read i = 7       //是否閱讀 0未讀, 1已讀  
name = status i = 8     //狀態 -1接收,0 complete, 64 pending, 128 failed 
name = type i = 9       
//ALL    = 0;
//INBOX  = 1;   接收
//SENT   = 2;   傳送
//DRAFT  = 3;
//OUTBOX = 4;
//FAILED = 5;
//QUEUED = 6; 
name = reply_path_present i = 10
name = subject i = 11   //簡訊的主題,一般為null
name = body i = 12      //簡訊內容
name = service_center i = 13   //簡訊服務中心號碼編號,如 8613800752011 
name = locked i = 14
name = error_code i = 15
name = seen i = 16
name = timed i = 17
name = deleted i = 18
name = sync_state i = 19
name = marker i = 20
name = source i = 21
name = bind_id i = 22
name = mx_status i = 23
name = mx_id i = 24
name = out_time i = 25
name = account i = 26
name = block_type i = 27
name = sim_id i = 28
name = advanced_seen i = 29

以上作了註釋的是較為常用的,我們可以只查詢出常用的列,查詢函式原型:query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder)
第二個引數:projection,可以寫上我們需要的列,第三個:selection是查詢的條件。

private static final String[] PROJECTION = new String[] { SMS._ID,// 0
SMS.TYPE,// 1
SMS.ADDRESS,// 2
SMS.SUBJECT,// 3
SMS.BODY,// 4
SMS.DATE,// 5
SMS.THREAD_ID,// 6
SMS.READ,// 7
SMS.PROTOCOL // 8
};
Cursor cursor = mContext.getContentResolver().query(
SMS.CONTENT_URI, PROJECTION, "type = 1 and read = 0", null,
null);

關於每個字元的型別可以看下packages/providers/TelephonyProvider/src/com/android/providers/telephony/MmsSmsDatabaseHelper.java檔案是如何建立表的:

db.execSQL("CREATE TABLE pdu_temp ("  
Mms._ID   " INTEGER PRIMARY KEY AUTOINCREMENT,"  
Mms.THREAD_ID   " INTEGER,"  
Mms.DATE   " INTEGER,"  
Mms.DATE_SENT   " INTEGER DEFAULT 0,"  
Mms.MESSAGE_BOX   " INTEGER,"  
Mms.READ   " INTEGER DEFAULT 0,"  
Mms.MESSAGE_ID   " TEXT,"  
Mms.SUBJECT   " TEXT,"  
Mms.SUBJECT_CHARSET   " INTEGER,"  
Mms.CONTENT_TYPE   " TEXT,"  
Mms.CONTENT_LOCATION   " TEXT,"  
Mms.EXPIRY   " INTEGER,"  
Mms.MESSAGE_CLASS   " TEXT,"  
Mms.MESSAGE_TYPE   " INTEGER,"  
Mms.MMS_VERSION   " INTEGER,"  
Mms.MESSAGE_SIZE   " INTEGER,"  
Mms.PRIORITY   " INTEGER,"  
Mms.READ_REPORT   " INTEGER,"  
Mms.REPORT_ALLOWED   " INTEGER,"  
Mms.RESPONSE_STATUS   " INTEGER,"  
Mms.STATUS   " INTEGER,"  
Mms.TRANSACTION_ID   " TEXT,"  
Mms.RETRIEVE_STATUS   " INTEGER,"  
Mms.RETRIEVE_TEXT   " TEXT,"  
Mms.RETRIEVE_TEXT_CHARSET   " INTEGER,"  
Mms.READ_STATUS   " INTEGER,"  
Mms.CONTENT_CLASS   " INTEGER,"  
Mms.RESPONSE_TEXT   " TEXT,"  
Mms.DELIVERY_TIME   " INTEGER,"  
Mms.DELIVERY_REPORT   " INTEGER,"  
Mms.LOCKED   " INTEGER DEFAULT 0,"  
Mms.SEEN   " INTEGER DEFAULT 0,"  
Mms.TEXT_ONLY   " INTEGER DEFAULT 0"  
");");

只查詢出我們關心的欄位就可以了。
下面就來看下簡訊提醒功能如何實現的。

程式結構


先定義一個常量類SMS.java

package com.deng.datawidget.sms;
import android.net.Uri;
import android.provider.BaseColumns;
public class SMS implements BaseColumns {
public static final Uri CONTENT_URI = Uri.parse("content://sms");
public static final String FILTER = "!imichat";
public static final String TYPE = "type";
public static final String THREAD_ID = "thread_id";
public static final String ADDRESS = "address";
public static final String PERSON_ID = "person";
public static final String DATE = "date";
public static final String READ = "read";
public static final String SUBJECT = "subject";
public static final String BODY = "body";
public static final String PROTOCOL = "protocol";
public static final int MESSAGE_TYPE_ALL = 0;
public static final int MESSAGE_TYPE_INBOX = 1;
public static final int MESSAGE_TYPE_SENT = 2;
public static final int MESSAGE_TYPE_DRAFT = 3;
public static final int MESSAGE_TYPE_OUTBOX = 4;
public static final int MESSAGE_TYPE_FAILED = 5; // for failed outgoing
// messages
public static final int MESSAGE_TYPE_QUEUED = 6; // for messages to send
// later
public static final int PROTOCOL_SMS = 0;// SMS_PROTO
public static final int PROTOCOL_MMS = 1;// MMS_PROTO
}

定義SmsObserver繼承ContentObserver監聽資料庫的變化

package com.deng.datawidget.sms;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.Locale;
import android.content.Context;
import android.database.ContentObserver;
import android.database.Cursor;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
/**
* 簡訊監聽器,根據資料庫的變化去查詢未讀簡訊,可以做到簡訊提醒功能
* 
* 
*/
public class SmsObserver extends ContentObserver {
private static final String TAG = "SmsObserver";
private Context mContext;
private Handler mHandler;
private static final String[] PROJECTION = new String[] { SMS._ID,// 0
SMS.TYPE,// 1
SMS.ADDRESS,// 2
SMS.SUBJECT,// 3
SMS.BODY,// 4
SMS.DATE,// 5
SMS.THREAD_ID,// 6
SMS.READ,// 7
SMS.PROTOCOL // 8
};
public SmsObserver(Context context, Handler handler) {
super(handler);
mHandler = handler;
mContext = context;
}
@Override
public void onChange(boolean selfChange) {
super.onChange(selfChange);
// 每當有新簡訊到來時,使用我們獲取短訊息的方法
int newMsgNum = getNewSmsCount();
Message msg = mHandler.obtainMessage();
msg.what = 2;
msg.obj = newMsgNum;
mHandler.sendMessage(msg);
Log.i(TAG, "onChange newMsgNum = "   newMsgNum);
}
private int getNewSmsCount() {
int result = 0;
try {
Cursor cursor = mContext.getContentResolver().query(
SMS.CONTENT_URI, PROJECTION, "type = 1 and read = 0", null,
null);
if (cursor != null) {
MessageItem msg;
result = cursor.getCount();
while (cursor.moveToNext()) {
int id = cursor.getInt(cursor.getColumnIndex(SMS._ID));
int type = cursor.getInt(cursor.getColumnIndex(SMS.TYPE));
int protocol = cursor.getInt(cursor
.getColumnIndex(SMS.PROTOCOL));
String address = cursor.getString(cursor
.getColumnIndex(SMS.ADDRESS));
String body = cursor.getString(cursor
.getColumnIndex(SMS.BODY));
String subject = cursor.getString(cursor
.getColumnIndex(SMS.SUBJECT));
SimpleDateFormat dateFormat = new SimpleDateFormat(
"yyyy-MM-dd hh:mm:ss", Locale.getDefault());
Date d = new Date(cursor.getLong(cursor
.getColumnIndex(SMS.DATE)));
String date = dateFormat.format(d);
msg = new MessageItem();
msg.setId(id);
msg.setType(type);
msg.setProtocol(protocol);
msg.setDate(date);
msg.setAddress(address);
msg.setSubject(subject);
msg.setBody(body);
Log.i(TAG, msg.toString());
}
String names[] = cursor.getColumnNames();
int i = 0;
for (String name : names) {
Log.i(TAG, "name = "   name   " i = "   i);
i  ;
}
cursor.close();
}
} catch (Exception e) {
Log.e(TAG, e.toString());
}
return result;
}
}

在activity中註冊內容觀察者

package com.deng.datawidget;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.Toast;
import com.deng.datawidget.sms.SMS;
import com.deng.datawidget.sms.SmsObserver;
public class MainActivity extends Activity {
private static final String TAG = "MainActivity";
private SmsObserver content = null;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
// TODO Auto-generated method stub
final int what = msg.what;
switch (what) {
case 2:
int num = (int) msg.obj;
Toast.makeText(MainActivity.this, "你有:"   num   " 條未讀簡訊",
Toast.LENGTH_LONG).show();
break;
default:
break;
}
super.handleMessage(msg);
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
content = new SmsObserver(this, mHandler);
// 註冊簡訊變化監聽
getContentResolver().registerContentObserver(SMS.CONTENT_URI, true,
content);
}
@Override
protected void onDestroy() {
// TODO Auto-generated method stub
super.onDestroy();
getContentResolver().unregisterContentObserver(content);
}
}

相應程式碼下載:http://download.csdn.net/detail/deng0zhaotai/9250353
以上方式只是ContentObserver的一種使用方法,可以用來監聽你需要監聽的資料庫是否有變化,如有變化作出相應的迴應。