Android面试系列之二
11, 谈谈对service的理解?
Service,服务。幕后工作者,甘心做绿叶。默默为前台提供支持。Android的核心三组件可以通过电视台进行比喻,电视播放画面可以看作Activity,用户可以通过遥控器切换不同的电视台可以看做是不同Activity之间的切换。电视播放的新闻可以看做是广播发送方,每个观众都是接收者。而电视幕后工作者可以看做是Service,从不抛头露面。默默为Activity提供所需要的内容。
说到Service,我们最熟悉莫过于windows中的服务。他们都是在后台长时间运行,接受上层指令,完成相关操作。但android中的service与其他的服务还是有所差别的,service与其他三个组件一样,其进程模型都是可以通过XML进行配置的。调用方和发布方都可以有权利来选择是把这个组件运行在同一个进程下,还是不同的进程下。如果一个Service,是有期望运行在于调用方不同进程的时候,就需要利用Android提供的RPC(Remote Procedure Call Protocol)机制,为其部署一套进程间通信的策略。当然这些策略android已经为你封装好了。你需要了解底层。直接拿来使用即可。RPC其实就是代理模式的一种实现,在调用端和服务端都去生成一个代理类,做一些序列化和反序列化的事情,使得调用端和服务器端都可以像调用一个本地接口一样使用RPC接口。
Android中用来做数据序列化的类是Parcel,封装了序列化的细节,向外提供了足够对象化的访问接口
AIDL (Android Interface Definition Language) ,一种接口定义的语言,服务的RPC接口,可以用AIDL来描述, ADT帮助你自动生成一整套的代理模式需要用到的类,不要要你自己写。下面会给个例子。
12, service的生命周期?
在有生命周期的这几个组件中,Service的生命周期最长,其次是Activity最后Receiver。
Service的生命周期相对Activity简单一些。Service提供了两种启动service的方式,每一种方式对应一套生命周期方法。以下是android提供的图片:
1) 以startService()方式启动的服务,它的生命周期如下:
onCreate()->onStartCommand()这时服务已经开启,如果再点击一下启动则只会调用onStartCommand()。这说明service是单例的,只实例化一次。点击停止按钮调用onDestroy()。销毁。生命周期完成。以下为图示:
onCreate()->onBind() 此时服务绑定。再次绑定则无响应。解除绑定:onUnbind()->onDestroy()。生命周期完成。如图所示: 13, 启动service的两种方法?有什么区别? 一种是startService(),另一种是bindService()。这两者的区别是第一种方式调用者开启了服务,即会与服务失去联系,两者没有关联。即使访问者退出了,服务仍在运行。如需解除服务必须显式的调用stopService方法。主要用于调用者与服务没有交互的情况下,也就是调用者不需要获取服务里的业务方法。比如电话录音。而后者调用者与服务绑定在一起的。当调用者退出的时候,服务也随之退出。用于需要与服务交互。 14, 实现进程内与进程间通信是怎么实现的? 在linux中进程通信机制有很多种,比如:消息队列(message queue),socket,共享内存(share mermory)等等。但是在Android中,无论是进程内还是进程间,所采用的通信机制,主要是以Binder为核心。Android之所以选择是Binder作为进程的通信机制,主要是Binder与其他通信方式相比更加快速和简洁,所消耗的内存也是相对较少。当然也有其他方面的原因,比如传统进程通信有可能会增加进程开销,也有安全方面的风险。Binder能解决这些问题。故成为首选的通信方式。 1) 进程内的通信,与进程间的通信相比,相对容易些。进程内通信肯定要采用绑定的方式开启服务。这样才能与服务进行交互。绑定服务的方法: bindService(Intent service, ServiceConnection conn, int flags) 这个方法的第一个参数很好理解。用于激活哪个服务,第二个参数是关键,服务的连接,这是一个接口,用于接收服务开启或者关闭时返回的数据。实现这个接口要重写两个方法: onServiceConnected(ComponentName name, IBinder service):一旦客户端与服务端绑定成功,将有这个方法的第二个参数接收服务端返回的IBinder对象。得到服务端的引用就可以在客户端调用服务里的一些业务方法。这也是进程内通信的主要部分。 onServiceDisconnected(ComponentName name):这个方法在服务断开是调用,服务被销毁或者被干掉时调用。附件处有例子。 2) 进程之间的通信,其主要的核心机制同样是Binder。其实Binder底层就是通过Parcel(邮包)来完成数据传输的。进程内通信可以通过IBinder对象来实现业务共享的,但是进程间的通信这种方式就肯定不行了。这时就用到了AIDL。 AIDL是一种接口定义语言,用于约束两个进程间的通讯规则,供编译器生成代码,实现Android设备上的两个进程间通信(IPC).AIDL的IPC机制和EJB所采用的CORBA很类似,进程之间的通信信息,首先会被转换成AIDL协议消息,然后发送给对方,对方收到AIDL协议消息后再转换成相应的对象.由于进程之间的通信信息需要双向转换,所以android采用代理类在背后实现了信息的双向转换,代理类由android编译器生成,对开发人员来说是透明的. 使用方式如下: 定义AIDL. //XXXService.aidl,注意扩展名 package com.iteye.androidtoast; interface XXXService { void sayHello(in/out/inout String name);//in|out|inout是参数的方向 } ide会自动在gen包下生成对应的java类,接口文件中生成一个Stub的抽象类,里面包括aidl定义的方法,还包括一些其它辅助方法.值得关注的是asInterface(IBinder iBinder),它返回接口类型的实例,对于远程服务调用,远程服务返回给客户端的对象为代理对象,客户端onServiceConnected(ComponentName name, IBinder service)方法引用该对象时不能直接强转成接口类型的实例,而应该使用asInterface(IBinder iBinder)进行类型转换. AIDL定义注意事项: (1)接口名和aidl文件名相同. (2)接口和方法前不用加访问权限修饰符public,private,protected等,也不能用final,static. (3)AIDL默认支持的类型包话java基本类型(int,long,boolean等)和(String,List,Map, CharSequence),使用这些类型时不需要import声明.对于List和Map中的元素类型必须是AIDL支持的类型.如果使用自定义类型作为参数或返回值,自定义类型必须实现Parcelable接口. (4)自定义类型和AIDL生成的其它接口类型在aidl描述文件中,应该显式import,即便在该类和定义的包在同一个包中. (5)在aidl文件中所有非Java基本类型参数必须加上in、out、inout标记,以指明参数是输入参数、输出参数还是输入输出参数. (6)Java原始类型默认的标记为in,不能为其它标记. 具体步骤: 1.创建服务器android项目(server) 2.创建服务类.CustomerService /** * 服务类 */ public class CustomerService extends Service { ... } 3.配置清单注册服务类 <!-- 注册服务 --> <service android:name=". CustomerService " /> 4.定义aidl文件. ICustomerService.aidl package com.iteye.androidtoast.aidl; interface ICustomerService { String sayHello(String name); } 5.ide在gen目录下自动生成java接口. 6.需要实现CustomerService.onBind()方法的返回值. public IBinder onBind(Intent intent) { return new ICustomerService.Stub() { public String sayHello(String name) throws RemoteException { return "hello " + name; } }; } 7.创建客户端项目(android项目) 8.复制服务端项目aidl文件到客户端(连同包结构一同复制),同样在客户端项目中 也会生成对应的接口类.同步骤(5). 9.绑定服务. class CustomerConnection implements ServiceConnection{ public void onServiceConnected(ComponentName name, IBinder service) { is = ICustomerService.Stub.asInterface(service); } public void onServiceDisconnected(ComponentName name) { } } 10.绑定服务 Intent i = new Intent(); i.setAction(“”) this.bindService(i, conn, BIND_AUTO_CREATE); 11,调用远程服务方法
2) 以bindService()方式启动服务。调用方式如下:
上一篇: <转>六种习惯提升大脑能力
下一篇: 7种大数据方案重塑医疗行业
推荐阅读
-
Android属性动画Property Animation系列一之ObjectAnimator_html/css_WEB-ITnose
-
JAVA/JSP学习系列之二(Tomcat安装)
-
Microsoft .Net Remoting系列教程之二:Marshal、Disconnect与生命周期以及跟踪服务
-
Android控件系列之EditText使用方法
-
Android控件系列之ImageView使用方法
-
Android控件系列之Button以及Android监听器使用介绍
-
Android控件系列之XML静态资源使用介绍
-
Android控件系列之Toast使用介绍
-
Android控件系列之相册Gallery&Adapter适配器入门&控件缩放动画入门
-
Android控件系列之RadioButton与RadioGroup使用方法