五、ContentProvider 内容提供者
续上一博文(Android核心基础-5.Android 数据存储与访问-4.ContentProvider 内容提供者)
前面讲了内容提供者ContentProvider和监听数据修改的ContentObserver
本讲将在上一博文的理论指导下,书写一个示例“短信的监听”
8.1 先导篇
我们启动模拟器->打开短信。发现log打印了一行如下:
07-26 10:40:20.208: I/ActivityManager(1007): START {act=android.intent.action.MAIN cat=[android.intent.category.LAUNCHER] flg=0x10200000 cmp=com.android.mms/.ui.ConversationList bnds=[192,417][256,481] u=0} from pid 1146
从日志中我们看到系统启动的短信应用程序的包名是com.android.mms
根据这个包名我们去系统目录下查找data/data/com.android.mms
很遗憾的发现没有数据库文件,那么我们发送/接收的短信数据都储存在哪里呢?
继续追查下去,去下载官方的源码(github地址:https://github.com/CyanogenMod/android_packages_providers_TelephonyProvider),我们发现打开的“短信”应用程序只是展示界面,其数据是存储在另外一个程序中(con.android.providers.telephony)通过然后ContentProvider进行增删改查的操作。
找到data/data/com.android.providers.telephony/databases
目录下的mmssms.db导出到电脑,用SQLite Expert Professional 3打开
我们发送的短信都存储在sms表中
- 从github上下载telephonyprovider, 从清单文件中获取Uri
- 在程序中对指定Uri注册ContentObserver, 当收发短信时就会执行onChange()
- 查询到最后一条数据就是短信记录
8.2 创建程序
程序不需要Activity,但是我们为了讲解示例,我们就暂且创建了Activity
package net.dxs.smshack;
import java.util.Date;
import android.app.Activity;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
public class MainActivity extends Activity {
private static final Uri uri = Uri.parse("content://sms");//手机短信内容提供者的Uri
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//注册ContentObserver
getContentResolver().registerContentObserver(uri, true, new ContentObserver(new Handler()) {
private Date date;
@Override
public void onChange(boolean selfChange) {//收发短信时查询出最后一条数据
Cursor cursor = getContentResolver().query(uri, new String[] { "address", "date", "type", "body" }, null, null, "_id DESC LIMIT 1");
if (cursor.moveToNext()) {
String address = cursor.getString(0);
Date newDate = new Date(cursor.getLong(1));
if (newDate.equals(date))
return;
date = newDate;
String type = cursor.getInt(2) == 1 ? "收" : "发";
String body = cursor.getString(3);
System.out.println(address + ", " + newDate + ", " + type + ", " + body);
// 通过短信发送到自己的手机
// 发送邮件
// 提交到服务器
}
}
});
}
}
程序中的地址Uri uri = Uri.parse(“content://sms”)
是根据我们下载的源码的清单文件:知道android:authorities=”sms”//授权/主机名
和android:name=”SmsProvider”知道是SmsProvider.java文件的代码查看
最后得到的Uri
<provider android:name="SmsProvider"
android:authorities="sms"//授权/主机名
android:multiprocess="false"//是否允许多进程同时使用
android:exported="true"//应用程序可以被其他应用使用
android:singleUser="true"//单用户
android:readPermission="android.permission.READ_SMS" //读权限
android:writePermission="android.permission.WRITE_SMS" />//写权限
注意:我们的程序要添加对应的用户权限
<uses-permission android:name="android.permission.READ_SMS" />
把我们的程序安装至模拟器,这个时候发送短信
将看到打印:
07-26 14:43:49.698: I/System.out(14329): 1 501-099-0415, Sun Jul 26 14:43:49 格林尼治标准时间+0800 2015, 发, 这是发送的内容
至此,我们短信监听就算是完成了。
8.3 写在最后
mmssms库的表
addr
android_metadata
attachments
canonical_addresse
drm
part
pdu
pending_msgs
rate
raw
sms
sr_pending
threads
words
其中我们关心的表为:sms,其字段为:
_id
thread_id
address
person
date
date_sent
protocol
read
status
type
reply_path_present
subject
body
service_center
locked
error_code
seen