-
Android
四大基本组件分别是
Activ
ity
,
Service
服务
,Content Provider
内容提供者,
BroadcastReceiver
广播接收器。
p>
一
:
了解四大基本组件
Activity :
应用程
序中,一个
Activity
通常就是一个单独的屏幕,它上面
可以显示一些控件也可以监
听并处理用户的事件做出响应。
<
/p>
Activity
之间通过
Intent
进行通信。在
Intent
的描述结
构中,有两个最重要的部分:动
作和动作对应的数据。
典型的动作类型有:
M AIN
(
p>
activity
的门户)、
VIEW
p>
、
PICK
、
ED
IT
等。而动作对应
的数据则以
URI <
/p>
的形式进行表示。例如:要查看一个人的联系方式,你需要创建一个动作
< br>类型为
VIEW
的
inten
t
,以及一个表示这个人的
URI
。<
/p>
与之有关系的一个类叫
IntentF
ilter
。相对于
intent
是一个有效的做某事的请求,一个
intentfilter
则用于描述一个
activity
(或
者
IntentReceiver
)能够操作哪些
intent
。一
个
act
ivity
如果要显示一个人的联系方式时,需要声明一个
I
ntentFilter
,这个
IntentFilter
要知道怎么去处理
VIEW
动作和表
示一个人的
URI
。
IntentFi
lter
需要在
中定义。通过解析
各种
intent
,从一个屏幕导航到另一个屏幕是
很简单的。当向前导航时,
activity
将会调用
startActivity(Intent myI
ntent)
方法。然
后,系统会在所有安装的应用程序中定义
的
IntentFilter
中查找,找到最匹配
myIntent
的
Intent
对应的
activity
。新的
activity
接收到
myIntent
的通知后,开始运行。当
startActivity
方法被调用将触发解析
myIntent
的动作,这个机制提供了两个关键好处:
A
、
Activities
能够重复利用从其它组件中以
Intent
的形式产生的一个请求;
B
、
Activities
可以在任何时候被一个具有相同
IntentFilter
的新的
Activity
取代。
AndroidManife
st
文件中含有如下过滤器的
Activity
组件为默认启动类当程序启动时系
统自动调用它
<
intent-
filter
>
<
action
android:name
=
/>
<
category
android:name
=
/>
intent-
filter
>
Broadcast
Receive
广播接收器
:
你的应用可以使用它对外部事件进行过滤只对感兴趣的外部事件
(
p>
如当电话呼入时,或者数
据网络可用时
)<
/p>
进行接收并做出响应。广播接收器没有用户界面。然而,它们可以启动一个
activity
或
serice
< br>来响应它们收到的信息,或者用
NotificationManager
p>
来通知用户。
通知可以用很多种方式来吸引用户的注意力
──
闪动背灯、震动、播放声音等。一般来说是
在
状态栏上放一个持久的图标,用户可以打开它并获取消息。
广播类型:
普通广播
,
通过
oadcast(Intent
myIntent)
发送的
有序广播
,
通过
deredBroadcast
(intent, receiverPermission)
发送
的,该方法第
2
个参数决定该广播的级别,级别数值是在<
/p>
-1000
到
1000
之间
,
值越大
,
发送的优先级越高;广播
接收者接收广播时的级别级别(可通过
intentfilter
中的
priority
进行设置设为
2147483647
时优先级最高),同级别接收的先后是随机的,
< br>
再
到级别低的收到广播,高级别的或同级别先接收到广
播的可以通过
abortBroadcast()
方
法截断广播使其他的接收者无法收到该广播,还有其他构造函数
异步广播
,
通过
ick
yBroadcast(Intent myIntent)
发送的,还有
sendStickyOrderedBroadcast(intent,
resultReceiver, scheduler, initialCode,
initialData, initialExtras)
方
法,该方法具有有序广播的特性也有异步广播的特性;发送
异步广播要:
<
br>Intent
android:name=
/><
/p>
权限,接收并处理
完
Intent
后,广播依然存在,直到你调用
removeStickyBroad
cast(intent)
主动把它去
掉
注意:发送广播时的
intent
参数与
ctivity()
启动起来的
Intent
不同
,
前者
可以被多个订阅它的广播接收器调用
,
后者只能被一
个
(Activity
或
servic
e)
调用
监听广播
步骤
:
1>
写一个继承
BroadCastReceiver
的类
,
重写
onRecei
ve()
方法
,
广播接收器
仅在它执行这个方法时处于活跃状态。当
onReceive()
返回后,它即为失活状态
,
注意
:
为
了保证用户交互过程的流畅
,
一些费时的操作要放到线程里
,
如
类名
SMSBroadcastReceiver
2>
注册该广播接收者
,
注册有两种方法程
序动态注册和
AndroidManifest
文件
中进行静态注册(可理解为系统中注册)如下:
静态注册
,
注册的广播,下面的
priority
表示接收广播的级别
2147483647
为最
高优先级
<
receiver
android:name
=
>
<
intent-filter
android:priority
=
>
<
action
android:name
=
/>
intent-
filter
>
receiver
>
动态注册,一般在
Activity
可交互时
onResume()
p>
内注册
BroadcastReceiver
IntentFilter
intentFilter=
new
IntentFilter(
registerReceiver(mBatteryI
nfoReceiver ,intentFilter);
//
反注册
unregisterReceiver(receiver);
注意:
1.
生命周期只有十秒左右,如果在
onReceive()
内做超过十秒内的事情,就会报
AN
R(Application No Response)
程序无响应的错误信息,如
果需要完成一项比较耗时
的工作
,
应该通过发送
Intent
给
Service,
由
Service
来完成
.
这里不能使用子线程来
解决
,
因为
BroadcastReceiver
的生命周期很短
,
子线程可能还没有结束
BroadcastReceiver
就先结束了
.BroadcastReceiver
一旦结束
,
此时
BroadcastReceiver
的所在进程很容易在系统需要内存时被优先杀死
,
因为它属于空进
程
(
没有任何活动组件的进程
).
如果它的宿主进程被杀死
,
那么正在工作的子线程也会
被杀死
.
所以采用子线程来解决是不可靠的
2.
动态注册广播接收器还有一个特点,就是当用来注册的<
/p>
Activity
关掉后,广播也就失
效
了。静态注册无需担忧广播接收器是否被关闭
,
只要设备是开启
状态
,
广播接收器也是打
开着的。也就
是说哪怕
app
本身未启动
,
该
app
订阅的广播在触发时也会对它起作用<
/p>
系统常见广播
Intent,
如开机启动、电池电量变化、时间改变等广播
Service
服务
:
一个
Service
是一段长生命周
期的,没有用户界面的程序,可以用来开发如监控类程序。
比
较好的一个例子就是一个正在从播放列表中播放歌曲的媒体播放器。在一个媒体播放器
的
应用中,应该会有多个
activity
,让使用者可以选择歌
曲并播放歌曲。然而,音乐重放
这个功能并没有对应的
acti
vity
,因为使用者当然会认为在导航到其它屏幕时音乐应该还
在播放的。在这个例子中,媒体播放器这个
activity
会使用
ervice()
来
启动一个
service
,从而可以在后台保持音乐的播放。同时,系统
也将保持这个
service
一直执行,直到这个
service
运行结束。另外,我们还可以通过使用
rvice()
方法,连
接到一个
service
上(如果这个
service
还没有
运行将
启动它)。当连接到一个
service
之后,我们还可以
service
提
供的接口与它进行通讯。
拿媒体播放器这个例子来说,我们还可以进行暂停、重播等操作
。
Service
使用步骤如下
1>
继承
servic
e
类
2>
配置清单文件中
节点
里对服务进行配置
服务不能自己运行
,
需要通过
ervice()
或
rvice()
启动服务
通过<
/p>
startService()
方法启动的服务于调用者没有关系
,
即使调用者关闭了
,
服务仍然运行
想停止服务要调用
rvice(),
p>
此时系统会调用
onDestory(),
使用此方法启
动时
,
服务首次启动系统
先调用服务的
onCreate()-->onStart(),
如果服务已经启动再次
调用只会触发
onStart()
p>
方法
使用
bin
dService()
启动的服务与调用者绑定
,
只要调用者关闭服务就终止
,
使用此方法启
动时
,
服务首次启动系统先调用服务的
onCreate()-->onBind(),
如果服务已经启动再次
调
用不会再触发这
2
个方法
,
调用者退出时系统会调用服务的
onUnbin
d()-->onDestory(),
想主动解除绑定可使用
Service(),
系统依次调用
onUnbind()--
>onDestory();
Content
Provider
内容提供者
:
<
/p>
android
平台提供了
Conten
t Provider
使一个应用程序的指定数据集提供给其他应用程
< br>序。这些数据可以存储在文件系统中、在一个
SQLite
数据库、或以任何其他合理的方式
,
其他应用可以通过
p>
ContentResolver
类
(
p>
见
ContentProviderAccessApp
例子
)
从该内
容提供者中
获取或存入数据
.(
相当于在应用外包了一层壳
),
只有需要在多个应用程序间共享数据是才需要内容提供者。例如,通讯录
数据被多个应用
程序使用,且必须存储在一个内容提供者中
<
/p>
它的好处
:
统一数据访问方式。
android
系统自带的内容提供者
(
顶级的表示数据库名
,
非顶级的都是表名
)
这些内容提供者
在
SDK
文档的
er Java
p>
包中都有介绍。见:
/reference/android/pr
ovider/package-
├
────Browser
├
────CallLog
├
────Contacts
│
├
────Groups
│
├
────People
│
├
────Phones
│
└────Photos
├
────Images
│
└────Thumbnails
├
────MediaStore
│
├
────Albums
│
├
────Artists
│
├
────Audio
│
├
────Genres
│
└────Playlists
├
────Settings
└────Video
CallLog
:地址和接收到的电话信息
:存储电话号码
:系统设置和偏好设置
使用
Content
Provider
对外共享数据的步骤
1>
继承
ContentProvider
< br>类并根据需求重写以下方法
:
public
boolean
onCreate();
//
处理初始化操作
/**
*
插入数据到内容提供者
(
允许其他
应用向你的应用中插入数据时重写
)
*
@param
uri
*
@param
initialValues
插入的数据
*
@return
*/
public
Uri insert(Uri uri,
ContentValues initialValues);
/**
*
从内容提供者中删除数据
(
允许其
他应用删除你应用的数据时重写
)
*
@param
uri
*
@param
selection
条件语句
*
@param
selectionArgs
参数
*
@return
*/
public
int
delete(Uri uri, String
selection, String[]
selectionArgs);
/**
*
更新内容提供者已存在的数据
(
允许其他应用更新你应用的数据时重
写
)
*
@param
uri
*
@param
values
更新的数据
*
@param
selection
条件语句
*
@param
selectionArgs
参数
*
@return
*/
public
int
update(Uri uri,
ContentValues values, String
selection,
String[]
selectionArgs);
/**
*
返回数
据给调用者
(
允许其他应用从你的应用中获取数据时重写
)
*
@param
uri
*
@param
projection
列名
*
@param
selection
条件语句
*
@param
selectionArgs
参数
*
@param
sortOrder
排序
*
@return
*/
public
Cursor query(Uri uri,
String[] projection, String
selection,
String[]
selectionArgs, String sortOrder)
/**
*
用于返回当前
U
ri
所代表数据的
MIME
类型
*
如果操作的数据为集
合类型
(
多条数据
),
那么返回的类型字符串应该
为
/
开头
*
例如要
得到所有
person
记录的
Uri<
/p>
为
content://provider/person,
*
那
么返回的
MIME
类型字符串应该为
<
/p>
*
如果操作的数据为单一数据
,
那么返回的类型字符串应该为
/
开头
*
例如
要得到
id
为
10
的
person
记录的
Uri
p>
为
content://provider/person/10,
*
那
么返回的
MIME
类型字符串应该为
<
/p>
*
@param
uri
*/
public
String getType(Uri
uri)
这些方法中的
Uri
p>
参数
,
得到后需要进行解析然后做对应处理
,Uri
表示要操作的数据
,
包含
两部分信息
:
1.
需要操作的
contentprovider
2.
对
content
provider
中的什么数据进行操作
,
一个
Uri
格式
:
结构
头
://authorities(
域名
)/
路径
(
要操作的数据
,
根据业务而定
)
content://provider/person/10
说明
< br>:contentprovider
的结构头已经由
an
droid
规定为
content://
authorities
用于唯一标识这个
content
provider
程序
,
外部调用者可
以根据这个找到他
路径表示我们要操作的数据
,
路径的构建根据业务而定
.
路径格式如
下
:
要操作
person<
/p>
表行号为
10
的记录
,
可以这样构建
/person/10
要操作
person<
/p>
表的所有记录
,
可以这样构建
/person
2>
在
中使用
对
ContentProvider
进行配置注册
(
内
容提供者注册它自己就像网站注册域名
< br>),ContentProvider
采用
author
itie(
原意授权
,
可
理解为域名
)
作为唯一标识
,
方便其他应用能找到
<
application
android:icon
=
android:label
=
>
<
provider
android:name
=
android:authorities
=
...
ap
plication
>
关于四大基本组件的一个总结:
1>
4
大组件的注册
4
< br>大基本组件都需要注册才能使用
,
每个
< br>Activity
、
service
、
Content Provider
内容提供
者都需要在
AndroidManifest
文件
中进行配置
AndroidManifest
文件中未进行声明
的
activity
、服务以及内容提供者将不为系统所见,从
而也就不可用,而
BroadcastReceive
广播接收
者的注册分静态注册(在
AndroidManifest
文件
中进行配
置)和通过代码动态创建并以调用
erReceive
r()
的方式注册至系统。需
要注意的是在
AndroidManifest
文件中进行配置的广播接收者会随系统的启动而一
直处
于活跃状态
,
只要接收到感兴趣的
广播就会触发(即使程序未运行)
AndroidManif
est
文件中进行注册格式如下:
元素的
name
属性指定了实现了这个
activity
的
Activity
的子类。
icon
和
label
属性指向了包含展示给用户的此
activity
的图标和标签的资源文件。
元素用于声明服务
元素用于声明广播接收器
元素用于声明内容提供者
2>
4
大组件的激活
?
容提供者的激活:当接收到
ContentResolver
发出的请求后,内容提供者被激活。而
其它三种组件
──activity
、服务和广播接收器被一种叫做
intent
的异步消息所激活
?
Activity
的激活通过传递一个
Intent
对象至
ctivity()
或
< br>ctivityForResult()
以载入(或指定新工作给)一个
activity
。相应的
activity
可以通过调用
getIntent()
方法来查看激活它的
intent
。如果它期望它所启动的<
/p>
那个
activity
返回一个结果,
它会以调用
startActivityForResult()
来取代
startActivity()
。比如说,如果它启
动了另外一个
Activity
以使用户挑选一张照片,它也
许想知道哪张照片被选中了。结果将会被封装在一个
Inten
t
对象中,并传递给发出调用
的
ac
tivity
的
onActivityResult()
方法。
?
服务的激活可以通过传递一个
Intent
< br>对象至
ervice()
或
rv
ice()
前者
Android
调用
服务的
onStart()
方法并将
I
ntent
对象传递
给它,后者
Android
调用服务的
onBind()
方法将这
个
Intent
对象传递给它
?
发送广播可以通过传递一个
Intent
对象至给
oadcast()
、
deredBroadcast(
)
或
ickyBroadcast()Android
会
调用所有对此广播有兴趣的广播接收器的
o
nReceive()
方法,将
intent
传递给它们
3>
四大组件的关闭
内容提供者仅在响应
ContentResolver
提出请求的时候激活。而一个广播接收器仅在响
应广播信息的时候激活
。所以,没有必要去显式的关闭这些组件。
Activity
关闭:可以通过调用它的
finish()
方法来关闭一个
activity
服务关闭:对于通过<
/p>
startService()
方法启动的服务要调用
rvice()
方法
关闭服务,使用
bindService()
方法启动的服务要调用
Service ()
方法关
闭服务
二
:
四大组件的生命周期
介绍生命周期之前,先提一下任务的概念
任务其实就是
activity
的栈
它由一个或多个
Activity
组成的共同完成一个完整的用
户体验,
换句话说任务就是
”
应用程序
”
(可以是一个也可以是多
个,比如假设你想让用户看到某
个地方的街道地图。而已经存在一个具有此功能的
activity
了,那么你的
activity
所需
要
做的工作就是把请求信息放到一个
Intent
对象里面,并把它传递给
startActivity()
。于
是地图浏览器就会显示那个地图。而当用户按下
B
ACK
键的时候,你的
activity
< br>又会再
一次的显示在屏幕上,此时任务是由
2
个应用程序中的相关
activity
组成的)栈
底的是启
动整个任务的
Activity
,栈顶的是当前运行的用户可以交互的
Activity
,当
一个
activity
启动另外一个的时候,新的
activity
就被压入栈,并成为当前运行的
activity
。而
前一个
activity
仍保持在栈之中。当用户按下
BACK
键的时候,当前
activity
出
栈,而前一个
恢复为当前运行的
activity
。栈中保存的其实是对象,栈中的
Activity
永远不会重排,只
会压入或弹出,所以如果发生了诸如需要多个地图浏览器的情况,就
会使得一个任务中出
现多个同一
Activity
子类的实例同时存在。
任务中的所有
activity
是作为一个整体进行移动的。整个的任务(即
activity
栈)可以移
到前台,或退至后台。举个例子说,比如当前任务在
栈中存有四个
activity──
三个在当前
activity
之下。当用户按下
HOME
p>
键的时候,回到了应用程序加载器,然后选择了一个
新的应用程序(
也就是一个新任务)。则当前任务遁入后台,而新任务的根
activity
显示
出来。然后,过了一小会儿,用户再次回到了应用程序加载器而又选
择了前一个应用程序
(上一个任务)。于是那个任务,带着它栈中所有的四个
activity
,再一次的到了前台。
当用户按
下
BACK
键的时候,屏幕不会显示出用户刚才离开的
activity
(上一个任务的根
activity
)。取而代之,当前任务的栈中最上面的
activity
被弹出,而同一任务中的上一
个
activity
显示了出来。
Activity
栈:先进后出规则
Android
系统是一个多任务<
/p>
(Multi-Task)
的操作系统,可以在用手机听音乐的同
时,也执
行其他多个程序。每多执行一个应用程序,就会多耗费一些系统内存,当同时执
行的程序
过多,或是关闭的程序没有正确释放掉内存,系统就会觉得越来越慢,甚至不稳
定。
为了解决这个问题,
Android
引入了一个新的机制
--
生命周期
(Life
Cycle)
。
Android
应用程序的生命周期是由
Android
框架进行管理,而不是由应用程序直接控
制。通常,每一个应用程序(入口一般会是一个
Activity
的
onCreate
方法),都会产生
一个进程
(Process)
。当系统内存即将不足的时候,会依照优先级自动进
行进程
(process)
的回收。不管是使用者或开发者,<
/p>
都无法确定的应用程序何时会被回收。所以为了很好的
防止数据丢失和其他问题,了解生命周期很重要。
Activity
生命周期
: