8.3. 在 Service 中循环
8.3.在 Service 中循环
根据设计,我们的 Service 需要被频繁地唤醒,检查消息更新,然后再次“睡眠”一段时间。这一过程会持续进行下去,直到 Service 停止。实现时可以将这一过程放在一个循环中,每迭代一次就暂停一段时间。在这里可以利用 Java 提供的Thread.sleep()方法,可以让当前进程以毫秒为单位暂停一段时间,并让出 CPU。
在这里还有一点需要考虑,那就是Service连接到服务端获取数据这一行为本身,需要花费相当长的时间。网络操作的执行效率直接受网络接入方式、服务端的响应速度以及一些不可预知的因素影响,延迟是很常见的。
要是把检查更新的操作放在主线程的话,网络操作中的任何延时都会导致用户界面僵死,这会给用户留下一个很不好的印象。甚至很可能会让用户不耐烦,直接调出 "Force Close or Wait" 对话框(参见‘Android的线程机制’一节)把我们的应用杀死。
解决这一问题的最好办法,就是利用Java内置的线程支持,把网络相关的操作放到另一个线程里。Service在控制UI的主线程之外执行,这使得它们与用户交互的代码总是分离的。这点对Yamba这样与网络交互的界面而言尤为重要,而且对其它场景也同样适用,哪怕它花费的时间不长。
例 8.5. UpdaterService.java, version 2
package com.marakana.yamba3;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.util.Log;
public class UpdaterService2 extends Service {
private static final String TAG = "UpdaterService";
static final int DELAY = 60000; // a minute
private boolean runFlag = false; //
private Updater updater;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
this.updater = new Updater(); //
Log.d(TAG, "onCreated");
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
super.onStartCommand(intent, flags, startId);
this.runFlag = true; //
this.updater.start();
Log.d(TAG, "onStarted");
return START_STICKY;
}
@Override
public void onDestroy() {
super.onDestroy();
this.runFlag = false; //
this.updater.interrupt(); //
this.updater = null;
Log.d(TAG, "onDestroyed");
}
/**
* Thread that performs the actual update from the online service
*/
private class Updater extends Thread { //
public Updater() {
super("UpdaterService-Updater"); //
}
@Override
public void run() { //
UpdaterService2 updaterService = UpdaterService2.this; //
while (updaterService.runFlag) { //
Log.d(TAG, "Updater running");
try {
// Some work goes here...
Log.d(TAG, "Updater ran");
Thread.sleep(DELAY); //
} catch (InterruptedException e) { //
updaterService.runFlag = false;
}
}
}
} // Updater
}
- 声明一个常量,用以表示网络更新的时间间隔。我们也可以把它做在选项里,使之可以配置。
- 这个标志变量用以方便检查 Service 的执行状态。
- Updater 在另一个线程中进行网络更新。这个线程只需创建一次,因此我们在onCreate()中创建它。
- 在 Service 启动时,它会调用onStartCommand()方法,我们就在这里启动 Updater 线程再合适不过。同时设置上标志变量,表示 Service 已经开始执行了。
- 与之对应,我们可以在onDestroy()中停止 Updater 线程。再修改标志变量表示 Service 已经停止。
- 我们通过调用interrupt()来停止一个线程执行,随后设置变量的引用为 null ,以便于垃圾收集器清理。
- 在这里定义 Updater 类。它是个线程,因此以 Java 的 Thread 类为基类。
- 给我们的线程取一个名字。这样便于在调试中辨认不同的线程。
- Java 的线程必须提供一个run()方法。
- 简单得到对 Service 的引用。 Updater 是 Service 的内部类。
- 这个循环会一直执行下去,直到 Service 停止为止。记着 runFlag 变量是由onStartCommand()与onDestroy()修改的。
- 调用Thread.sleep()暂停Updater线程一段时间,前面我们将DELAY设置为1分钟。
- 对执行中的线程调用interrupt(),会导致run()中产生一个InterruptException异常。 我们捕获这个异常,并设置 runFlag 为 false ,从而避免它不断重试。