使用ContentObserver实现短信提醒功能

该博客介绍如何在Android应用中通过ContentObserver监听并处理短信。通过查询`content://sms` Uri获取未读短信,并展示如何获取数据库中的短信列字段。程序设计包括定义常量类SMS用于存储相关配置。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

通过查询语句: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.youkuaiyun.com/detail/deng0zhaotai/9250353
以上方式只是ContentObserver的一种使用方法,可以用来监听你需要监听的数据库是否有变化,如有变化作出相应的回应。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值