ContentPrivider

ContentProvider组件

  1. ContentPrsovider的概念
  2. ContentProvider的基本使用
  3. ContentResolver内容观察者
  4. ContentProvider的常见应用
    1. 操作系统短信 (直接操作表)
    2. 操作系统联系人 (直接操作表)
    3. 联系人信息的获得 (操作系统给我们提供好的URL)
    4. 来电日志的删除 (内容观察者)
    5. 监听短信 (内容观察者)

01-ContentPrsovider的概念

  1. 目的:就是把自己私有的数据库内容通过内容提供者给暴露出来
  2. 内容提供者是以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内容观察者

  1. 需要先在内容提供者中发一条消息:
    getContext().getContentResolver().notifyChange(uri, null);

  2. 内容观察者

    1. ContentObserver 对对数据的变化进行监听
    2. 需要定义一个类继承内容观察者,复写他的onChange()方法
    3. 然后注册内容观察者,反注册可有可无,可以实现验证码,自动填充.
      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的常见应用

  1. 操作系统短信 (直接操作表)
  2. 操作系统联系人 (直接操作表)
  3. 联系人信息的获得 (操作系统给我们提供好的URL)
  4. 来电日志的删除 (内容观察者)
  5. 监听短信 (内容观察者)
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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值