首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网络技术 > 网络基础 >

android札记-Service与AIDL

2012-07-15 
android笔记--Service与AIDL[coolxing按: 转载请注明作者和出处, 如有谬误, 欢迎在评论中指正.]?Service是

android笔记--Service与AIDL

[coolxing按: 转载请注明作者和出处, 如有谬误, 欢迎在评论中指正.]

?

Service是android中的服务组件, 经常用来执行一些运行在后台的耗时操作. 使用一个Service需要继承Service类, 并根据需要重写生命周期方法. Service的生命周期如下:

android札记-Service与AIDL

|--?public abstract?IBinder?onBind?(Intent?intent): 该方法是一个抽象方法, 因此Service子类必须实现这个方法. 它返回一个IBinder对象, 应用程序可以通过这个对象与Service组件通信(关于这一点, 其后会有详细的讲解), 以bindService()方式启动Service时回调该方法.

|--?public void?onCreate?(): 当Service第一次被创建后回调的方法.

|--?public void?onDestroy?(): Service关闭之前回调的方法.

|--?public int?onStartCommand?(Intent?intent, int flags, int startId): 以startService(Intent intent)的方式启动Service时, 系统都会回调该方法.

|--?public boolean?onUnbind?(Intent?intent): 当所有绑定该Service的组件都断开连接时回调该方法.

?

从图中可以看出, Service可以有两种启动方式:

1. 以startService(Intent intent)的方式启动. 此时启动的Service与调用者之间没有关联, 即使调用者已经退出, Service仍然可以继续运行, 而且调用者和Service之间无法进行数据交换和通信. 如果需要停止Service的运行, 只能调用Context类的stopService(intent)方法, 或者由Service本身调用其stopSelf()等方法.

2. 以bindService(Intent?service,?ServiceConnection?conn, int flags)的方式启动.

此时调用者与Service绑定在一起, 如果调用者退出, 则Service也随之退出, 而且调用者和Service之间可以进行数据交换或通信.

根据调用者和Service是否在一个应用程序内, 可以将调用者和Service之间的通信分为进程内通信和进程间通信.

?

?

a. 进程内通信. bindService(Intent service, ServiceConnection conn, int flags)方法的第二个参数为ServiceConnection对象, 最后一个参数通常可以是Service.BIND_AUTO_CREATE. ServiceConnection是一个接口, 该接口包含2个方法:

|-- onServiceConnected(ComponentName name, IBinder service): 该方法在调用者和Service成功绑定之后由系统回调.

方法中的第一个参数ComponentName是所绑定的Service的组件名称, 而IBinder对象就是Service中onBinder()方法的返回值. 要实现调用者和Service之间的通信, 只需要调用IBinder对象中定义的方法即可.

|-- onServiceDisconnected(ComponentName name): 该方法在调用者解除和Service的绑定之后由系统回调.

以下是利用Service实现进程内通信的一个例子.

首先自定义Service类:

?

public class MyService extends Service {public class MyBinder extends Binder {/** * 获取Service的运行时间 * @return */public long getServiceRunTime() {return System.currentTimeMillis() - startTime;}}private long startTime;/** * MyBinder是Binder的子类, 而Binder实现了IBinder接口. */@Overridepublic IBinder onBind(Intent intent) {return new MyBinder();}@Overridepublic void onCreate() {super.onCreate();startTime = System.currentTimeMillis();}}
?

然后在activity中绑定上述的Service:

?

public class MainActivity extends Activity {private MyBinder binder = null;/** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);// 创建一个指向MyService的intentIntent intent = new Intent("cn.xing.action.my_service");this.bindService(intent, new MyServiceConnection(),Service.BIND_AUTO_CREATE);Button button = (Button) this.findViewById(R.id.button);button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (binder != null) {Toast.makeText(getApplicationContext(), "MyService已经运行了" + binder.getServiceRunTime()+ "毫秒", Toast.LENGTH_LONG).show();} }});}/** * 实现ServiceConnection接口 *  * @author xing *  */private final class MyServiceConnection implements ServiceConnection {/** * 和MyService绑定时系统回调这个方法 */@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// MyService中的onBinder()方法的返回值实际上是一个MyBinder对象, 因此可以使用强制转换.binder = (MyBinder) service;}/** * 解除和MyService的绑定时系统回调这个方法 */@Overridepublic void onServiceDisconnected(ComponentName name) {// 解除和MyService的绑定后, 将binder设置为null.binder = null;}}}
?

b.进程间通信. 调用者和Service如果不在一个进程内, 就需要使用android中的远程Service调用机制.

android使用AIDL定义进程间的通信接口. AIDL的语法与java接口类似, 需要注意以下几点:

1. AIDL文件必须以.aidl作为后缀名.

2. AIDL接口中用到的数据类型, 除了基本类型, String, List, Map, CharSequence之外, 其他类型都需要导包, 即使两种在同一个包内. List和Map中的元素类型必须是AIDL支持的类型.

3. 接口名需要和文件名相同.

4. 方法的参数或返回值是自定义类型时, 该自定义的类型必须实现了Parcelable接口.

5. 所有非java基本类型参数都需要加上in, out, inout标记, 以表明参数是输入参数, 输出参数, 还是输入输出参数.

6. 接口和方法前不能使用访问修饰符和static, final等修饰.

?

下面通过一个例子来演示android远程Service调用机制的各个步骤:

1. 创建remoteService项目.

2. 在cn.xing.remoteservice包下定义aidl文件--IRemoteService.aidl:

?

package cn.xing.remoteservice;interface IRemoteService{int getServiceRunTime();}

Eclipse的ADT插件会在gen目录的cn.xing.remoteservice包下自动根据aidl文件生成IRemoteService接口.?

接口中有一个static的抽象内部类Stub, Stub类继承了Binder类并实现了IRemoteService接口. Stub类有如下的静态方法:

public static cn.xing.remoteservice.IRemoteService asInterface(android.os.IBinder obj)

该方法接受一个IBinder对象, 返回值是IRemoteService的instance, 通过这个instance我们就可以调用IRemoteService中定义的方法了.

3. 在remoteService项目的cn.xing.remoteservice包下创建远程服务类RemoteService:

?

public class RemoteService extends Service {private long startTime;/** * IRemoteService.Stub类实现了IBinder和IRemoteService接口 * 因此Stub的子类对象可以作为onBinder()方法的返回值. * @author xing * */public class MyBinder extends IRemoteService.Stub {@Overridepublic long getServiceRunTime() throws RemoteException {return System.currentTimeMillis() - startTime;}};@Overridepublic IBinder onBind(Intent intent) {return new MyBinder();}@Overridepublic void onCreate() {super.onCreate();startTime = System.currentTimeMillis();}}

4. 创建一个新的android项目invokeRemoteService, 并复制remoteService项目中的aidl文件(连同包结构一起复制)到invokeRemoteService项目中.

5. 在invokeRemoteService项目中绑定远程服务, 并调用远程方法.

?

public class MainActivity extends Activity {private IRemoteService iRemoteService = null;/** Called when the activity is first created. */@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.main);// 创建一个指向RemoteService的intentIntent intent = new Intent("cn.xing.action.remote_service");this.bindService(intent, new MyServiceConnection(),Service.BIND_AUTO_CREATE);Button button = (Button) this.findViewById(R.id.button);button.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if (iRemoteService != null) {try {Toast.makeText(getApplicationContext(), "MyService已经运行了" + iRemoteService.getServiceRunTime()+ "毫秒", Toast.LENGTH_LONG).show();} catch (RemoteException e) {e.printStackTrace();}} }});}/** * 实现ServiceConnection接口 *  * @author xing *  */private final class MyServiceConnection implements ServiceConnection {/** * 和RemoteService绑定时系统回调这个方法 */@Overridepublic void onServiceConnected(ComponentName name, IBinder service) {// 此处不能使用强制转换, 应该调用Stub类的静态方法获得IRemoteService接口的实例对象iRemoteService = IRemoteService.Stub.asInterface(service);}/** * 解除和RemoteService的绑定时系统回调这个方法 */@Overridepublic void onServiceDisconnected(ComponentName name) {// 解除和RemoteService的绑定后, 将iRemoteService设置为null.iRemoteService = null;}}}

?

附件中包含进程内通信和进程间通信例子的源码, 需要的朋友可自行下载查看.

?

不错的知识! 不错的知识!
开博以来, 你是第一个留言的. 谢谢.
有的时候觉得iteye上的朋友真是不够意思, 好像都很吝啬自己的评论. 3 楼 Jefry 2011-11-27   写的很好 我希望成为第二个留言的 4 楼 z303729470 2012-02-08   嗯,写的不错,学习了 5 楼 liuwuping1206 2012-03-04   初学者表示说非常不错  呵呵。。。 6 楼 yun2223 2012-06-08   楼主辛苦了  不够意思的朋友要回复了呵呵

热点排行