Android - 四大组件之内容提供者,通知栏提醒Notification,短信,联系人数据库,内容观察者

转载请注明出处:https://blog.csdn.net/mythmayor/article/details/72876812

1.四大组件

  • activity
  • service
  • broadcast receiver
  • content provider 内容提供者

2.内容提供者的作用

应用程序创建的数据库默认都是私有的,别的应用程序不可以访问里面的数据。如果有需求把自己应用程序私有的数据库暴露给别的用户,就需要使用内容提供者

3.创建内容提供者

  1. 创建一个类继承ContentProvider

    public class BankDBBackdoor extends ContentProvider {
    
    }
    
  2. 在清单文件的application节点中进行配置

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        ...
        ...
        <provider
            android:name="com.mythmayor.db.BankDBBackdoor"
            //必须配置该主机名,访问者使用该主机名才能访问
            android:authorities="com.mythmayor.db" >
        </provider>
    </application>
    
  3. 重写内容提供者中的insert等方法

4.访问内容提供者

// 得到内容提供者的解析器
ContentResolver resolver = getContentResolver();
// 访问内容提供者主要通过uri来访问
Uri uri = Uri.parse("content://com.mythmayor.db");
ContentValues values = new ContentValues();
// 通过内容解析器让内容提供者添加一条数据
resolver.insert(uri, values);

5.UriMatcher的使用步骤

  1. 创建一个UriMatcher,并初始化

    //初始化为不匹配
    static UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    
  2. 创建一些匹配规则

    //如果uri满足 content://com.mythmayor.db/account,则返回SUCCESS这个常量值
    static {
        mUriMatcher.addURI("com.mythmayor.db", "account", SUCCESS);
    }
    
    //系统短信应用的匹配规则
    private static final UriMatcher sURLMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    static {
        sURLMatcher.addURI("sms", null, SMS_ALL); //所有短信
        sURLMatcher.addURI("sms", "inbox", SMS_INBOX); //收件箱
        sURLMatcher.addURI("sms", "sent", SMS_SENT); //发件箱
        sURLMatcher.addURI("sms", "draft", SMS_DRAFT); //草稿箱
    }
    
  3. 在insert等方法中,先使用match(Uri uri)方法匹配一个uri,然后根据返回的值进行不同的操作

    int code = mUriMatcher.match(uri);
    if (code == SUCCESS) {
        ...
        ...
    }else{
        ...
        ...
    }
    

6.内容提供者编写的流程

  1. 写一个类继承ContentProvider,实现增删改查的方法
  2. 在清单文件中配置内容提供者,指定 android:authorities=”com.mythmayor.db”
  3. 在内容提供者代码的内部 声明uriMatcher
  4. 通过uriMatcher 检查uri的路径是否正确
  5. 在另外一个应用程序里面 通过contentResolver 增删改查

7.内容提供者编写的流程

  1. 创建一个类继承ContentProvider

    public class BankDBBackdoor extends ContentProvider {
    
    }
    
  2. 在清单文件的application节点中进行配置

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        ...
        ...
        <provider
            android:name="com.mythmayor.db.BankDBBackdoor"
            //必须配置该主机名,访问者使用该主机名才能访问
            android:authorities="com.mythmayor.db" >
        </provider>
    </application>
    
  3. 在内容提供者代码的内部声明UriMatcher,创建匹配规则

    public static final int SUCCESS = 1;
    /**
     * 创建一个保安,检查uri的规则,如果uri匹配失败 返回-1
     */
    static UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
    static {
        mUriMatcher.addURI("com.mythmayor.db", "account", SUCCESS);
    }
    
  4. 实现增删改查的方法,通过uriMatcher的返回值确定要做什么操作

  5. 在另外一个应用程序里面,通过contentResolver进行增删改查

8.学习内容提供者的目的

  1. 了解内容提供者原理
  2. 能看懂系统源码
  3. 获取系统应用内容提供者所提供的数据,例如联系人、短信应用

9.如何去分析系统应用的内容提供者

  1. 查看数据库,分析数据库的表和字段
  2. 操作内容提供者需要uri
  3. 找到系统应用的源代码,首先去清单文件中查找主机名authorities

    <provider android:name="SmsProvider"
          android:authorities="sms"
          android:multiprocess="true"
          android:readPermission="android.permission.READ_SMS"
          android:writePermission="android.permission.WRITE_SMS" />
    
  4. 去对应的Provider的源代码中查找匹配规则,确定表名

    static {
        sURLMatcher.addURI("sms", null, SMS_ALL); //所有短信
        sURLMatcher.addURI("sms", "inbox", SMS_INBOX); //收件箱
        sURLMatcher.addURI("sms", "sent", SMS_SENT); //发件箱
        sURLMatcher.addURI("sms", "draft", SMS_DRAFT); //草稿箱
    }
    
  5. 根据主机名和表名确定uri,使用ContentResolver的增删改查方法操作对应的数据库

10.通知栏提醒Notification

显示在另外一个进程的界面里面的

  1. 在低版本中的写法(api小于16),创建Notification时直接new Notification()

    NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    
    //1.初始化Notification
    Notification notification = new Notification(R.drawable.ic_launcher, "有新的消息到来了", System.currentTimeMillis()); 
    
    //2.创建通知栏的点击事件
    Intent intent = new Intent();
    intent.setAction(Intent.ACTION_CALL);
    intent.setData(Uri.parse("tel://110"));
    //PendingIntent延时的意图,可以打开Activity、Service和发送广播
    PendingIntent contentIntent = PendingIntent.getActivity(this, 0, intent, 0);
    
    //3.设置通知的点击事件
    notification.setLatestEventInfo(this, "我是标题", "我是文本", contentIntent);
    
    //4.显示通知
    nm.notify(0, notification);  
    
  2. 在高版本中的写法(api大于等于16),创建Notification时使用Notification.Builder

    NotificationManager nm = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
    
    //1.初始化Notification
    Notification notification = new Notification.Builder(this)
        .setContentTitle("我是标题")
        .setContentText("我是文本")
        .setSmallIcon(R.drawable.ic_launcher)
        .setLargeIcon(BitmapFactory.decodeResource(getResources(), R.drawable.ic_launcher))
        .setContentIntent(PendingIntent intent) //设置点击事件
        .build();
    
    //2.显示通知
    nm.notify(0, notification); 
    
  3. Notification中使用自定义View

    api小于16

    Notification notification = new Notification(R.drawable.ic_launcher, "有新的消息到来了", System.currentTimeMillis());
    //设置自定义布局
    RemoteViews remoteViews = new RemoteViews(getPackageName(), R.layout.xxx);
    notification.contentView = remoteViews; 
    

    api大于16

    Builder builder = Notification.Builder(this);
    //设置自定义布局
    builder.setContent(RemoteViews views); 
    
  4. RemoteViews使用方式

    RemoteViews views = new RemoteViews(getPackageName(), R.layout.xxx);
    views.setTextViewText(R.id.xxx, "hello"); //设置TextView的文本
    views.setImageViewResource(R.id.xxx, R.drawable.xxx); //设置ImageView的图片
    views.setOnClickPendingIntent(R.id.xx, pendingIntent); //设置按钮的点击事件
    

11.如何打开短信界面

尝试打开系统某个界面的思路

  1. 从logcat中查看是哪个Activity
  2. 在上层源码中搜索该工程
  3. 查看清单文件中是否有隐式意图可以激活

    //打开短信界面的隐式意图
    Intent intent = new Intent();
    intent.setAction("android.intent.action.MAIN");
    intent.addCategory("android.intent.category.DEFAULT");
    intent.setType("vnd.android.cursor.dir/mms");
    startActivity(intent);
    

12.联系人数据库

  1. 路径:data/data/com.android.providers.contacts/databases/contacts2.db
  2. 主要操作的3张表:
    1. raw_contact:联系人的id表
      • contact_id 保存联系人的id
    2. data:联系人的数据表
      • raw_contact_id 表示属于哪个联系人
      • data1 具体的数据
      • mimetype_id 数据的类型,使用该id去mimetypes表中查询数据类型
    3. mimetypes:联系人的数据类型表
  3. 查询联系人数据库的数据的步骤
    1. 查询raw_contact表,获取所有联系人id
    2. 根据联系人id,查询data表,该联系人的所有数据
    3. 根据mimetype确定数据类型

13.如何读取联系人数据

ContentResolver resolver = getContentResolver();
//1.查询raw_contact表,获取所有联系人id
Uri uri = Uri.parse("content://com.android.contacts/raw_contacts");
Uri datauri = Uri.parse("content://com.android.contacts/data");
Cursor cursor = resolver.query(uri, new String[]{"contact_id"}, null, null, null);
while(cursor.moveToNext()){
    String id = cursor.getString(0);
    System.out.println("Id:"+id);

    //2.根据联系人id,查询data表,该联系人的所有数据
    Cursor datacursor = resolver.query(datauri, new String[]{"data1","mimetype"}, "raw_contact_id=?", new String[]{id}, null);
    while(datacursor.moveToNext()){

        //3.根据mimetype确定数据类型
        String data1 = datacursor.getString(0);
        System.out.println("data1:"+data1);
        String mimetype = datacursor.getString(1);
        System.out.println("mimetype:"+mimetype);
    }
    datacursor.close();
    System.out.println("------------");
}
cursor.close();
  • 备注:加上READ_CONTACTS权限,取mimetype时有个小细节,直接在data表里面就可以查询mimetype数据类型了,实际是查询数据库中的视图。

  • 数据库视图:视图是虚表,是从一个或几个基本表(或视图)中导出的表。

    1. 简单性:看到的就是需要的。视图不仅可以简化用户对数据的理解,也可以简化他们的操作。那些被经常使用的查询可以被定义为视图。
    2. 安全性:通过视图用户只能查询和修改他们所能见到的数据。数据库中的其它数据则既看不见也取不到。

14.系统联系人应用删除一个联系人的处理逻辑

  • 联系人应用删除一个联系人时,只是在raw_contact表中,把对应联系人的id置为null了
  • Google这么设计的目的是为了进行联系人与服务器同步,还有减少计算量
    • 比如,本地有4个联系人,服务器有5个联系人,而且服务器也具有添加联系人的功能,那同步时的逻辑是要往本地加一个联系人呢?还是要在服务器减一个联系人呢?
    • 另外对比少哪一个数据是一个非常麻烦的算法,要从A里取一个去遍历B里是否有这样一个数据

15.添加一个联系人到数据库的步骤

  1. 在raw_contact表中添加一个联系人的id
  2. 在data表里添加联系人的数据,姓名、电话、邮箱等

16.内容观察者

//注册内容观察者 
Uri uri = Uri.parse("content://com.mythmayor.db/account");
getContentResolver().registerContentObserver(uri, true, new ContentObserver(new Handler()) {

    @Override
    public void onChange(boolean selfChange) {
        System.out.println("我是观察者,我发现银行的数据库变化了.");
        super.onChange(selfChange);
    }

});
  • 内容观察者一般用于观察系统数据库的变化,例如联系人、短信等。系统的数据库发生变化是不需要操作数据库的人手动调用ContentResolver.notifyChange()的,所以无论是谁改变了数据库我们都会收到通知。

17.界面提醒方式


  • 土司
  • 对话框
  • 通知栏 notification

显示在另外一个进程的界面里面的

18.总结

  1. 内容提供者(ContentProvider)
    1. 内容提供者的作用
    2. 如何编写内容提供者
    3. UriMatcher的作用,如何使用
    4. 如何访问其他应用的内容提供者
    5. 通过内容提供者操作短信数据
    6. 通过内容提供者操作联系人数据
      • 操作联系人数据库中要用到的三张表
      • 获取所有联系人数据的思路
  2. 内容观察者(ContentObserver)
    1. 内容观察者的作用
    2. 如何使用内容观察者
  3. 通知栏提醒(Notification)
    1. 通知栏提醒Notification的使用
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值