Android程序模块2

4、Intent
Intent   是对被执行操作的抽象描述。调用startActivity(Intent),可以启动 Activity;调用broadcastIntent(Intent),可以把Intent 发送给任何相关的
IntentReceiver 组件;调用startService(Intent, Bundle) 以及bindService(Intent, String, ServiceConnection, int)    可以让应用和后台服务进行通信。
Intent    提供了一个在不同应用的代码之间进行动态绑定(late runtime binding) 的机制。它主要被用来启动Activities,因此可以被看作是Activities之间的粘合剂。Intent 大体上是一个被动数据结构,该数据结构包括被执行动作的抽象描述。Intent 中的主要内容有:
action --    需要被执行的动作。比如VIEW_ACTION, EDIT_ACTION, MAIN_ACTION 等。
data --    执行动作要操作的数据,在Intent 里用指向数据记录的URI (ContentURI) 表示。比如联系人数据库中的一个联系人记录。

  除了action, data 两个主要属性,Intent 还具有一些其它属性,这些属性也可以被用在Intent    里:
category --    类别,被执行动作的附加信息。例如LAUNCHER_CATEGORY 表示Intent    的接受者应该在Launcher    中作为顶级应用出现;而ALTERNATIVE_CATEGORY 表示当前的Intent    是一系列的可选动作中的一个,这些动作可以在同一块数据上执行。
type --    数据类型,显式指定Intent    的数据类型(MIME)   。一般上Intent 的数据类型能够根据数据本身进行判定,但是通过设置这个属性,可以强制采用显式指定的类型而不 再进行推导。
component --    组件,为使用Intent    的组件类指定名称。通常会根据Intent 中包含的其它信息 比如action, data/type, categories —— 进行查找,最终找到一个与之匹配的组件。如果这个属性存在的话,将直接使用它指定的组件,不再执行上述查找过程。指定了这个属性以后,Intent    的其它所有属性都是可选的。
extras --    额外的附加信息,是其它所有附加信息的集合。使用extras 可以为组件提“ ” 供扩展信息,比如,如果要发送电子邮件,也就是要执行 发送电子邮件 的动作,可以将电子邮件的标题、正文等保存在extras    里。在Intent类里定义了多种标准action和category 常量(字符串),同时应用也可以根据自己的需要进行定义。
Intent    有两种主要形式:
显式意图:
显式意图是指定了 component   属 性的 intents 。 调 用 setComponent(ComponentName)    或者setClass(Context, Class)    可以为intents 设定component   ——    属性 指定具体的组件类。这些intents 一般不包括其它任何信息,它们通常只是用来通知应用启动内部的activities    作为该应用的(当前)用户界面。
隐式意图:
       隐式意图是没有指明comonent    的intents   。这些intents 必须包括足够的信息,这样系统才能确定在所有的可用组件中,对一个intent    来说运行哪一个组件才是最合适的。Intent    解析机制主要是将已安装应用程序包里的Intent-Filter    描述和Intent 进行匹配。如果使用广播发送Intent   ,还要在已经注册的IntentReceiver 中尽心匹配。更多的相关描述可以在IntentFilter    中找到。
  在解析Intent    的过程中要用到Intent 的三个属性:动作、数据类型和类别。使用这些属性,就可以PackageManager    上查询能够处理当前intent 的合适组件。组件是否合适 由AndroidManifest.xml    文件中提供的intent    信息决定。判断的方法如下:
如果intent    指明了要执行的action   ,组件action    列表中就必须包含着个action,否则不能匹配;
如果Intent    没有提供数据类型(type)   ,系统从数据(data) 中得到数据类型。和 action    一样,组件的数据类型列表中必须包含intent    的数据类型,否则不能匹配。
如果Intent    中的数据不是content:    类型的URL   ,而且Intent 也没有明确指定它的数据类型,将根据Intent   中数据的scheme (   比如http: or mailto:) 进行匹配。同上,Intent    的scheme    必须出现在组件的scheme    列表中。
如果Intent 指定了一个或多个类别,这些类别必须全部出现在组建的类别列表中。比如 intent   中 包 含 了两个 类别:LAUNCHER_CATEGORY   和 ALTERNATIVE_CATEGORY   ,解析得到的组件必须至少包含这两个类别。
5、Service
服务是在后台长时间运行的应用组件,不和用户直接进行交互。在每一个服务类在 AndroidManifest.xml     文件中,必须有一个相应的<service> 声明。服务必须用 
Context.startService()    或者Context.bindService()    启动。和其它应用对象一样,服务运行在它们宿主进程的主线程里。这意味着,如果一个服务 需要执行阻塞操作(比如网络操作)或者CPU    敏感的操作(比如MP3播放器),它应该 分离出一个线程来执行这样的操作。服务类是应用程序的生命周期中的一个重要部分。在
这里要讨论的内容有:
  服务的生命周期
  访问权限
  进程生命周期

服务的生命周期
  启动服务有两种方法。
  如果客户调用Context.startService(),系统将获得服务(如果服务不存在,系统创建服务,然后调用它的onCreate() 方法),然后使用调用者提供的参数调用服务的 onStart(int,   Bundle)  方 法。 从 此 以 后 ,服 务开始持续运 行 , 直 到 Context.stopService()     或 者 stopSelf()   被 调 用 。注 意: 多次调 用 Context.startService()虽然会导致onStart() 被多次调用,但是服务本身不会嵌套。所 以无论调用多少次Context.startService()   ,只要调用一次Context.stopService() 或者stopSelf()   ,服务就会停止运行。
 客户也可以调用Context.bindService() 获得到服务的永久连接。如果服务之前没有启动,一样会创建服务然后调用它的onCreate()    方法;但是不会调用它的onStart() 方 法。服务调用它的getBinder()    方法,并且将返回的IBinder 对象传递给客户。连接建立以后,不管客户是否保留这个IBinder 对象的引用,只要连接还存在,服务都会持续运行。通常返回的IBinder    对象是一个由AIDL    实现的复杂接口。服务可以同时被启动和绑定多个连接。在这种情况下,只要服务被启动,或者存在着到这个服务的连接,服务都会持续运行。当两个条件都不满足时,系统调用服务的 onDestroy()    方法,服务从此被终止。当onDestroy() 返回的时候,所有的清理工作(停止线程,取消已经注册的receivers   )都已经完成。

访问权限
  对服务的全局访问权限可以通过服务的manifest    中的<service> 元素指定。这样,其它应用需要在它们的manifest    中声明对应的<uses-permission> 元素,这样才能启动、停止和绑定到服务。同时,在执行IPC    调用之前,服务可以调用checkCallingPermission(String) 对这次IPC    调用的权限进行检查。进程生命周期
只要服务被启动或者被客户绑定(建立连接),Android 系统就尽可能维护一个进程来作这个服务的宿主。当系统内存不足的时候,系统需要杀死进程来出让内存。这时候在下列情况下,服务的宿主进程具有较高的优先级:
如果服务已经被启动,它的宿主进程比任何在屏幕上对用户可见的进程都具有更低的优先级;但是比其它所有不可见的进程都具有更高的优先级。通常对用户可见的进程的数量 非常少,所以正在运行的服务在绝大多数时候不会被杀死 除非系统的可用内存极其 匮乏。
如果有客户绑定在服务上,服务的宿主进程的优先级至少和客户的优先级一样(不会 比客户更低)。这意味着如果客户对用户可见,那么服务本身也会被系统认为对用户可见。在服务的宿主进程中运行有其它应用组件,比如activity,可以提高整个进程的优先 级,而不是仅仅提高服务本身的优先级。

6、NotificationManager
NotificationManager用来通知手机使用者有事件发生的类。用来告诉使用者在后台有一些事情发生了。
这些通知可以采用以下一些不同的方式:
1. 当时间发生时临时显示一个View对象。
2. 在状态栏上显示一个图标,并通过图标能过激活。
3. 打开或闪烁设备上的LED灯或者通过闪烁背光,播放声音,或者振动提示用户。

用两种方式可以在屏幕上显示一条消息,这个消息会在一段时间内消失:
notifyWithView(int, View, int, Notification)和notifyWithText(int, charSequence, int, Notification);
函数notifyWithText(int, charSequence, int, Notification)方法只是构造一个带提示文字的TextView对象。这些方法也产生了一个Notification对象,该对
象是你能够设定一个固定的提示方法和其它的一些属性。如果要使用一个Intent或状态栏单独的提示使用者,可以使用notify()方法。
当提示信息框(View  对象)被显示给使用者时,是作为一个浮动在当前应用(application)   之上的View 对象出现的。它永远不能接受焦点(focus),因为用户可能正在
录入信息或在做其它什么事情。尽管如此,当仍然显示你想给用户所看的信息时,一个好主意是尽量避免唐突。音量控制和短消息到达提示是两个可以考虑的。
  每一个通知方法都带一个整型的id    参数。从应用到系统这个id 参数唯一标识了这次通知,因此,在你的应用里要确保id 唯一。如果你调用一个通知方法,使用当前在用通知 的id    并且传递一组新的通知参数,则该通知将被更新。例如,你传递一个新的状态栏图标,位于状态栏的原先的图标将被新的代替。同样,传递同一个id   给cancel(int) 方法将清除该通知。

7、Android IDL
通常每个应用程序都在它自己的进程内运行,但有时需要在进程间传递对象,你可以通过应用程序UI的方式写个运行在一个不同的进程中的service。在AndRoid平台中,一个进程通常不能访问其它进程中的内存区域。AIDL为解决进程间通信提供了一套机制。
AIDL是一个IDL 语言,它可以生成一段代码,可以使在一个Android设备上运行的两个进程使用内部通信进程进行交互。如果你需要在一个进程中(例如:在一个Activity中)访问另一个进程中(例如:一个Service)某个对象的方法,你就可以使用AIDL来生成这样的代码来传递各种参数。
AIDL IPC的机制是基于接口的,和COM或Corba类似,但它是轻量级的。
下面介绍如何使用AIDL:
1. 创建你的AIDL文件,这个文件定义一个接口(YourInterface.aidl),该接口定义了可供客户端访问的方法和属性。注意AIDL的接口文件有一定的语法规则,但是十分简单。
2.如果你在Eclipse编写的话,这是会自动创建一个Java类,就是接口文件自动生成的符合Java   语法规则的接口类。
3   .实现接口方法-AIDL编译器从你的AIDL接口中使用JAVA编程语言来创建一个接口。这个接口有一个名为Stub的内部抽象类,它继承接口(并实现供IPC调用的所必需的几个附加方法)   。你必须创建一个类来实现该接口。
4   .向客户端开放接口-如果你写个service,你应该扩展该Service并重载getBinder()   方法来返回一个实现上述接口的类的实例。

AIDL语法简单,你可以用来声明一个带一个或多个方法的接口,也可以传递参数和返回值。这些参数和返回值可以是任何类型,甚至是其它的AIDL生成的接口。然而,值得重视的是你必须导入所有的non-bult-in   类型,即使他们已经作为接口在其它包里定义了。

以下代码是AIDL的一个例子:
package com.google.android.sample;
interface MDSInterface {
void playFile( in int position );
};
AIDL生成一个接口文件,文件名和你的AIDL文件名一致。如果你使用的是Eclipse插件,AIDL会作为build过程的一部分自动运行。生成的接口包括一个名为Stub的内部抽象类,该类声明了你在aidl   文件中声明的所有方法。实现接口,具体代码如下:
MDSInterface.Stub mBinder = new MDSInterface.Stub() {
void playFile( int position) {
     //To-do sth.
}
};
实现接口时有几个原则: 
抛出的异常不要返回给调用者。
IPC调用是同步的。如果你知道一个IPC服务需要超过几毫秒的时间才能完成地话,
你应该避免在Activity/View线程中调用。
只有方法才获得支持,换句话就是不支持变量。
你不能在AIDL接口中声明静态属性。
现在你已完成了接口的实现,你需要向客户端公开该实现。这就是我们所熟悉的"发布服务"。发布一个Service,然后继承Service并实现getBinder()返回一个实
现的类的实例。下面是个Service的代码片断,该Service向客户端公了MDSInterface   接口。
public class MDService extends Service {
public IBinder onBind(Intent intent) {
return mBinder;
}
        private final MDSInterface.Stub mBinder = 
                                             new MDSInterface.Stub() {
}
 }
    现在被调用者已经全部实现了,接下来就是如何实现调用者端的操作了。
    下面是调用的代码:
public class MusicDroid extends Activity {
private MDSInterface mpInterface;
public void onCreate(Bundle icicle) {
//------------------------------------------bindService(new Intent(MusicDroid.this, 
MDService.class),
mConnection, Context.BIND_AUTO_CREATE);
        }
        private ServiceConnection mConnection = new 
ServiceConnection() 
            {
  public void onServiceConnected(ComponentName className, 
                IBinder service) {
mpInterface = MDSInterface.Stub.asInterface((IBinder) 
service);
}
public void onServiceDisconnected(ComponentName className) {
mpInterface = null;
}
};
}
从调用的代码可以看出,要想调用Service时,必需还要有一个工具类ServiceConnection,这个可以有两个必须要实现的函数,分别是:
public void onServiceConnected(ComponentName className, 
IBinder service) {}
此函数在系统启动Service时调用,进行必要时初始化。
public void onServiceDisconnected(ComponentName className){}
此函数在系统断开Service时调用,进行必要的析构操作。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值