移动应用开发-郑贵锋08服务与多线程

上传人:hs****ma 文档编号:584284925 上传时间:2024-08-30 格式:PPT 页数:47 大小:1.42MB
返回 下载 相关 举报
移动应用开发-郑贵锋08服务与多线程_第1页
第1页 / 共47页
移动应用开发-郑贵锋08服务与多线程_第2页
第2页 / 共47页
移动应用开发-郑贵锋08服务与多线程_第3页
第3页 / 共47页
移动应用开发-郑贵锋08服务与多线程_第4页
第4页 / 共47页
移动应用开发-郑贵锋08服务与多线程_第5页
第5页 / 共47页
点击查看更多>>
资源描述

《移动应用开发-郑贵锋08服务与多线程》由会员分享,可在线阅读,更多相关《移动应用开发-郑贵锋08服务与多线程(47页珍藏版)》请在金锄头文库上搜索。

1、#8 服务与多线程郑贵锋 博士刘宁Email:Android提供Service类用于创建隐形的,不需要用户接口的程序。Service其实就是没有专属界面(UI)的Activity。Android的Service对象是以分时进程的方式运行,即在Activity里面启动的Service,也不会在相同的Process运行,而是各自属于不同的程序。利用Activity启动的Service,有各自独立的事件处理Service 简介通过Service可以使程序在退出之后仍然能够对事件或用户操作做出反应,或者在后台继续运行某些程序功能。例如在退出播放器界面之后,继续在后台播放音乐,还有浏览器在后台下载网络数

2、据。Android赋予Services比处于不活动(inactivity)的Activities更高的优先级,所以它们的进程不会轻易被系统杀掉。Service 简介在某些极端的情况下(例如为前台Activity提供资源),Service可能会被杀掉,但是只要有足够的资源,系统会自动重启Service。在某些需要确保用户体验的情况下,(例如播放音乐)Service也可以被提高到与前台进程相同的优先级。Service是由其他Service,Activity或者Broadcast Receiver开始,停止和控制。Service 简介启动模式一:通过startService启动通过startServ

3、ice启动的Service的生命周期状态(一旦启动,各自无关)通过调用Context.startService()启动,而以调用Context.stopService()结束。它可以调用Service.stopSelf() 或 Service.stopSelfResult()来自己停止。不论调用了多少次startService()方法,需要调用一次stopService()来停止服务。Service 简介onCreateonDestroy用于实现应用程序的耗时任务,比如查询升级信息,并不占用应用程序比如Activity所属线程,而是单开线程后台执行,这样用户体验较好。startService(

4、)启动和stopService()关闭服务,Service与访问者之间基本不存在太多关联,因此Service和访问者之间无法通讯和数据交换。Service 简介开启Service在Activity中可以通过startService(Intent)开启一个Service。与Activity跳转类似。Intent intent = new Intent(this,MyService.class);startService(intent);其中MyService类是开发者自定义的继承Service的子类。当第一次启动Service时,先后调用了onCreate(),onStart()这两个方法,当停

5、止Service时,则执行onDestroy()方法。若Service已经启动,当再次启动Service时,不会在执行onCreate()方法,而是直接执行onStart()方法。模式一:开始和停止Service关闭Service在Activity中通过stopService(Intent)关闭Service; Intent intent = new Intent(this,MyService.class);stopService(intent);或者在Service中通过stopSelf()关闭自身。模式一:开始和停止Service通过Context.bindService()方法启动服务,

6、通过 Context.unbindService()关闭服务。多个客户端可以绑定至同一个服务。如果服务此时还没有加载,bindService()会先加载它。bindService启动的Service的生命周期模式二:通过bindService启动onBind()只有采用Context.bindService()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,多次调用Context.bindService()方法并不会导致该方法被多次调用。采用Context.bindService()方法启动服务时只能调用onUnbind()方法解除调用者与服务解除,服务

7、结束时会调用onDestroy()方法。可被其他应用程序复用,比如天气预报服务,其他应用程序不需要再写这样的服务,调用已有的即可。模式二:通过bindService启动两种启动模式对比建立Android工程Activity:ServiceApplication.java 程序入口,例程将在这个Activity中启动Service。Service:MyService.java(继承Service的子类) 如何实现一个Service在大多情况,需要重写onCreate和onStartCommand方法onStartCommand方法在使用startService方法启动Service时被调用,在S

8、ervice的生命周期内会多次被调用。onStartCommand方法代替了Android 2.0之前一直使用的onStart方法。通过onStartCommand方法,可以明确告诉操作系统,在用户调用stopService或者stopSelf方法显式停止之前被操作系统杀死的Service重启的时候要执行的操作。如何实现一个ServiceMyService.javapublic class MyService extends Service Overridepublic IBinder onBind(Intent intent) / 必须实现的接口return null; Overridepu

9、blic int onStartCommand(Intent intent, int flags, int startId) return Service.START_STICKY;Overridepublic boolean onUnbind(Intent intent) return super.onUnbind(intent);Overridepublic void onDestroy() super.onDestroy();如何实现一个ServiceServiceApplication.javapublic class ServiceApplication extends Activi

10、ty Override public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState);setContentView(R.layout.main);Intent intent = new Intent(this,MyService.class); startService(intent);如何实现一个Service在AndroidManifest.xml中注册这个Service如果没有在此定义服务名称、访问权限,服务就无法被正确运行。 如何实现一个Service由于Service没有界面,所以

11、用户控制Service需要通过另外一个Activity来接收用户输入。通过绑定Activity与Service,可以实现Activity与Service之间的交互。例如在Activity中控制音乐播放Service对音乐进行开始/停止,快进/快退等操作。绑定Activity和Service如果Service运行在本地进程,即与Activity属于同一进程,则只要在Activity中获得指向Service的引用,就可以像调用成员对象的方法一样去调用Service的方法。如果Service运行在远程进程中,则Activity与Service的交互属于进程间通讯。跟其他操作系统一样,Android操

12、作系统也对进程空间进行保护,一个进程不能直接访问另一个进程的内存空间。所以进程间数据交互需要利用Android操作系统提供的进程间通讯(IPC)机制来实现。绑定Activity和ServiceIBinder是远程对象的基本接口,是为高效率进行进程间通讯设计的轻量级远程过程调用机制的核心。该接口描述了与远程对象交互的抽象协议。通常我们使用的时候并不是直接实现这个接口,而是继承自Binder父类。IPC机制IBinderBinder实质上是以IPC(Inter-Process Communication,进程间通信)框架为基础。可以简单按下图理解 ,其实质就是通过共享内存实现进程间的通讯。关于消息

13、传递Android SDK进程1进程2Linux kernel共享内存Java层C+层Activity和Service交互示意图绑定Activity和ServiceActivityBinderServiceIBinderMyService.javapublic class MyService extends Service private IBinder mBinder = new MyBinder(); Override public IBinder onBind(Intent intent) / 必须实现的接口 return mBinder; public class MyBinder e

14、xtends BinderOverrideprotected boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException return super.onTransact(code, data, reply, flags);绑定Activity和ServiceServiceApplication.javapublic class ServiceApplication extends Activity private IBinder mBinder;private Service

15、Connection mConnection; Override public void onCreate(Bundle savedInstanceState) super.onCreate(savedInstanceState);setContentView(R.layout.main);mConncetion = new ServiceConnection()Overridepublic void onServiceConnected(ComponentName name, IBinder service) mBinder = service;Overridepublic void onS

16、erviceDisconnected(ComponentName name) mConnection = null;Intent intent = new Intent(this,MyService.class); bindService(intent, mConnection, Context.BIND_AUTO_CREATE);绑定Activity和ServiceonServiceConnection的输入参数IBinder就是Service中onBind返回的Binder对象。通过IBinder对象就可以实现Activity和Service进程间通讯。通过配对的IBinder的trans

17、act()方法和Binder的onTransact()方法,可以实现从IBinder接口发送消息,在Binder对象中接收消息,处理消息,再返回的过程。绑定Activity和Servicetransact()和onTransact()是一个同步调用过程,意味着线程A调用transact()后,在线程B完成onTransact()整个处理过程之前,线程A都是阻塞着。所以,如果在onTransact()中需要进行大规模计算时,通常需要在线程A中开启新线程调用transact()。绑定Activity和ServiceonTransact(int code, Parcel data, Parcel r

18、eply,int flags) transact(int code, Parcel data, Parcel reply,int flags) 通过onTransact和transact交互的数据都被封装在Parcel中由于IBinder只提供了一个消息传递接口,只能通过int类型的输入参数code对消息进行识别和判断绑定Activity和ServiceAIDL(Android Interface Description Language)弥补了IBinder接口单一的缺点。AIDL接口描述文件,语法与普通的Java接口一样,只是文件扩展名为.aidl。ADT会根据这个描述文件自动生成一个底层

19、基于IBinder机制,表层提供描述文件所定义方法的接口类。AIDL简介以下例程中自定义了set、get两个方法ITest.aidlinterface IAidlTest/可以看到,aidl文件语法与普通接口一致void set(int i);int get();AIDL简介ADT会根据这个.aidl文件,自动生成一个.java接口文件,其中代码结构如下:public interface IAidlTest extends android.os.IInterface/部分省略public static abstract class Stub extends android.os.Binder

20、implements com.book.ServiceApplication.IAidlTest /部分省略private static class Proxy implements com.book.ServiceApplication.IAidlTest/部分省略public void set(int i) throws android.os.RemoteException /implement./ public int get() throws android.os.RemoteException /implement./ /需要在服务端重写set、get函数,实现具体操作public

21、void set(int i) throws android.os.RemoteException;public int get() throws android.os.RemoteException;AIDL简介AIDL接口代码结构如下,可以看出这里采用了COM组件开发的Proxy/Stub结构,这种代理设计模式多用于远程对象的调用。AIDL简介AIDL interfaceProxyStubServiceActivityProcess AProcess BMyService.java部分代码通过匿名类,实现服务端(stub端)的方法private final IAidlTest.Stub b

22、inder = new IAidlTest.Stub() Overridepublic void set(int i) throws RemoteException /在这里实现set方法Overridepublic int get() throws RemoteException /在这里实验get方法;Overridepublic IBinder onBind(Intent intent) return binder;AIDL使用ServiceApplication.java部分代码ServiceConnection mSrcConn = new ServiceConnection() O

23、verridepublic void onServiceConnected(ComponentName name, IBinder service) /这里stub.asInterface其实就是返回一个代理(Proxy)对象IBinder mBinder = IAidlTest.Stub.asInterface(service);Overridepublic void onServiceDisconnected(ComponentName name) /省略部分代码;AIDL使用1.为了提供良好的用户体验,我们必须保证程序有高响应性,所以不能在UI线程中进行耗时的计算或IO操作。2.Andr

24、oid操作系统在下面情况下会强制关闭程序UI线程在5秒内没有响应广播对象不能再10秒内完成onReceive方法多线程应用-背景因此需要采用多线程的方法,将大规模的计算放在后台线程中进行计算,然后将计算结果再显示到前台。例如,在后台下载网络图片,下载完成后显示在屏幕上。多线程应用-应用场景Java基础Thread mThread = new Thread() Override public void run() timeConsumingProcess(); ;mThread.start()新建用户线程但是由于Android操作系统的线程安全机制,不能在非UI线程中重绘UI,所以在用户线程中进

25、行类似更改进度条,修改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对象还有

26、消息内容。这种机制对应这设计模式中的命令模式Handler与UI线程是同一个线程,所以我们在用户线程中完成计算之后,可以通过向消息队列加入一个消息,通知特定的Handler去更改UI。Handler机制/* ServiceApplication.java */ Handler mHandler = new Handler() Overridepublic void handleMessage(Message msg) super.handleMessage(msg);switch(msg.what)/在此处判断消息类型并更新UI ;Thread mThread = new Thread() O

27、verridepublic void run() timeConsumingProcess(); /进行耗时操作/定义接收消息的Handler对象,并将消息加入队列mHandler.obtainMessage(type).sendToTarget(); ;Handler实现与与UI同一线程的消息同一线程的消息处理器处理器Handler,专门,专门负责处理非负责处理非UI线程发线程发送过来的各种消息,送过来的各种消息,更新更新UI。非非UI线程负责耗时工线程负责耗时工作,将不同类型的消作,将不同类型的消息发送给上面定义的息发送给上面定义的Handler。AsyncTask是在Android SD

28、K 1.5之后推出的一个方便编写后台线程与UI线程交互的辅助类。AsyncTask的内部实现是一个线程池,每个后台任务会提交到线程池中的线程执行,然后使用Thread+Handler的方式调用回调函数(对程序员透明)。AsyncTask抽象出后台线程运行的五个状态,分别是:1、准备运行,2、正在后台运行,3、进度更新,4、完成后台任务,5、取消任务,对于这五个阶段,AsyncTask提供了五个回调函数。AsyncTask概述1、准备运行:onPreExecute(),该回调函数在任务被执行之后立即由UI线程调用。这个步骤通常用来建立任务,在用户接口(UI)上显示进度条。2、正在后台运行:doI

29、nBackground(Params.),该回调函数由后台线程在onPreExecute()方法执行结束后立即调用。通常在这里执行耗时的后台计算。计算的结果必须由该函数返回,并被传递到onPostExecute()中。在该函数内也可以使用publishProgress(Progress.)来发布一个或多个进度单位(unitsof progress)。这些值将会在onProgressUpdate(Progress.)中被发布到UI线程。AsyncTask可重载的回调函数3. 进度更新:onProgressUpdate(Progress.),该函数由UI线程在publishProgress(Pro

30、gress.)方法调用完后被调用。一般用于动态地显示一个进度条。4. 完成后台任务:onPostExecute(Result),当后台计算结束后调用。后台计算的结果会被作为参数传递给这一函数。5、取消任务:onCancelled (),在调用AsyncTask的cancel()方法时调用AsyncTask可重载的回调函数三个模板参数1.Params,传递给后台任务的参数类型。2.Progress,后台计算执行过程中,进度单位(progressunits)的类型。(就是后台程序已经执行了百分之几了。)3.Result, 后台执行返回的结果的类型。AsyncTask并不总是需要使用上面的全部3种类

31、型。标识不使用的类型很简单,只需要使用Void类型即可。AsyncTask的构造函数ServiceApplication.javaclass MyTask extends AsyncTaskOverrideprotected Integer doInBackground(Integer. params) /重写该函数,实现后台处理大规模计算return null;Overrideprotected void onProgressUpdate(Integer. values) super.onProgressUpdate(values);/重写该回调函数,更新UI很清晰的一套模板方法设计模式,只

32、需要重写关键事件,不用去了解底层的多线程并发的实现机制AsyncTask使用1.在布局里放置进度条,在代码里定义进度条ProgressBarmProgBar;2.定义class MyTask extends AsyncTask3.在MyTask 的doInBackground里执行耗时操作,在适当的时候调用publishProgress(n)来设置进度条进度。AsyncTask更新进度条的例子4. 在MyTask的onProgressUpdate (Integer. progress) 里具体设置进度条进度,例如mProgBar.setProgress(progress0);注意:这个函数在doInBackground调用publishProgress时触发,虽然调用时只有一个参数, 但是这里取到的是一个数组,所以要用progesss0来取值, 第n个参数就用progressn来取值。.定义并运行:MyTask mt = new MyTask(); mt.execute(100);AsyncTask更新进度条的例子Questions?

展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 高等教育 > 研究生课件

电脑版 |金锄头文库版权所有
经营许可证:蜀ICP备13022795号 | 川公网安备 51140202000112号