报告任务执行状态

编写:kesenhoo - 原文:http://developer.android.com/training/run-background-service/report-status.html

这章节会演示如何回传IntentService中执行的任务状态与结果给发送方。 例如,回传任务的执行状态给Activity并进行更新UI。推荐的方式是使用LocalBroadcastManager,这个组件可以限制broadcast intent只在自己的app中进行传递。

利用IntentService 发送任务状态

为了在IntentService中向其他组件发送任务状态,首先创建一个Intent并在data字段中包含需要传递的信息。作为一个可选项,还可以给这个Intent添加一个action与data URI。

下一步,通过执行LocalBroadcastManager.sendBroadcast() 来发送Intent。Intent被发送到任何有注册接受它的组件中。为了获取到LocalBroadcastManager的实例,可以执行getInstance()。代码示例如下:

  1. public final class Constants {
  2. ...
  3. // Defines a custom Intent action
  4. public static final String BROADCAST_ACTION =
  5. "com.example.android.threadsample.BROADCAST";
  6. ...
  7. // Defines the key for the status "extra" in an Intent
  8. public static final String EXTENDED_DATA_STATUS =
  9. "com.example.android.threadsample.STATUS";
  10. ...
  11. }
  12. public class RSSPullService extends IntentService {
  13. ...
  14. /*
  15. * Creates a new Intent containing a Uri object
  16. * BROADCAST_ACTION is a custom Intent action
  17. */
  18. Intent localIntent =
  19. new Intent(Constants.BROADCAST_ACTION)
  20. // Puts the status into the Intent
  21. .putExtra(Constants.EXTENDED_DATA_STATUS, status);
  22. // Broadcasts the Intent to receivers in this app.
  23. LocalBroadcastManager.getInstance(this).sendBroadcast(localIntent);
  24. ...
  25. }

下一步是在发送任务的组件中接收发送出来的broadcast数据。

接收来自IntentService的状态广播

为了接受广播的数据对象,需要使用BroadcastReceiver的子类并实现BroadcastReceiver.onReceive() 的方法,这里可以接收LocalBroadcastManager发出的广播数据。

  1. // Broadcast receiver for receiving status updates from the IntentService
  2. private class ResponseReceiver extends BroadcastReceiver
  3. {
  4. // Prevents instantiation
  5. private DownloadStateReceiver() {
  6. }
  7. // Called when the BroadcastReceiver gets an Intent it's registered to receive
  8. @
  9. public void onReceive(Context context, Intent intent) {
  10. ...
  11. /*
  12. * Handle Intents here.
  13. */
  14. ...
  15. }
  16. }

一旦定义了BroadcastReceiver,也应该定义actions,categories与data用过滤广播。为了实现这些,需要使用IntentFilter。如下所示:

  1. // Class that displays photos
  2. public class DisplayActivity extends FragmentActivity {
  3. ...
  4. public void onCreate(Bundle stateBundle) {
  5. ...
  6. super.onCreate(stateBundle);
  7. ...
  8. // The filter's action is BROADCAST_ACTION
  9. IntentFilter mStatusIntentFilter = new IntentFilter(
  10. Constants.BROADCAST_ACTION);
  11. // Adds a data filter for the HTTP scheme
  12. mStatusIntentFilter.addDataScheme("http");
  13. ...

为了给系统注册这个BroadcastReceiver和IntentFilter,需要通过LocalBroadcastManager执行registerReceiver()的方法。如下所示:

  1. // Instantiates a new DownloadStateReceiver
  2. DownloadStateReceiver mDownloadStateReceiver =
  3. new DownloadStateReceiver();
  4. // Registers the DownloadStateReceiver and its intent filters
  5. LocalBroadcastManager.getInstance(this).registerReceiver(
  6. mDownloadStateReceiver,
  7. mStatusIntentFilter);
  8. ...

一个BroadcastReceiver可以处理多种类型的广播数据。每个广播数据都有自己的ACTION。这个功能使得不用定义多个不同的BroadcastReceiver来分别处理不同的ACTION数据。为BroadcastReceiver定义另外一个IntentFilter,只需要创建一个新的IntentFilter并重复执行registerReceiver()即可。例如:

  1. /*
  2. * Instantiates a new action filter.
  3. * No data filter is needed.
  4. */
  5. statusIntentFilter = new IntentFilter(Constants.ACTION_ZOOM_IMAGE);
  6. ...
  7. // Registers the receiver with the new filter
  8. LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
  9. mDownloadStateReceiver,
  10. mIntentFilter);

发送一个广播Intent并不会启动或重启一个Activity。即使是你的app在后台运行,Activity的BroadcastReceiver也可以接收、处理Intent对象。但是这不会迫使你的app进入前台。当你的app不可见时,如果想通知用户一个发生在后台的事件,建议使用Notification永远不要为了响应一个广播Intent而去启动Activity。