|
|
|
|
移动端

在服务中循环

《Learning Android(中文版)》第8章服务,在本章,我们将动手创建一个服务。这个服务的任务是在后台运行的,获取用户在Twitter上最新的时间轴消息,并更新到应用上。本节为大家介绍在服务中循环。

作者:李亚舟/任中龙/杜钢译来源:电子工业出版社|2012-07-27 11:37

年前最后一场技术盛宴 | 1月27日与京东、日志易技术大咖畅聊智能化运维发展趋势!


在服务中循环

根据设计,我们的服务需要被频繁地唤醒,从在线服务中检查最新的消息,然后再次“睡眠”一段时间。这一过程需要保持一直进行下去,直到服务被停止。实现这个设计的一个好办法是,把我们的服务放在一个循环中,两次迭代之间暂停一段时间。Java提供了一个Thread.sleep()方法,我们可以用来让当前运行的进程以毫秒为单位暂停一段时间,并让出 CPU资源。

在这里还有一点要记得考虑,服务可能需要比较长的时间去建立到Twitter的连接,并获取朋友的状态数据。网络操作的执行效率受到网络接入方式、服务端的响应速度等因素影响,在所有相关因素的共同作用下,延迟是很常见的。

要是把检查更新的操作放在默认线程的话,联网更新所造成的任何延时,都会导致用户界面僵死,这会使得我们的程序用起来十分呆滞,甚至导致Android系统弹出ForceClose or Wait对话框,试图把我们的应用强行关闭(参见65页的“Android的线程机制”一节)。

解决这一问题的最好办法,就是利用Java内置的线程支持,把网络相关的操作放到一个单
独的线程里。如例8-5所示,服务所做的工作总是放在UI主线程之外的独立线程中,不论你觉得这个服务的工作速度会有多快,一定要把非交互性的程序跟用户界面隔离开。当你有与网络相关的界面时,比如Yamba这样的程序,隔离就显得更加重要,但是这条原则对任何服务都是成立的。

例8-5:UpdaterService.java, version 2

  1. package com.marakana.yamba3;  
  2. import android.app.Service;  
  3. import android.content.Intent;  
  4. import android.os.IBinder;  
  5. import android.util.Log;  
  6. public class UpdaterService2 extends Service {  
  7. private static final String TAG = "UpdaterService";  
  8. static final int DELAY = 60000; // 1.  
  9. private boolean runFlag = false; //   
  10. private Updater updater;  
  11. @Override  
  12. public IBinder onBind(Intent intent) {  
  13. return null;  
  14. }  
  15. @Override  
  16. public void onCreate() {  
  17. super.onCreate();  
  18. this.updater = new Updater(); //   
  19. Log.d(TAG, "onCreated");  
  20. }  
  21. @Override  
  22. public int onStartCommand(Intent intent, int flags, int startId) {  
  23. super.onStartCommand(intent, flags, startId);  
  24. this.runFlag = true; //   
  25. this.updater.start();  
  26. Log.d(TAG, "onStarted");  
  27. return START_STICKY;  
  28. }  
  29. @Override  
  30. public void onDestroy() {  
  31. super.onDestroy();  
  32. this.runFlag = false; //   
  33. this.updater.interrupt(); //   
  34. this.updater = null;  
  35. Log.d(TAG, "onDestroyed");  
  36. }  
  37. /**  
  38. * ......  
  39. */  
  40. private class Updater extends Thread { //   
  41. public Updater() {  
  42. super("UpdaterService-Updater"); //   
  43. }  
  44. @Overrid  
  45. public void run() { //   
  46. UpdaterService2 updaterService = UpdaterService2.this; // 凢  
  47. while (updaterService.runFlag) { //  
  48. Log.d(TAG, "Updater running");  
  49. try {  
  50. // ㄇ..ń.﹍  
  51. Log.d(TAG, "Updater ran");  
  52. Thread.sleep(DELAY); //  
  53. } catch (InterruptedException e) { //  
  54. updaterService.runFlag = false;  
  55. }  
  56. }  
  57. }  
  58. } // Updater  

指定一个常量,用以表示网络更新的时间间隔。我们也可以把它做在首选项里,让用户可以配置。

这个标志变量帮助我们检查该服务是否正在运行。

Updater是实际进行联网更新的独立线程。这个线程只需创建一次,因此我们在onCreate()方法中创建它。

在服务启动时,它会调用onStartCommand()方法,这也是一个启动Updater线程的很合适的地方。同时设置标志变量,表示服务已经开始执行。

与之对应,onDestroy()是一个合适的方法,用以停止我们的网络线程,以及修改标志变量,表示服务已经停止。

我们通过调用interrupt()来中断一个线程执行,随后设置变量的引用为null,以便于垃圾收集器进程清理。

在这里定义Updater类。它是个线程,因此以Java的Thread类为基类。

这里的目的只是给我们的线程取一个名字。这样便于在调试中辨认不同的线程。

Java线程必须提供一个run()方法。这里是线程实际干活的地方。

这里简单创建一个对服务的引用。Updater是这个服务的内部类。

这个循环会让网络更新重复执行下去,直到服务停止为止。要记得runFlag变量是在onStartCommand()与onDestroy()方法中修改的。

调用Thread.sleep(),会暂停Updater线程一段时间。前面我们将DELAY常量已经设置为1分钟。

当对执行中的线程发出interrupt()的信号时,会导致run()方法中产生一个InterruptedException异常。我们处理这个异常时,简单地设置runFlag为false,从而避免它试图再次运行。

【责任编辑:book TEL:(010)68476606】

回书目   上一节   下一节
点赞 0
分享:
大家都在看
猜你喜欢

读 书 +更多

J2ME手机游戏设计技术与实战

本书主要介绍了在手机上开发J2ME游戏的方法,作者在介绍了J2ME游戏开发相关知识背景的基础上,以大富翁手机游戏的设计开发为例,详细讲述了...

订阅51CTO邮刊

点击这里查看样刊

订阅51CTO邮刊