




已阅读5页,还剩42页未读, 继续免费阅读
版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
#8服务与多线程,郑贵锋博士,刘宁Email:liuning2,Android提供Service类用于创建隐形的,不需要用户接口的程序。Service其实就是没有专属界面(UI)的Activity。Android的Service对象是以分时进程的方式运行,即在Activity里面启动的Service,也不会在相同的Process运行,而是各自属于不同的程序。利用Activity启动的Service,有各自独立的事件处理,Service简介,通过Service可以使程序在退出之后仍然能够对事件或用户操作做出反应,或者在后台继续运行某些程序功能。例如在退出播放器界面之后,继续在后台播放音乐,还有浏览器在后台下载网络数据。Android赋予Services比处于不活动(inactivity)的Activities更高的优先级,所以它们的进程不会轻易被系统杀掉。,Service简介,在某些极端的情况下(例如为前台Activity提供资源),Service可能会被杀掉,但是只要有足够的资源,系统会自动重启Service。在某些需要确保用户体验的情况下,(例如播放音乐)Service也可以被提高到与前台进程相同的优先级。Service是由其他Service,Activity或者BroadcastReceiver开始,停止和控制。,Service简介,启动模式一:通过startService启动通过startService启动的Service的生命周期状态(一旦启动,各自无关)通过调用Context.startService()启动,而以调用Context.stopService()结束。它可以调用Service.stopSelf()或Service.stopSelfResult()来自己停止。不论调用了多少次startService()方法,需要调用一次stopService()来停止服务。,Service简介,用于实现应用程序的耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验较好。startService()启动和stopService()关闭服务,Service与访问者之间基本不存在太多关联,因此Service和访问者之间无法通讯和数据交换。,Service简介,开启Service在Activity中可以通过startService(Intent)开启一个Service。与Activity跳转类似。Intentintent=newIntent(this,MyService.class);startService(intent);其中MyService类是开发者自定义的继承Service的子类。当第一次启动Service时,先后调用了onCreate(),onStart()这两个方法,当停止Service时,则执行onDestroy()方法。若Service已经启动,当再次启动Service时,不会在执行onCreate()方法,而是直接执行onStart()方法。,模式一:开始和停止Service,关闭Service在Activity中通过stopService(Intent)关闭Service;Intentintent=newIntent(this,MyService.class);stopService(intent);或者在Service中通过stopSelf()关闭自身。,模式一:开始和停止Service,通过Context.bindService()方法启动服务,通过Context.unbindService()关闭服务。多个客户端可以绑定至同一个服务。如果服务此时还没有加载,bindService()会先加载它。bindService启动的Service的生命周期,模式二:通过bindService启动,onBind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,多次调用Context.bindService()方法并不会导致该方法被多次调用。采用Context.bindService()方法启动服务时只能调用onUnbind()方法解除调用者与服务解除,服务结束时会调用onDestroy()方法。可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。,模式二:通过bindService启动,两种启动模式对比,建立Android工程Activity:ServiceApplication.java程序入口,例程将在这个Activity中启动Service。Service:MyService.java(继承Service的子类),如何实现一个Service,在大多情况,需要重写onCreate和onStartCommand方法onStartCommand方法在使用startService方法启动Service时被调用,在Service的生命周期内会多次被调用。onStartCommand方法代替了Android2.0之前一直使用的onStart方法。通过onStartCommand方法,可以明确告诉操作系统,在用户调用stopService或者stopSelf方法显式停止之前被操作系统杀死的Service重启的时候要执行的操作。,如何实现一个Service,MyService.javapublicclassMyServiceextendsServiceOverridepublicIBinderonBind(Intentintent)/必须实现的接口returnnull;OverridepublicintonStartCommand(Intentintent,intflags,intstartId)returnService.START_STICKY;OverridepublicbooleanonUnbind(Intentintent)returnsuper.onUnbind(intent);OverridepublicvoidonDestroy()super.onDestroy();,如何实现一个Service,ServiceApplication.javapublicclassServiceApplicationextendsActivityOverridepublicvoidonCreate(BundlesavedInstanceState)super.onCreate(savedInstanceState);setContentView(R.layout.main);Intentintent=newIntent(this,MyService.class);startService(intent);,如何实现一个Service,在AndroidManifest.xml中注册这个Service如果没有在此定义服务名称、访问权限,服务就无法被正确运行。,如何实现一个Service,由于Service没有界面,所以用户控制Service需要通过另外一个Activity来接收用户输入。通过绑定Activity与Service,可以实现Activity与Service之间的交互。例如在Activity中控制音乐播放Service对音乐进行开始/停止,快进/快退等操作。,绑定Activity和Service,如果Service运行在本地进程,即与Activity属于同一进程,则只要在Activity中获得指向Service的引用,就可以像调用成员对象的方法一样去调用Service的方法。如果Service运行在远程进程中,则Activity与Service的交互属于进程间通讯。跟其他操作系统一样,Android操作系统也对进程空间进行保护,一个进程不能直接访问另一个进程的内存空间。所以进程间数据交互需要利用Android操作系统提供的进程间通讯(IPC)机制来实现。,绑定Activity和Service,IBinder是远程对象的基本接口,是为高效率进行进程间通讯设计的轻量级远程过程调用机制的核心。该接口描述了与远程对象交互的抽象协议。通常我们使用的时候并不是直接实现这个接口,而是继承自Binder父类。,IPC机制IBinder,Binder实质上是以IPC(Inter-ProcessCommunication,进程间通信)框架为基础。可以简单按下图理解,其实质就是通过共享内存实现进程间的通讯。,关于消息传递,AndroidSDK,进程1,进程2,Linuxkernel,共享内存,Java层,C+层,Activity和Service交互示意图,绑定Activity和Service,Activity,Binder,Service,IBinder,MyService.javapublicclassMyServiceextendsServiceprivateIBindermBinder=newMyBinder();OverridepublicIBinderonBind(Intentintent)/必须实现的接口returnmBinder;publicclassMyBinderextendsBinderOverrideprotectedbooleanonTransact(intcode,Parceldata,Parcelreply,intflags)throwsRemoteExceptionreturnsuper.onTransact(code,data,reply,flags);,绑定Activity和Service,ServiceApplication.javapublicclassServiceApplicationextendsActivityprivateIBindermBinder;privateServiceConnectionmConnection;OverridepublicvoidonCreate(BundlesavedInstanceState)super.onCreate(savedInstanceState);setContentView(R.layout.main);mConncetion=newServiceConnection()OverridepublicvoidonServiceConnected(ComponentNamename,IBinderservice)mBinder=service;OverridepublicvoidonServiceDisconnected(ComponentNamename)mConnection=null;Intentintent=newIntent(this,MyService.class);bindService(intent,mConnection,Context.BIND_AUTO_CREATE);,绑定Activity和Service,onServiceConnection的输入参数IBinder就是Service中onBind返回的Binder对象。通过IBinder对象就可以实现Activity和Service进程间通讯。通过配对的IBinder的transact()方法和Binder的onTransact()方法,可以实现从IBinder接口发送消息,在Binder对象中接收消息,处理消息,再返回的过程。,绑定Activity和Service,transact()和onTransact()是一个同步调用过程,意味着线程A调用transact()后,在线程B完成onTransact()整个处理过程之前,线程A都是阻塞着。所以,如果在onTransact()中需要进行大规模计算时,通常需要在线程A中开启新线程调用transact()。,绑定Activity和Service,onTransact(intcode,Parceldata,Parcelreply,intflags)transact(intcode,Parceldata,Parcelreply,intflags)通过onTransact和transact交互的数据都被封装在Parcel中由于IBinder只提供了一个消息传递接口,只能通过int类型的输入参数code对消息进行识别和判断,绑定Activity和Service,AIDL(AndroidInterfaceDescriptionLanguage)弥补了IBinder接口单一的缺点。AIDL接口描述文件,语法与普通的Java接口一样,只是文件扩展名为.aidl。ADT会根据这个描述文件自动生成一个底层基于IBinder机制,表层提供描述文件所定义方法的接口类。,AIDL简介,以下例程中自定义了set、get两个方法ITest.aidlinterfaceIAidlTest/可以看到,aidl文件语法与普通接口一致voidset(inti);intget();,AIDL简介,ADT会根据这个.aidl文件,自动生成一个.java接口文件,其中代码结构如下:publicinterfaceIAidlTestextendsandroid.os.IInterface/部分省略publicstaticabstractclassStubextendsandroid.os.Binderimplementscom.book.ServiceApplication.IAidlTest/部分省略privatestaticclassProxyimplementscom.book.ServiceApplication.IAidlTest/部分省略publicvoidset(inti)throwsandroid.os.RemoteException/implement./publicintget()throwsandroid.os.RemoteException/implement./需要在服务端重写set、get函数,实现具体操作publicvoidset(inti)throwsandroid.os.RemoteException;publicintget()throwsandroid.os.RemoteException;,AIDL简介,AIDL接口代码结构如下,可以看出这里采用了COM组件开发的Proxy/Stub结构,这种代理设计模式多用于远程对象的调用。,AIDL简介,AIDLinterface,Proxy,Stub,Service,Activity,ProcessA,ProcessB,MyService.java部分代码通过匿名类,实现服务端(stub端)的方法privatefinalIAidlTest.Stubbinder=newIAidlTest.Stub()Overridepublicvoidset(inti)throwsRemoteException/在这里实现set方法Overridepublicintget()throwsRemoteException/在这里实验get方法;OverridepublicIBinderonBind(Intentintent)returnbinder;,AIDL使用,ServiceApplication.java部分代码ServiceConnectionmSrcConn=newServiceConnection()OverridepublicvoidonServiceConnected(ComponentNamename,IBinderservice)/这里stub.asInterface其实就是返回一个代理(Proxy)对象IBindermBinder=IAidlTest.Stub.asInterface(service);OverridepublicvoidonServiceDisconnected(ComponentNamename)/省略部分代码;,AIDL使用,为了提供良好的用户体验,我们必须保证程序有高响应性,所以不能在UI线程中进行耗时的计算或IO操作。Android操作系统在下面情况下会强制关闭程序UI线程在5秒内没有响应广播对象不能再10秒内完成onReceive方法,多线程应用-背景,因此需要采用多线程的方法,将大规模的计算放在后台线程中进行计算,然后将计算结果再显示到前台。例如,在后台下载网络图片,下载完成后显示在屏幕上。,多线程应用-应用场景,Java基础ThreadmThread=newThread()Overridepublicvoidrun()timeConsumingProcess();mThread.start(),新建用户线程,但是由于Android操作系统的线程安全机制,不能在非UI线程中重绘UI,所以在用户线程中进行类似更改进度条,修改TextView文字等操作都会造成程序强制关闭(FC)Android提供了两种方法解决上述问题:HandlerAsyncTask,新建用户线程,Android操作系统在UI线程中,缺省维护该MessageQueue和一个Looper。Looper伪码,Handler机制,while(true)Msg=getFirstMessage(MessageQueue)if(Msg!=null)processMessage(),Looper通过一个死循环,当有消息Message加入队列时,通过FIFO的顺序处理消息。一个Message中包括了处理Message的Handler对象还有消息内容。这种机制对应这设计模式中的命令模式Handler与UI线程是同一个线程,所以我们在用户线程中完成计算之后,可以通过向消息队列加入一个消息,通知特定的Handler去更改UI。,Handler机制,/*ServiceApplication.java*/HandlermHandler=newHandler()OverridepublicvoidhandleMessage(Messagemsg)super.handleMessage(msg);switch(msg.what)/在此处判断消息类型并更新UI;ThreadmThread=newThread()Overridepublicvoidrun()timeConsumingProcess();/进行耗时操作/定义接收消息的Handler对象,并将消息加入队列mHandler.obtainMessage(type).sendToTarget();,Handler实现,与UI同一线程的消息处理器Handler,专门负责处理非UI线程发送过来的各种消息,更新UI。,非UI线程负责耗时工作,将不同类型的消息发送给上面定义的Handler。,AsyncTask是在AndroidSDK1.5之后推出的一个方便编写后台线程与UI线程交互的辅助类。AsyncTask的内部实现是一个线程池,每个后台任务会提交到线程池中的线程执行,然后使用Thread+Handler的方式调用回调函数(对程序员透明)。AsyncTask抽象出后台线程运行的五个状态,分别是:1、准备运行,2、正在后台运行,3、进度更新,4、完成后台任务,5、取消任务,对于这五个阶段,AsyncTask提供了五个回调函数。,AsyncTask概述,1、准备运行:onPreExecute(),该回调函数在任务被执行之后立即由UI线程调用。这个步骤通常用来建立任务,在用户接口(UI)上显示进度条。2、正在后台运行:doInBackground(Params.),该回调函数由后台线程在onPreExecute()方法执行结束后立即调用。通常在这里执行耗时的后台计算。计算的结果必须由该函数返回,并被传递到onPostExecute()中。在该函数内也可以使用publishProgress(Progress.)来发布一个或多个进度单位(unitsofprogress)。这些值将会在onProgressUpdate(Progress.)中被发布到UI线程。,AsyncTask可重载的回调函数,3.进度更新:onProgressUpdate(Progress.),该函数由UI线程在publishProgress(Progress.)方法调用完后被调用。一般用于动态地显示一个进度条。4.完成后台任务:onPostExecute(Result),当后台计算结束后调用。后台计算的结果会被作为参数传递给这一函数。5、取消任务:onCan
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025年公路水运工程试验检测师公共基础试题及答案(法规与技术标准)解析
- 全2025年公路水运试验检测人员考试题库及答案
- 2017年6月国开电大法律事务专科《行政法与行政诉讼法》期末纸质考试试题及答案
- 2025 年小升初沧州市初一新生分班考试英语试卷(带答案解析)-(人教版)
- 事业单位年度考核表个人总结2025教师7篇
- 北师大版灵宝市20252025学年度上期期末综合测试小学五年级语文试卷及参考答案
- 安徽省阜阳市界首市2024-2025学年八年级(下)期末物理试卷(含答案)
- 承包水立方合同范本
- 防疫车辆租车合同范本
- 工程劳务合同范本模板
- 美容外科安全应急预案范文(3篇)
- 6G多维度切片QoS保障-洞察及研究
- 2025-2026学年外研版(三起)(2024)小学英语四年级上册教学计划及进度表
- 2025年安徽国控集团所属企业招聘7人笔试备考题库及答案解析
- 仓库盘盈盘亏处理方案(3篇)
- 2025年海南省警务辅助人员招聘考试(公共基础知识)历年参考题库含答案详解(5套)
- 城市道路清扫保洁协议
- 人教版二年级上册数学全册教学设计(配2025年秋新版教材)
- 2025年医学检验在编考试题库
- 特色食品卖场建设方案(3篇)
- 2025年书法级考试题及答案
评论
0/150
提交评论