A股上市公司传智教育(股票代码 003032)旗下技术交流社区北京昌平校区

 找回密码
 加入黑马

QQ登录

只需一步,快速开始

本帖最后由 小鲁哥哥 于 2016-12-4 18:42 编辑

【济南中心】Android课程同步笔记day09:Android应用开发基础

四大组件:
Activity,Service服务,Content Provider内容提供者,BroadcastReceiver广播接收器,前面几张讲过activity、service和BroadcastReceiver,在这一章里主要介绍ContentProvider。

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

创建内容提供者:
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.itheima.db.BankDBBackdoor"
                //必须配置该主机名,访问者使用该主机名才能访问
                android:authorities="com.itheima.db" >
            </provider>
        </application>
3. 重写内容提供者中的insert等方法

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

UriMatcher的使用步骤:
1. 创建一个UriMatcher,并初始化
        //初始化为不匹配
        static UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);

2. 创建一些匹配规则
[Java] 纯文本查看 复制代码
                //如果uri满足 content://com.itheima.db/account,则返回SUCCESS这个常量值
                static {
                        mUriMatcher.addURI("com.itheima.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,然后根据返回的值进行不同的操作
[Java] 纯文本查看 复制代码
                int code = mUriMatcher.match(uri);
                if (code == SMS_ALL) {
                        ...
                        ...
                }elseif (code == SMS_INBOX){
                        ...
                        ...
                }

内容提供者编写的流程:
1. 创建一个类继承ContentProvider
        public class BankDBBackdoor extends ContentProvider {}

2. 在清单文件的application节点中进行配置
[HTML] 纯文本查看 复制代码
                <application
                android:allowBackup="true"
                android:icon="@drawable/ic_launcher"
                android:label="@string/app_name"
                android:theme="@style/AppTheme" >
                ...
                        ...
                <provider
                    android:name="com.itheima.db.BankDBBackdoor"
                                //必须配置该主机名,访问者使用该主机名才能访问
                    android:authorities="com.itheima.db" >
                </provider>
            </application>

3. 在内容提供者代码的内部声明UriMatcher,创建匹配规则
[Java] 纯文本查看 复制代码
                public static final int SUCCESS = 1;
                /**
                 * 创建一个保安,检查uri的规则,如果uri匹配失败 返回-1
                 */
                static UriMatcher mUriMatcher = new UriMatcher(UriMatcher.NO_MATCH);
                static {
                        mUriMatcher.addURI("com.itheima.db", "account", SUCCESS);
                }

4. 实现增删改查的方法,通过uriMatcher的返回值确定要做什么操作
5. 在另外一个应用程序里面,通过contentResolver进行增删改查

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

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

[HTML] 纯文本查看 复制代码
                <provider android:name="SmsProvider"
              android:authorities="sms"
              android:multiprocess="true"
              android:readPermission="android.permission.READ_SMS"
              android:writePermission="android.permission.WRITE_SMS" />

4. 去对应的Provider的源代码中查找匹配规则,确定表名
[Java] 纯文本查看 复制代码
                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的增删改查方法操作对应的数据库

通知栏提醒Notification:
显示在另外一个进程的界面里面的
1. 在低版本中的写法(api小于16),创建Notification时直接new Notification()

[Java] 纯文本查看 复制代码
                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);
                //点击自动关闭消息
                notification.flags |= Notification.FLAG_AUTO_CANCEL;
                //4.显示通知
                nm.notify(0, notification);

2. 在高版本中的写法(api大于等于16),创建Notification时使用Notification.Builder
[Java] 纯文本查看 复制代码
                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) //设置点击事件
                        setAutoCancel(true)//点击后自动关闭
                        .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); //设置按钮的点击事件

如何打开短信界面:
尝试打开系统某个界面的思路:
1. 从logcat中查看是哪个Activity
2. 在上层源码中搜索该工程
3. 查看清单文件中是否有隐式意图可以激活
[Java] 纯文本查看 复制代码
                //打开短信界面的隐式意图
                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);

联系人数据库:
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确定数据类型

如何读取联系人数据:
[Java] 纯文本查看 复制代码
        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. 安全性:通过视图用户只能查询和修改他们所能见到的数据。数据库中的其它数据则既看不见也取不到。

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

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

内容观察者:
[Java] 纯文本查看 复制代码
        //注册内容观察者 
        Uri uri = Uri.parse("content://com.itheima.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 个回复

正序浏览

回帖奖励 +1 黑马币

多谢分享
回复 使用道具 举报

回帖奖励 +1 黑马币

多谢分享
回复 使用道具 举报
cheat 中级黑马 2017-7-10 22:49:51
15#

回帖奖励 +1 黑马币


可以的 很棒,
回复 使用道具 举报

回帖奖励 +1 黑马币

恩,除了黑马币之外的东西,都是福利
回复 使用道具 举报

回帖奖励 +1 黑马币

可以的 很强势
回复 使用道具 举报

回帖奖励 +1 黑马币

谢谢分享!
回复 使用道具 举报

回帖奖励 +1 黑马币

感谢老师分享, 辛苦了
回复 使用道具 举报
wh121 中级黑马 2017-3-24 15:30:08
10#

回帖奖励 +1 黑马币

进来看看学习
回复 使用道具 举报

回帖奖励 +1 黑马币

谢谢分享!
回复 使用道具 举报

回帖奖励 +1 黑马币

好东西!谢谢分享!谢谢!!!
回复 使用道具 举报

回帖奖励 +1 黑马币

支持一下 赞赞赞!!!!!
回复 使用道具 举报

回帖奖励 +1 黑马币

东西真的很棒 顶
回复 使用道具 举报

回帖奖励 +1 黑马币

哟西,很不错的说
来自宇宙超级黑马专属苹果客户端来自宇宙超级黑马专属苹果客户端
回复 使用道具 举报

回帖奖励 +1 黑马币

不错,支持一个
回复 使用道具 举报

回帖奖励 +1 黑马币

支持黑马
回复 使用道具 举报

回帖奖励 +1 黑马币

支持支持!
回复 使用道具 举报

回帖奖励 +1 黑马币

666....详细   
回复 使用道具 举报
您需要登录后才可以回帖 登录 | 加入黑马