第5章Android服务(Service).ppt

上传人:feelhesitate105 文档编号:373666 上传时间:2018-10-05 格式:PPT 页数:47 大小:1.98MB
下载 相关 举报
第5章Android服务(Service).ppt_第1页
第1页 / 共47页
第5章Android服务(Service).ppt_第2页
第2页 / 共47页
第5章Android服务(Service).ppt_第3页
第3页 / 共47页
第5章Android服务(Service).ppt_第4页
第4页 / 共47页
第5章Android服务(Service).ppt_第5页
第5页 / 共47页
亲,该文档总共47页,到这儿已超出免费预览范围,如果喜欢就下载吧!
资源描述

1、第5章 Android服务(Service),网络资源:http:/ Service概述,文本,5.1.1 Service介绍,Service是android 系统中的一种组件,它跟Activity的级别差不多,它们都是从Context派生出来的,但是它不能自己运行,只能在后台运行,并且可以和其它组件进行交互。它需要通过某一个Activity或者其他Context对象来调用。,5.1.2 启动Service的两种方式,在Android系统中,常采用以下两种方式启动Service.(1)通过Context的startService()启动service后,访问者与service之间没有关联,该s

2、ervice将一直在后台执行,即使调用startservice的进程结束了,service仍然还存在,直到有进程调用stopService(),或者service自己停止(stopSelf)。这种情况下,service与访问者之间无法进行通信,数据交换,往往用于执行单一操作,并且没有返回结果。例如通过网络上传,下载文件,操作一旦完成,服务应该自动销毁。(2)通过Context的bindService()绑定Service,绑定后Service就和调用bindService的组件同生共死了。也就是说当调用bindService()的组件销毁了,那么它绑定的Service也要跟着被结束,当然期间也

3、可以调用unbindservice()让Service提前结束。注意:一个服务可以与多个组件绑定,只有当所有的组件都与之解绑后,该服务才会被销毁。,5.1.2 启动Service的两种方式,以上两种方法可以混合使用,即一个Service既可以启动也可以绑定,只需要同时实现onStartedCommand()(用于启动)和onBind()(用于绑定)方法,那么只有调用stopService(),并且调用unbindService()方法后,该Service才会被销毁。 注意:服务运行在它所在进程的主线程,服务并没有创建它自己的线程,也没有运行在一个独立的进程上(单独指定的除外),这意味着,如果你

4、的服务做一些消耗CPU或者阻塞的操作,你应该在服务中创建一个新的线程去处理。通过使用独立的线程,你就会降低程序出现ANR(Application No Response程序没有响应)的风险,程序的主线程仍然可以保持与用户的交互。,5.1.3 Service中常用方法,与开发其它Android组件类似,开发Service组件需要先开发一个Service子类,该类需继承系统提供的Service类,系统中Service类包含的方法主要有: abstract IBinder onBind(Intent intent):该方法是一个抽象方法,所有Service子类必须实现该方法。该方法将返回一个IBin

5、der对象,应用程序可通过该对象与Service组件通信; void onCreate():当Service第一次被创建时,将立即回调该方法; void onDestroy():当Service被关闭之前,将回调该方法; void onStartCommand(Intent intent,int flags,int startId):每次客户端调用startService(Intent intent)方法启动该Service时都会回调onStartCommand()方法; boolean onUnbind(Intent intent):当该Service上绑定的所有客户端都断开连接时将会回调该

6、方法。,开发Service组件需要先开发一个Service子类,然后在AndroidManifest.xml文件中配置该Service,配置时可通过元素指定它可被哪些Intent启动。,在AndroidManifest.xml文件中配置Service:,Action中的值一定要与程序中创建的Intent的Action的值一致,程序就是根据Action的值来查找相应的Service从而启动它。,5.1.3 Service中常用方法,通过Context的startService()启动Service后,访问者与Service之间没有关联,该Service将一直在后台执行,即使调用startServ

7、ice()的进程结束了,Service仍然还存在,直到有进程调用stopService(),或者Service自己自杀(stopSelf())。这种情况下,Service与访问者之间无法进行通信、数据交换。,通过Context的bindService()绑定Service后,Service就和 调用bindService()的组件同生共死了,也就是说当调用 bindService()的组件销毁了,那么它绑定的Service也要跟着被结束。,5.1.2 Service中常用方法简介,案例:FirstService,定义的Service子类必须实现onBind()方法,然后还需在AndroidMa

8、nifest.xml文件中对该Service子类进行配置,配置时可通过元素指定它可被哪些Intent启动。下面具体来创建一个Service子类并对它进行配置,代码如下。,程序清单:/FirstService/src/iet/jxufe/cn/android/MyService.java,public class MyService extends Service private static final String TAG = “MyService“;public IBinder onBind(Intent arg0) Log.i(TAG, “MyService onBind invoked

9、!“);return myBinder; public void onCreate() Log.i(TAG, “MyService onCreate invoked!“);super.onCreate(); public void onDestroy() Log.i(TAG, “MyService onDestroy invoked!“);super.onDestroy();quit=true; public int onStartCommand(Intent intent, int flags, int startId) Log.i(TAG, “MyService onStartComman

10、d invoked!“);return super.onStartCommand(intent, flags, startId); ,自定义服务类,重写OnBind方法,重写OnCreate方法,重写OnDestory方法,重写OnStartCommand方法,案例:FirstService,在上述代码中,创建了自定义的MyService类,该类继承了Android.app.Service类,并重写了onBind(),onCreate(),onStartCommand(),onDestory等方法,在每个方法中,通过LOG语句测试和查看该方法是否被调用。,定义完Service之后,还需在项目的

11、AndroidManifest.xml文件中配置该Service,增加配置片段如下。,虽然目前MyService已经创建并注册了,但系统仍然不会启动MyService,要想启动这个服务。必须显示地调用startService()方法。如果想停止服务,需要显示地调用stopService()方法,下面代码中,使用Activity作为Service的启动者,分别定义了启动Service和关闭Service两个按钮,并为它们添加了事件处理。,程序清单:/FirstService/src/iet/jxufe/cn/android/MainActivity.java,public class MainA

12、ctivity extends Activity public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);start=(Button)findViewById(R.id.start);stop=(Button)findViewById(R.id.stop);final Intent intent=new Intent();intent.setAction(“.android.MyService“);start

13、.setOnClickListener(new OnClickListener() public void onClick(View v) startService(intent); );stop.setOnClickListener(new OnClickListener() public void onClick(View v) stopService(intent); ); ,案例:FirstService,案例:FirstService,运行本节的例子后,第一次单击【启动Service】按钮后,在DDMS视图下的LogCat视图有如下图所示的输出。,然后单击【关闭Service】按钮,

14、LogCat视图有如下图所示的输出。,下面按如下的单击顺序,重新测试一下本例。【启动Service】【启动Service】【启动Service】【停止Service】测试完程序,查看LogCat控制台输出信息如下图所示。系统只在第一次单击【启动Service】按钮时调用onCreate()和onStartCommand()方法,再单击该按钮 时,系统只会调用onStartCommand()方法,而不会重复调用onCreate()方法。,5.1.4 绑定Service过程,Context的bindService()方法的完整方法签名为:bindService(Intent service,Ser

15、viceConnection conn, int flags),该方法的三个参数解释如下: service:该参数表示与服务类相关联的Intent对象,用于指定所绑定的Service应该符合哪些条件; conn:该参数是一个ServiceConnection对象,该对象用于监听访问者与Service之间的连接情况。当访问者与Service之间连接成功时,将回调该ServiceConnection对象的onServiceConnected(ComponentName name,IBinder service)方法;当访问者与Service之间断开连接时将回调该ServiceConnection对

16、象的onServiceDisconnected(ComponentName name)方法。 flags:指定绑定时是否自动创建Service(如果Service还未创建)。该参数可指定BIND_AUTO_CREATE(自动创建)。,当开发Service类时,该Service类必须提供一个onBind()方法,在绑定本地Service的情况下,onBind()方法所返回的IBinder对象将会传给ServiceConnection对象里onServiceConnected(ComponentName name,IBinder service)方法的service参数,这样访问者就可以通过IBi

17、nder对象与Service进行通信。实际开发时通常会采用继承Binder(IBinder的实现类)的方式实现自己的IBinder对象。,5.1.4 绑定Service过程,5.1.4 绑定Service案例,在上一个案例中,添加两个按钮,一个用于绑定服务,一个用于解绑,然后分别为其添加事件处理。在绑定服务时,需要传递一个ServiceConnection对象,所以先创建该对象,代码如下。,private ServiceConnection conn=new ServiceConnection() public void onServiceDisconnected(ComponentName

18、name) Log.i(TAG,“MainActivity onServiceDisconnected invoked!“); public void onServiceConnected(ComponentName name, IBinder service) Log.i(TAG,“MainActivity onServiceConnected invoked!“);myBinder=(MyBinder)service;,程序清单:/FirstService/src/iet/jxufe/cn/android/MainActivity.java,5.1.4 (绑定Service案例),然后在M

19、yService中添加两个与绑定Service相关的方法,onUnBind()和onRebind(),与其他方法类似,只是在方法体重打印出该方法被调用了信息,代码如下。,public boolean onUnbind(Intent intent) Log.i(TAG, “MyService onUnbind invoked!“);return super.onUnbind(intent);public void onRebind(Intent intent) Log.i(TAG, “MyService onRebind invoked!“);super.onRebind(intent);,程序

20、清单:/FirstService/src/iet/jxufe/cn/android/MyService.java,5.1.4 (绑定Service案例),最后在MainActivity中为绑定Service和解绑Service按钮添加事件处理,代码如下。,public class MainActivity extends Activity public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);bind=(B

21、utton)findViewById(R.id.bind);unbind=(Button)findViewById(R.id.unbind);final Intent intent=new Intent();intent.setAction(“.android.MyService“);bind.setOnClickListener(new OnClickListener() public void onClick(View v) bindService(intent, conn,Service.BIND_AUTO_CREATE); ); unbind.setOnClickListener(ne

22、w OnClickListener() public void onClick(View v) unbindService(conn); );,程序清单:/FirstService/src/iet/jxufe/cn/android/MainActivity.java,5.1.4 (绑定Service案例),程序执行后,单击绑定Service按钮,LogCat控制台打印信息如下图所示,首先调用onCreate()方法,然后调用onBind()方法。,程序执行后,单击解绑Service按钮,LogCat控制台打印信息如下图所示,首先调用onUnbind()方法,然后调用onDestory()方法。

23、,程序运行后,单击绑定Service按钮,然后退出程序,LogCat控制台打印信息如下图。可以看出,程序退出后,Service会自动退出。,5.1.4 (绑定Service案例),当单击绑定Service按钮后,再重复多次单击绑定Service按钮,查看控制台打印信息,发现程序并不会多次调用onBind()方法。,采用绑定服务的另一个优势是组件可以与Service之间进行通信,传递数据。这主要是通过IBinder对象进行的,因此需在Service中创建一个IBinder对象,然后让其作为onBind()方法的返回值返回,对数据的操作是放在IBinder对象中的。修改我们的MyService类,

24、添加一个内部类MyBinder,同时在onCreate()方法中启动一个线程,模拟后台服务,该线程主要是做数据递增操作,在MyBinder类中,提供一个方法,可以获取当前递增的值(count的值),具体代码如下。,程序清单:/FirstService/src/iet/jxufe/cn/android/MyService.java,5.1.4 (绑定Service案例),public class MyService extends Service private static final String TAG = “MyService“;private int count=0;private b

25、oolean quit=false;private MyBinder myBinder=new MyBinder();public class MyBinder extends Binder public MyBinder() Log.i(TAG, “MyBinder Constructure invoked!“);public int getCount() return count; public IBinder onBind(Intent arg0) Log.i(TAG, “MyService onBind invoked!“);return myBinder; public void o

26、nCreate() Log.i(TAG, “MyService onCreate invoked!“);super.onCreate();,线程中循环是否停止的标志,创建自定义的MyBinder对象,MyBinder的构造方法,观察什么时候创建,MyBinder中提供的获取数据的方法,重写onBind()方法, 返回创建的对象,5.1.4 (绑定Service案例),new Thread()public void run()while(!quit)tryThread.sleep(500);count+;System.out.println();catch (Exception e) e.pri

27、ntStackTrace(); .start();public void onDestroy() Log.i(TAG, “MyService onDestroy invoked!“);super.onDestroy();quit=true;,判断是否继续执行循环,休眠0.5秒,数据递增,改变循环是否退出的标志,否则子线程一直在循环,5.1.4 (绑定Service案例),接着在MainActivity中添加一个获取数据的按钮,获取数据的前提是要绑定Service,所以先绑定Service,在ServiceConnection()对象的onServiceConnected()方法中,获取绑定Se

28、rvice时,返回的IBinder对象,然后将该对象强制类型转换成MyBinder对象,最后利用MyBinder对象获取服务中的数据信息。首先改写创建ServiceConnection对象的方法,关键代码如下。,private ServiceConnection conn=new ServiceConnection() public void onServiceDisconnected(ComponentName name) Log.i(TAG,“MainActivity onServiceDisconnected invoked!“); public void onServiceConnec

29、ted(ComponentName name, IBinder service) Log.i(TAG,“MainActivity onServiceConnected invoked!“);myBinder=(MyBinder)service;,程序清单:/FirstService/src/iet/jxufe/cn/android/MainActivity.java,将传递的参数强制类型装换成MyBinder对象,5.1.4 (绑定Service案例),然后,为获取数据按钮添加事件处理方法,关键代码如下。,getData.setOnClickListener(new OnClickListen

30、er() public void onClick(View v) Toast.makeText(MainActivity.this, “Count=“+myBinder.getCount(), Toast.LENGTH_LONG).show(); );,程序清单:/FirstService/src/iet/jxufe/cn/android/MainActivity.java,以消息的形式,显示获取的数据,此时,单击绑定服务后,LogCat控制台打印信息如下图,首先创建MyBinder对象,因为该对象是作为MyService的成员变量进行创建的,完成MyService的初始化工作,然后再调用on

31、Create()方法,再调用onBind()方法,该方法返回一个IBinder对象,因为IBinder对象不为空,表示有服务连接,所以会调用ServiceConnection借口的onServiceConnected()方法,并将调用IBinder对象它的第二个参数。,案例总结,1、通过Context的startService()方法启动和停止Service 2、通过Context的bindService()方法绑定和解除绑定 3、两种方式混合使用,案例总结,两种方式混合使用时,方法的执行顺序是怎么样的?,问题与讨论,1、先启动后绑定,2、先绑定后启动,案例总结,1)先启动Service,然后

32、绑定Service。测试步骤:【启动Service】【绑定Service】【启动Service】【停止Service】【绑定Service】【解绑Service】。,总结:调用顺序如下:onCreate()onStartCommand()1到N次 onBind() onServiceConnected()onUnbind() onServiceConnected()onRebind()0到N次onDestroy()。,控制台信息如下图所示。,案例总结,2)先绑定Service,后启动Service。测试步骤:【绑定Service】【启动Service】【绑定Service】【解绑Service

33、】【启动Service】【停止Service】。,总结:调用顺序如下:onCreate()onBind()onServiceConnected() onStartCommand() 1到N次onUnBindonServiceConnected() onRebind()0到N次onUnBindonDestroy()。,控制台信息如下图所示。,案例总结,注意: (1)未启动Service而直接停止Service不起作用,但未绑定Service而先解绑Service则程序出错,强制退出; (2)若该Service处于绑定状态下,该Service不会被停止即单击停止按钮不起作用,当单击解绑Servic

34、e按钮时,它会先解除绑定随后直接销毁; (3)若在解除之前,没有单击停止Service,则只解绑而不会销毁。,5.1.5 Service的生命周期,每当Service被创建时会回调onCreate()方法,每次Service被启动时都会回调onStartCommand()方法,多次启动一个已有的Service组件将不会再回调onCreate()方法,但每次启动时都会回调onStartCommand()方法。,绑定服务的执行过程:执行单击事件方法根据Intent找到相应的Service类,并初始化该类调用Service的onCreate()方法调用该类的onBind()方法调用onService

35、Connected()方法。多次单击绑定服务按钮,并不会重复执行绑定方法。一旦解绑,调用onunBind()方法,然后自动销毁。,5.2 跨进程调用Service,AIDL是一种接口定义语言,用于约束两个进程间通信规则,供编译器生成代码,实现Android设备上的两个进程间通信(IPC)。 进程之间的通信信息,首先会被转换成AIDL协议消息,然后发送给对方,对方收到AIDL协议消息后再转换成相应的对象。 由于进程之间的通信信息需要双向转换,所以android采用代理类在背后实现了信息的双向转换,代理类由android编译器生成,对开发人员来说是透明的。,AIDL:Android Interfa

36、ce Definition Language,5.2.1 什么是AIDL服务,客户端访问Service时,Android并不是直接返回Service对象给客户端,Service只是将一个回调对象(IBinder对象)通过onBind()方法回调给客户端。与绑定本地Service不同的是,本地Service的onBind()方法会直接把IBinder对象本身传给客户端的ServiceConnection的onServiceConnected方法的第二个参数。但远程Service的onBind()方法只是将IBinder对象的代理传给客户端的ServiceConnection的onServiceC

37、onnected方法的第二个参数。当客户端获取了远程的Service的IBinder对象的代理之后,接下来可通过该IBinder对象去回调远程Service的属性或方法。,AIDL文件创建和java借口定义相类似,但在编写AIDL文件时,需注意:,5.2.2 建立AIDL文件,1.接口名和aidl文件名相同;2.接口和方法前不用加访问权限修饰符public,private等,也不能用final,static;3.Aidl默认支持的类型包话java基本类型(int、long、boolean等)和(String、List、Map、CharSequence),使用这些类型时不需要import声明。对

38、于List和Map中的元素类型必须是Aidl支持的类型。如果使用自定义类型作为参数或返回值,自定义类型必须实现Parcelable接口。4.自定义类型和AIDL生成的其它接口类型在aidl描述文件中,应该显式import,即便在该类和定义的包在同一个包中。5.在aidl文件中所有非Java基本类型参数必须加上in、out、inout标记,以指明参数是输入参数、输出参数还是输入输出参数。6.Java原始类型默认的标记为in,不能为其它标记。,定义好AIDL接口之后(如Song.aidl),ADT工具会自动在gen目录下生成相应的包,并生成一个song.java接口,在该接口里包含一个Stub内部

39、类,该内部类实现了IBender,Song两个接口,这个Stub类将会作为远Service的回调类。由于它实现了IBinder接口,因此可作为Service的onBind()方法的返回值。,package .android; interface SongString getName();String getAuthor(); ,程序清单:/AIDLServer/src/iet/jxufe/cn/android/Song.aidl,5.2.2 建立AIDL文件,AIDL定义接口的源代码必须以.aidl结尾; AIDL接口中用到数据类型,除了基本类型、String、List、Map、CharSeq

40、uence之外,其他类型全部都需要导包,即使它们在同一个包中也需要导包。定义好AIDL接口之后(如Song.aidl),ADT工具会自动在gen目录下生成相应的包,并生成一个Song.java接口,在该接口里包含一个Stub内部类,该内部类实现了IBinder、Song两个接口,这个Stub类将会作为远程Service的回调类。它内部能实现一些功能。开发客户端的第一步就是将Service端的AIDL接口文件复制到客户端应用中,复制到客户端后ADT工具会为AIDL接口生成相应的Java接口类。,AIDL使用时需注意:,5.2.2 建立AIDL文件,5.2.3 建立AIDL服务端,远程Servic

41、e的编写和本地Service很相似,只是远程Service中onBind()方法返回的IBinder对象不同,该Service代码如下。,程序清单:/AIDLServer/src/iet/jxufe/cn/android/AIDLServer.java,public class AIDLServer extends Service private String names=new String“老男孩“,“春天里“,“在路上“;private String authors=new String“筷子兄弟“,“汪峰“,“刘欢“;private String name,author;private

42、 SongBinder songBinder;private Timer timer=new Timer();public class SongBinder extends Stub public String getName() throws RemoteException return name;public String getAuthor() throws RemoteException return author; ,5.2.3 建立AIDL服务端,远程Service的编写和本地Service很相似,只是远程Service中onBind()方法返回的IBinder对象不同,该Serv

43、ice代码如下。,程序清单:/AIDLServer/src/iet/jxufe/cn/android/AIDLServer.java,public IBinder onBind(Intent intent) return songBinder; public void onCreate() songBinder=new SongBinder();timer.schedule(new TimerTask() public void run() int rand=(int)(Math.random()*3);name=namesrand;author=authorsrand;System.out.

44、println(rand);, 0,1000);public void onDestroy() super.onDestroy();timer.cancel(); ,5.2.3 建立AIDL服务端,通过上面的程序可以看出,在远程Service中定义了一个SongBinder类,且该类继承Stub类,而Stub类继承了Binder类,并实现了Song接口,Binder类实现了IBinder接口。因此,与本地Service相比,开发远程Service要多定义一个AIDL接口。另外,程序中onBind()方法返回SongBinder类的对象实例,以便客户端获得服务对象,SongBinder对象的创建

45、放在onCreate()方法中,因为onBind()方法在onCreate()方法之后被调用,因此onBind()方法的返回值不会为空。接下来在AndroidManifest.xml文件中配置该Service类,配置Service类的代码如下:,程序清单:/AIDLServer/AndroidManifest.xml,5.2.4 建立AIDL客户端,1、创建ServiceConnection对象;2、以ServiceConnection对象作为参数,调用Context的bindService()方法绑定远程Service。3、将返回的IBinder对象的代理类转换成IBinder对象,从而调用

46、Service中的相应方法。,客户端绑定远程Service与绑定本地Service的区别不大, 同样只需要三步:,5.2.4 建立AIDL客户端案例,通过一个按钮来获取远程Service的状态,并显示在两个文本框中。,5.2.4 建立AIDL客户端案例,程序清单:/AIDLClient/src/iet/jxufe/cn/android/client/MainActivity.java,public class MainActivity extends Activity private Button getData;private EditText name,author;private Son

47、g songBinder; public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);getData=(Button)findViewById(R.id.getData);name=(EditText)findViewById(R.id.name);author=(EditText)findViewById(R.id.author);final Intent intent=new Intent();intent

48、.setAction(“.android.AIDLServer“);bindService(intent, conn, Service.BIND_AUTO_CREATE);getData.setOnClickListener(new OnClickListener() public void onClick(View v) tryname.setText(songBinder.getName();author.setText(songBinder.getAuthor(); ,用于获取其他进程数据的按钮,显示获取的数据的文本编辑框,用户交互的IBinder对象,根据ID找到相应控件,根据ID找到

49、相应控件,根据ID找到相应控件,创建一个Intent对象,设置Intent的特征,绑定Service,添加单击事件处理,显示获取的数据,5.2.4 建立AIDL客户端案例,catch(Exception ex)ex.printStackTrace(); );private ServiceConnection conn=new ServiceConnection() public void onServiceDisconnected(ComponentName name) songBinder=null; public void onServiceConnected(ComponentName name, IBinder service) songBinder=Song.Stub.asInterface(service);protected void onDestroy() super.onDestroy();unbindService(conn);,

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 教学课件 > 大学教育

copyright@ 2008-2019 麦多课文库(www.mydoc123.com)网站版权所有
备案/许可证编号:苏ICP备17064731号-1