ContentProvider组件
- ContentPrsovider的概念
- ContentProvider的基本使用
- ContentResolver内容观察者
- ContentProvider的常见应用
- 操作系统短信 (直接操作表)
- 操作系统联系人 (直接操作表)
- 联系人信息的获得 (操作系统给我们提供好的URL)
- 来电日志的删除 (内容观察者)
- 监听短信 (内容观察者)
01-ContentPrsovider的概念
- 目的:就是把自己私有的数据库内容通过内容提供者给暴露出来
- 内容提供者是以Uri进行传递的,其他组件都是都通Intent来传递信息的 URI的命名规则:Content://主机名/path/id
02-ContentProvider的使用
1. 内容提供者APP
- 定义一个继承SQLiteOpenHelper的类来创建一个数据库
- 定义一个类继承内容提供者在类中重写了CRUD的方法
- 需要在清单文件中配置
2. 内容解析者APP
- 获得内容解析者对数据库进行URCD的操作
//定义一个继承SQLiteOpenHelper的类来创建一个数据库
public class UserSQLiteOpenHelper extends SQLiteOpenHelper {
private static final String DB_NAME = "user.db";
private static final int VERSION = 1;
private UserSQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) {
super(context, name, factory, version);
}
public UserSQLiteOpenHelper(Context context) {
this(context, DB_NAME, null, VERSION);
}
@Override
public void onCreate(SQLiteDatabase db) {
// 初始化两张表
// t_woman
String sql = "create table t_woman(_id integer primary key,c_name varchar(20),c_age integer,c_phone varchar(12))";
db.execSQL(sql);
// t_man
String sql2 = "create table t_man(_id integer primary key,c_name varchar(20),c_age integer,c_phone varchar(12))";
db.execSQL(sql2);
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
//定义一个继承SQLiteOpenHelper的类来创建一个数据库
public class UserContentProvider extends ContentProvider {
//该定义其实也算是单例的一种
private static final UriMatcher sUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
private static final int MATCH_WOMAN = 1;
private static final int MATCH_MAN = 2;
static{
//给UriMatcher初始化,添加其可以支持的uri
//定义了两条路径1.content://com.itheima.provider/t_woman
// 2.content://com.itheima.provider/t_man ,其他的URI的访问将通不过
sUriMatcher.addURI("com.itheima.userProvider", "t_woman", MATCH_WOMAN);
sUriMatcher.addURI("com.itheima.userProvider", "t_man", MATCH_MAN);
}
private UserSQLiteOpenHelper userSQLiteOpenHelper;
/*
* 调用的时机:at application launch time 在主线程中被调用
*/
@Override
public boolean onCreate() {
//在内容提供者中获取Context对象
Context context = getContext();
//初始化SQLiteOpenHelper
userSQLiteOpenHelper = new UserSQLiteOpenHelper(context);
//返回值:如果初始化成功了,就返回true.
return true;
}
/*
* 参数1:内容解析者传递过来的uri
* 参数2:内容解析者访问内容提供者时传递的参数
*/
@Override
public Uri insert(Uri uri, ContentValues values) {
SQLiteDatabase database = userSQLiteOpenHelper.getWritableDatabase();
String tableName = getTableName(uri);
if (TextUtils.isEmpty(tableName)) {
return null;
}
long insert = database.insert(tableName, null, values);
Log.d("tag", "insert:"+insert);
//当进行该项操作时会给内容观察者发一条消息.
getContext().getContentResolver().notifyChange(uri, null);
//需要返回插入成功后的id
//但是这里只能返回一个uri类型的数据,不能直接返回id
//解决方法:uri+id
Uri withAppendedId = ContentUris.withAppendedId(uri, insert);
return withAppendedId;
}
//自定义的方法
private String getTableName(Uri uri) {
String tableName = "";
int match = sUriMatcher.match(uri);
switch (match) {
case MATCH_WOMAN:
tableName = "t_woman";
break;
case MATCH_MAN:
tableName = "t_man";
break;
case UriMatcher.NO_MATCH:
Log.d("tag", "错误的uri地址:"+uri);
return null;
default:
break;
}
return tableName;
}
/*
* 参数2:内容解析者提供的where表达式
* 参数3:where表达式中的?号的真实值
*/
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
SQLiteDatabase database = userSQLiteOpenHelper.getReadableDatabase();
String tableName = getTableName(uri);
//删除成功的行数
int delete = database.delete(tableName, selection, selectionArgs);
return delete;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
SQLiteDatabase database = userSQLiteOpenHelper.getWritableDatabase();
String tableName = getTableName(uri);
/*
* 参数1:表名
* 参数2:要更新的字段的key和value
*/
int update = database.update(tableName, values, selection, selectionArgs);
//将影响的行数返回给内容解析者
return update;
}
/*
* 参数2:要查询哪些字段
*/
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
SQLiteDatabase database = userSQLiteOpenHelper.getReadableDatabase();
String tableName = getTableName(uri);
/*
* 参数2:要查询哪些字段
*/
Cursor cursor = database.query(tableName, projection, selection, selectionArgs, null, null, sortOrder);
//给内容解析者返回游标
return cursor;
}
@Override
public String getType(Uri uri) {
return null;
}
}
//注册文件
<provider android:name="com.example.contentProvider.UserContentProvider"
//主机名
android:authorities="com.itheima.userProvider"
//此步需要设为true,不设置也是可以的,建议设置
android:exported="true" >
</provider>
//内容解析者APP,获得内容解析者对数据库进行URCD的操作
public class MainActivity extends Activity {
private ListView lv_users;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv_users = (ListView) findViewById(R.id.lv_users);
}
public void insertWoman(View view){
/*
* 1. 获取内容解析者
*/
ContentResolver contentResolver = getContentResolver();
ContentValues values = new ContentValues();
values.put("c_name", "lucy"+new Random().nextInt(100));
values.put("c_age", 20+new Random().nextInt(30));
values.put("c_phone", "110");
/*
* 2. 调用内容解析者的insert方法
*/
Uri insert = contentResolver.insert(Uri.parse("content://com.itheima.userProvider/t_woman"), values);
/*
* 3. 将返回的uri中的id再解析出来
*/
long parseId = ContentUris.parseId(insert);
Toast.makeText(this, "插入成功后的id是:"+parseId, Toast.LENGTH_SHORT).show();
}
public void insertMan(View view){
/*
* 1. 获取内容解析者
*/
ContentResolver contentResolver = getContentResolver();
ContentValues values = new ContentValues();
values.put("c_name", "高斯雷"+new Random().nextInt(100));
values.put("c_age", 30+new Random().nextInt(30));
values.put("c_phone", "120");
/*
* 2. 调用内容解析者的insert方法
*/
Uri insert = contentResolver.insert(Uri.parse("content://com.itheima.userProvider/t_man"), values);
/*
* 3. 将返回的uri中的id再解析出来
*/
long parseId = ContentUris.parseId(insert);
Toast.makeText(this, "插入成功后的id是:"+parseId, Toast.LENGTH_SHORT).show();
}
public void deleteMan(View view){
/*
* 获取内容解析者,然后调用delete方法
* 需求:将年龄大于54的干掉
*/
int delete = getContentResolver().delete(Uri.parse("content://com.itheima.userProvider/t_man"), "c_age>?", new String[]{"54"});
Toast.makeText(this, "成功删除了:"+delete, Toast.LENGTH_SHORT).show();
}
public void updateMan(View view){
ContentValues values = new ContentValues();
values.put("c_name", "雨泽2");
/*
* 需求:将年龄小于40的记录的c_name改为宇泽
*
* update t_user set c_name='雨泽' where c_age<40;
*
*/
int update = getContentResolver().update(Uri.parse("content://com.itheima.userProvider/t_man"), values, "c_age<?", new String[]{"40"});
Toast.makeText(this, "修改了:"+update, Toast.LENGTH_SHORT).show();
}
public void queryMan(View view){
List<String> users = new ArrayList<>();
/*
* 最后一个参数:排序表达式,不能包好order by本身
*/
Cursor cursor = getContentResolver().query(Uri.parse("content://com.itheima.userProvider/t_man"), new String[]{"c_name","c_age","c_phone"}, null, null, "c_age desc");
/*
* 遍历cursor
*/
while(cursor.moveToNext()){
String name = cursor.getString(0);
int age = cursor.getInt(1);
String phone = cursor.getString(2);
users.add("name="+name+"\nage="+age+"\nphone="+phone);
}
cursor.close();
//将数据显示到ListView上
lv_users.setAdapter(new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1, users));
}
}
03. ContentResolver内容观察者
需要先在内容提供者中发一条消息:
getContext().getContentResolver().notifyChange(uri, null);
内容观察者
- ContentObserver 对对数据的变化进行监听
- 需要定义一个类继承内容观察者,复写他的onChange()方法
- 然后注册内容观察者,反注册可有可无,可以实现验证码,自动填充.
getContentResolver().registerContentObserver(uri, true, new MyContentObserver(new Handler()));
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//[1]注册内容观察者
//第二个参数的含义是,是否派生到uri的子类,true表示,该Uri下派生的其他URI的变化都可以接受到,
Uri uri = Uri.parse("content://com.itheima.provider");
getContentResolver().registerContentObserver(uri, true, new MyContentObserver(new Handler()));
}
//定义一个内容观察者
private class MyContentObserver extends ContentObserver{
public MyContentObserver(Handler handler) {
super(handler);
}
//当内容发送改变的时候调用
@Override
public void onChange(boolean selfChange) {
System.out.println("哈哈哈 数据库的内容发送了改变 ");
super.onChange(selfChange);
}
}
}
04. ContentProvider的常见应用
- 操作系统短信 (直接操作表)
- 操作系统联系人 (直接操作表)
- 联系人信息的获得 (操作系统给我们提供好的URL)
- 来电日志的删除 (内容观察者)
- 监听短信 (内容观察者)
01-操作系统短信(短信的备份与还原)
//1. 操作系统短信 ,使用场景:短信的备份与还原
public class MainActivity extends Activity {
private ListView lv_sms;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv_sms = (ListView) findViewById(R.id.lv_sms);
}
public void readSms(View view){
Cursor cursor = getContentResolver().query(Uri.parse("content://sms"), new String[]{"address","date","type","body","_id"}, null, null, null);
/*
* 参数3:是否重查,如果true,那么当短信内容改变的时候,CursorAdapter会自动更新ListView
* 注意:cursorAdapter所使用的Cursor中必须用_id字段
*/
CursorAdapter cursorAdapter = new CursorAdapter(this,cursor,true) {
@Override
public View newView(Context context, Cursor cursor, ViewGroup parent){
TextView textView = new TextView(context);
textView.setTextSize(26);
textView.setTextColor(Color.BLUE);
return textView;
}
@Override
public void bindView(View view, Context context, Cursor cursor) {
TextView textView = (TextView)view;
Sms sms = new Sms();
sms.address = cursor.getString(0);
sms.date = cursor.getLong(1);
sms.type = cursor.getInt(2);
sms.body = cursor.getString(3);
textView.setText(sms.toString());
}
};
lv_sms.setAdapter(cursorAdapter);
}
public void insertSms(View view){
ContentValues values = new ContentValues();
values.put("address", "95555");
values.put("type", 1);
values.put("date", new Date().getTime());
values.put("body", "您尾号5553的招行卡,入账61020.25元,备注:7月份工资.详情请访问:http://www.cmbchina.com/");
Uri insert = getContentResolver().insert(Uri.parse("content://sms"), values);
long parseId = ContentUris.parseId(insert);
Toast.makeText(this, "插入成功:"+parseId, Toast.LENGTH_SHORT).show();
}
}
//权限
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.WRITE_SMS"/>
02-操作系统联系人(直接操作表)
//操作系统联系人,使用场景:微信,QQ读取联系人
//注:在手机上删除联系人后,仅仅是把raw_contects表中的一个标记字段改为了1,默认是0.在data表并没有删除
//数据库的名字是/data/data/com.android.providers.contacts/databases/包下的contact2.db 数据库。
1. 系统联系人表结构
1. data表 contact_id
2. mimetypes 记录通讯录中支持的所有的数据类型.叫数据字典表,只能查询,不会增加.
3. raw_contacts表:记录用户的id,一个用户一个id
2. 查询步骤
1. 首先查询raw_contacts表,cursor,遍历cursor,contact_id = 1;
2. 再带着contact_id=1,去查询data表
3. 遍历data表中查到的字段,然后根据字段中的mimeType区分当前遍历到的字段到底是啥数据
3. 插入系统联系人步骤
1. 首先读取raw_contacts表中最大的contact_id,然后contact_id+1作为我们新的id,
1. select contact_id from raw_contacts order by contact_id desc limit 1;
2. getCount()的方式也是可以的
2. 将contact_id+1插入到raw_contacts表中
3. 有几个字段就让data表中插入几行记录(raw_contact_id,mimeytype,data1)
4.系统读取短信的流程是先去读raw_contacts,只有当该表的标记字段是0的时候才会能够显示在手机的联系人中.
public class MainActivity extends Activity {
private ListView lv_contact;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
lv_contact = (ListView) findViewById(R.id.lv_contact);
}
public void readContact(View view){
List<Contact> contactList = new LinkedList<>();
ContentResolver contentResolver = getContentResolver();
/*
* 1. 首先查询raw_contacts表,cursor,遍历cursor,contact_id = 1;
*/
Cursor cursor = contentResolver.query(Uri.parse("content://com.android.contacts/raw_contacts"), new String[]{"contact_id"}, "deleted=?", new String[]{"0"}, null);
/*
* 2. 遍历cursor,再带着contact_id=1,去查询data表
*/
while(cursor.moveToNext()){
//取出联系人的id
int contact_id = cursor.getInt(0);//1 2
//创建一个JavaBean,一个id就代表一个JavaBean
Contact contact = new Contact();
//去data表中查询,记得改表名
/*
* 注意:data表中看着是mimetype_id,其实真正查询的时候会被转换为mimetype字段,并且返回的是字符串
* 注意:data表中国看着是raw_contact_id,其实真正查询的时候会被转换为contact_id,其实两者都是可以的
*/
Cursor cursor2 = contentResolver.query(Uri.parse("content://com.android.contacts/data"), new String[]{"data1","mimetype"}, "contact_id=?", new String[]{contact_id+""}, null);
while(cursor2.moveToNext()){
String data1 = cursor2.getString(0);
String mimetype = cursor2.getString(1);
//根据mimetype区分当前的数据类型,然后封装到JavaBean上
if ("vnd.android.cursor.item/name".equals(mimetype)) {
contact.name = data1;
}else if("vnd.android.cursor.item/phone_v2".equals(mimetype)){
contact.phone = data1;
}else if ("vnd.android.cursor.item/email_v2".equals(mimetype)) {
contact.email = data1;
}else if ("vnd.android.cursor.item/postal-address_v2".equals(mimetype)) {
contact.address = data1;
}
}
cursor2.close();
//将当前Contact添加到集合中
contactList.add(contact);
}
cursor.close();
lv_contact.setAdapter(new ArrayAdapter<Contact>(this, android.R.layout.simple_list_item_1, contactList));
}
public void insertContact(View view){
Contact contact = new Contact();
ContentResolver contentResolver = getContentResolver();
contact.address = "深圳福田区福中三路";
contact.phone = "(0755)82100000";
contact.email = "518000";
contact.name = "许勤"+new Random().nextInt(1000);
/*
* 1. 首先读取raw_contacts表中最大的contact_id,然后contact_id+1作为我们新的id
*/
int new_contact_id = 1;
Cursor cursor = contentResolver.query(Uri.parse("content://com.android.contacts/raw_contacts"), new String[]{"contact_id"}, null, null, "contact_id desc limit 1");
if(cursor!=null&&cursor.moveToNext()){
int contact_id = cursor.getInt(0);
new_contact_id = contact_id+1;
}
cursor.close();
ContentValues values2 = new ContentValues();
/*
* 2. 将contact_id+1插入到raw_contacts表中
*/
values2.put("contact_id", new_contact_id);
contentResolver.insert(Uri.parse("content://com.android.contacts/raw_contacts"), values2 );
/*
* 3. 有几个字段就让data表中插入几行记录(raw_contact_id,mimeytype,data1)
*/
ContentValues values = new ContentValues();
//插入name
values.put("raw_contact_id", new_contact_id);
values.put("mimetype", "vnd.android.cursor.item/name");
values.put("data1", contact.name);
contentResolver.insert(Uri.parse("content://com.android.contacts/data"), values);
//插入phone
values.clear();
values.put("raw_contact_id", new_contact_id);
values.put("mimetype", "vnd.android.cursor.item/phone_v2");
values.put("data1", contact.phone);
contentResolver.insert(Uri.parse("content://com.android.contacts/data"), values);
//插入address
values.clear();
values.put("raw_contact_id", new_contact_id);
values.put("mimetype", "vnd.android.cursor.item/postal-address_v2");
values.put("data1", contact.address);
contentResolver.insert(Uri.parse("content://com.android.contacts/data"), values);
//插入email
values.clear();
values.put("raw_contact_id", new_contact_id);
values.put("mimetype", "vnd.android.cursor.item/email_v2");
values.put("data1", contact.email);
contentResolver.insert(Uri.parse("content://com.android.contacts/data"), values);
Toast.makeText(this, "插入成功:"+contact, Toast.LENGTH_SHORT).show();
}
}
//权限
<uses-permission android:name="android.permission.READ_CONTACTS"/>
<uses-permission android:name="android.permission.WRITE_CONTACTS" />
03-联系人信息的获得(操作系统给我们提供好的URL)
- 需求 : 获取本地通讯录中的联系人数据,获取联系人的名字,号码与ID号
- 实现 : 通过系统定义好的常量去获取联系人数据
- 联系人数据库地址: data/data/com.android.providers.contacts/databases/contacts2.db
URI简介
- 联系人电话Uri: content://com.android.contacts/data/phones
- 联系人Email Uri: content://com.android.contacts/data/emails
Android官方有将上述URI进行封装,我们可以使用API以更简单的方式获取这些URI
- 联系人电话Uri: ContactsContract.CommonDataKinds.Phone.CONTENT_URI
- 联系人名字列名常量:ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME
- 联系人号码列名常量:ContactsContract.CommonDataKinds.Phone.NUMBER
- 联系人ID列名常量: ContactsContract.CommonDataKinds.Phone.CONTACT_ID
读取联系人需要添加权限
- 写权限
- 代码 :
public static ArrayList<PhoneNumEntry> getAllContacts(Context context) {
ArrayList<PhoneNumEntry> list = new ArrayList<PhoneNumEntry>();
ContentResolver cr = context.getContentResolver();
// 查询联系人号码的URI
Uri uri = ContactsContract.CommonDataKinds.Phone.CONTENT_URI;
// 返回的数据的列
String[] projection = new String[] {Phone.DISPLAY_NAME, Phone.NUMBER};
String selection = null;
String[] selectionArgs = null;
String sortOrder = null;
Cursor cursor = cr.query(uri, projection, selection, selectionArgs, sortOrder);
if (cursor != null) {
while (cursor.moveToNext()) {
PhoneNumEntry entry = new PhoneNumEntry();
String name = cursor.getString(0);
String num = cursor.getString(1);
entry.name = name;
entry.num = num;
list.add(entry);
}
}
cursor.close();
return list;
}
- 需求 : 联系人图片数据的获得
- 实现 : 通过 ContactsContract.Contacts.openContactPhotoInputStream()方法获取文件流, 然后通过BitmapFactory获取对应的Bitmap,通过拿到联系人的ID,追加在Contacts.CONTENT_URI后面,才能够拿到联系人的头像
- 代码 :
public static Bitmap getPhoto(Context context, String id) {
ContentResolver cr = context.getContentResolver();
Uri contactUri = Uri.withAppendedPath(Contacts.CONTENT_URI, id);
InputStream is = ContactsContract.Contacts.openContactPhotoInputStream(cr, contactUri);
return BitmapFactory.decodeStream(is);
}
04-来电日志的删除(内容提供者)
- 需求 :
- 拦截骚扰号码以后, 在手机通话记录中会留有通话记录, 将其删除
- 实现:
- 添加权限 android.permission.WRITE_CALL_LOG
- 让线程休眠一会儿, 再删除, 能否删除成功无法保证
- 来电日志Uri uri = CallLog.Calls.CONTENT_URI;
- 通过内容观察者. 代码:
final ContentResolver contentResolver = getContentResolver();
final Uri uri = CallLog.Calls.CONTENT_URI;
// true,当前注册的URI及其分支发生改变时,通知观察者
// false,仅当前注册的URI发生改变时,通知观察者,分支发生改变时,不通知观察者
boolean notifyForDescendents = true;
ContentObserver observer = new ContentObserver(new Handler()) {
public void onChange(boolean selfChange) {
contentResolver.delete(uri, CallLog.Calls.NUMBER + " = ?",
new String[] { incomingNumber });
// 取消监听
contentResolver.unregisterContentObserver(this);
};
};
contentResolver.registerContentObserver(uri, notifyForDescendents, observer);
05-短信监听(内容提供者)
//短信监听
//data/data/com.android.providers.telephony/databases/mmssms.db的短信数据库
public class MainActivity extends Activity {
private SmsContentObserver smsContentObserver;
private TextView tv_sms;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
tv_sms = (TextView) findViewById(R.id.tv_sms);
/*
* 1. 注册内容观察者
*/
//首先获取内容解析者,然后通过内容解析者注册内容观察者
ContentResolver contentResolver = getContentResolver();
/*
* 参数1: 你想观察哪个uri
* 参数2:true,代表不仅可以观察"content://sms"还可以观察到所有以"content://sms"开头(派生)的uri的变化
*/
smsContentObserver = new SmsContentObserver(new Handler());
//Uri uri = Uri.parse("content://sms/outbox");则只会收到发件箱的消息
//发送短信:先放到草稿箱->再放到发件箱->放到普通的短信里,所以发送短信会收到三条信息.这三种信息都会放在sms表中
contentResolver.registerContentObserver(Uri.parse("content://sms"), true, smsContentObserver);
}
class SmsContentObserver extends ContentObserver{
//handler用于决定onChange方法在哪个线程中执行,handler是在主线,这运行在主线程中,如果是在子线中这是子线程中.默认在子线程中执行.
public SmsContentObserver(Handler handler) {
super(handler);
}
//覆写一个回调方法
/*
* 参数1:是自己app发出的通知吗
* 参数2:观察到变化的uri
*/
//注意在这里查询到的是变化的一部分.原因在onChange()方法给我们传入了变化的Uri地址.
@Override
public void onChange(boolean selfChange, Uri uri) {
super.onChange(selfChange, uri);
Log.d("tag", "selfChange="+selfChange+"/uri="+uri);
Log.d("tag", "ThreadName="+Thread.currentThread().getName());
//读取短信
Cursor cursor = getContentResolver().query(uri, new String[]{"body","address","date","type"}, null, null, null);
if (cursor.moveToNext()) {
String body = cursor.getString(0);
String address = cursor.getString(1);
long date = cursor.getLong(2);
int type = cursor.getInt(3);
if (type==2) {
tv_sms.setText("她在发短信:body="+body+"\naddress="+address+"\ntype="+type);
Toast.makeText(MainActivity.this, "她在发短信:body="+body+"\naddress="+address+"\ntype="+type, Toast.LENGTH_LONG).show();
}else if (type==1) {
tv_sms.setText("她在收短信:body="+body+"\naddress="+address+"\ntype="+type);
Toast.makeText(MainActivity.this, "她在收短信:body="+body+"\naddress="+address+"\ntype="+type, Toast.LENGTH_LONG).show();
}
}
cursor.close();
}
}
@Override
protected void onDestroy() {
super.onDestroy();
/*
* 2. 取消内容观察者
*/
if (smsContentObserver!=null) {
//取消内容观察者,就是不在观察
getContentResolver().unregisterContentObserver(smsContentObserver);
smsContentObserver = null;
}
}
}
2016/9/15 13:48:19