移动平台应用软件开发 Service 主讲 : 张齐勋 zhangqx@ss.pku.edu.cn 移动平台应用软件开发 课程建设小组 北京大学 二零一七年
什么是 Service 与 Activity 一样, 同属 Android 基本组件 后台运行, 不与用户交互, 没有可视化界面 最常见的 Service 如 : 在后台播放歌曲 后台执行文件的下载 同样需在 AndroidManifest.xml 中注册 每一个服务均继承自父类 Service Service 可以通过 Context.startService() 或 Context.bindService() 来创建
void oncreate( ) Service 生命周期 void onstartcommand( ) void ondestroy()
实现 Service 实现 Service 需要继承 android.app.service 类, 然后重写 onstartcommand onbind 和 oncreate 等方法 如果在 Activity 等组件中通过 Context.startService() 方法启动 Service, 需要重写 onstartcommand 方法 如果在 Activity 等组件中通过 Context.bindService() 方法绑定 Service, 需要重写 onbind 方法
Service 的调用 如果调用 Context.startService(), 那么系统将会查找这个 Service, 如果必要则创建它并调用它的 oncreate() 方法, 然后调用 onstartcommand 方法, Service 开始运行直到 Context.stopService() 或者 stopself() 方法被调用 注意, 多次调用 Context.startservice() 不会嵌套 ( 即使会有相应的 onstartcommand 被调用 ), 所以无论同一个服务被启动了多少次, 一旦调用 Context.stopService() 或者 stopself(), 他都会被停止 一个服务只会创建一次, 销毁一次, 但可以开始多次, 因此,onCreate 和 ondestroy 方法只会被调用一次, 而 onstartcommand 方法会被调用多次
Service 示例 public class MyService extends Service { @Nullable public IBinder onbind(intent intent) { Log.d("Myservice","Myservice->onBind"); return null; public void oncreate() { super.oncreate(); Log.d("Myservice","Myservice->onCreate"); public int onstartcommand(intent intent, int flags, int startid) { Log.d("Myservice","Myservice->onStartCommand"); return super.onstartcommand(intent, flags, startid); startservice(new Intent(this,MyService.class)); startservice(new Intent(this,MyService.class)); startservice(new Intent(this,MyService.class)); stopservice(new Intent(this,MyService.class)); stopservice(new Intent(this,MyService.class)); public void ondestroy() { super.ondestroy(); Log.d("Myservice","Myservice->onDestroy");
扩展练习 重写 onstartcommand oncreate 方法 ondestroy, 并通过 Log 打印信息, 分析这几个函数的调用时机 在 onstartcommand 中开启一个新的线程, 每隔一秒输出一条信息
在 Service 异步执行任务 Android 提一个工具类 AsyncTask 实现 AsyncTask 类中定义的下面一个或几个方法 Ø onpreexecute() 开始执行前的准备工作 ; Ø doinbackground(params...) 开始执行后台处理, 可以调用 publishprogress 方法来更新实时的任务进度 ; Ø onprogressupdate(progress...) 在 publishprogress 方法被调用后,UI thread 将调用这个方法从而在界面上展示任务的进展情况, 例如通过一个进度条进行展示 Ø onpostexecute(result) 执行完成后的操作, 传送结果给 UI 线程
AsyncTask Android 另外提供了一个工具类 :AsyncTask 使得 UI thread 的使用变得异常简单 它使创建需要与用户界面交互的长时间运行的任务变得更简单, 不需要借助线程和 Handler 即可实现 使用 AsyncTask 时, 需要继承 AsyncTask 父类并重写其中的回调函数和后台处理函数
AsyncTask 使用 实现 AsyncTask 类中定义的下面一个或几个方法 Ø onpreexecute() 开始执行前的准备工作 ; Ø doinbackground(params...) 开始执行后台处理, 可以调用 publishprogress 方法来更新实时的任务进度 ; Ø onprogressupdate(progress...) 在 publishprogress 方法被调用后,UI thread 将调用这个方法从而在界面上展示任务的进展情况, 例如通过一个进度条进行展示 Ø onpostexecute(result) 执行完成后的操作, 传送结果给 UI 线程 这 4 个方法都不能手动调用 所以要求 : 1) AsyncTask 的实例必须在 UI thread 中创建 ; 2) AsyncTask.execute 方法必须在 UI thread 中调用 ;
示例 : 使用 AsyncTask 的计时器 private Button BtnStart; private TextView txtviewtimer; private int Count = 0; private boolean isrunning = false; BtnStart = (Button) findviewbyid(r.id.btnstart); txtviewtimer = (TextView) findviewbyid(r.id.txtviewtimer); BtnStart.setOnClickListener(btnlistener); private Button.OnClickListener btnlistener = new Button.OnClickListener() { public void onclick(view v) { // TODO Auto-generated method stub isrunning=true; TimeTickLoad timetick = new TimeTickLoad(); timetick.execute(); ;
private class TimeTickLoad extends AsyncTask<Void, Integer, Void> { protected void onpreexecute() { super.onpreexecute(); protected Void doinbackground(void... arg0) { while (isrunning) { try { Thread.sleep(1000); catch (InterruptedException e) { // TODO Auto-generated catch block e.printstacktrace(); Count++; publishprogress(null); return null;
protected void onprogressupdate(integer... values) { // TODO Auto-generated method stub txtviewtimer.settext(" 时间已经过去了 " + String.valueOf(Count) + "S"); super.onprogressupdate(values); protected void onpostexecute(void result) { super.onpostexecute(result);
讨论 在天气预报项目中, 如何利用服务的机制?
Q&A 本讲结束!