Android开发文档翻译之-Services

Service是一种能长期在后台运行同时不需要与用户进行交互的应用组件。其他组件可以开启service,开启后service可以自行运行及时用户已经切换到其他的应用。此外,组件可以与service进行绑定来进行交互,及时是跨进程的交互(Android的IPC机制)。网络操作、播放音乐、执行文件IO操作或是与内容提供者进行交互,这些操作都可以通过service在后台进行。

Service的两种形式:

Started

通过调用startService(),你可以启动一个service。一旦被启动,service可以独立的运行在后台,即使启动的组件被销毁。通常,被启动的service用来执行一个单一的操作,并且没有返回值。例如,下载网络上的一个文件。当操作执行完毕后,service应当自行结束。

Bound

通过调用bindService(),你可以绑定一个service。一个被绑定的service一般会提供一个接口用来与组件进行交互、发送请求、获取结果、甚至进行进程间的交互(IPC)。被绑定的service的生命周期和其绑定的组件相同。尽管多个组件可以同时绑定一个service,但是但所有这些组件进行解绑后,service会被销毁。

虽然文档中一般会对两种形式的service分开介绍,但是你可以同时开启和绑定service。只需要同时覆写两个回调-onStartCommand和onBind即可。

无论是用哪种方式启动service(或是两者都用),你都可以使用Intent来操作service,就想操作Activity一样。然而,如果你不想让其他应用使用你的service,你可以在manifest文件中将service申明为私有的,具体请看Service在清单文件中的申明

基础介绍

想要使用service,你需要继承Service类或其子类。你需要覆写一些回调方法同时在这些方法中进行一些关键操作。一下是一些较为重要的生命周期回调回调:

onStartCommand()

系统会在你调用了startService后调用该函数。一旦该方法执行,service会被启动并独立运行在后台。如果你实现了该方法,你必须在合适的时机调用stopSelf()或者stopService()来停止service。(如果你仅提供绑定接口,你可以不实现该方法)

onBind()

当有其他组件通过bindService()绑定service后,系统会调用onBind()函数。你需要在该方法中提供一个实现了IBinder接口的类供给client使用。该方法必须要覆写,如果你不希望你的service提供绑定功能,你可以直接返回null。

Android系统会在内存较低时强制停止service;如果service被绑定在一个拥有焦点的activity上时,其被kill的风险会降低;如果一个service被申明为前台service,那么它几乎不会被kill。否者的话,如果service被长时间开启,那么随着时间的推移,service在系统中的优先级就会越低,被kill的风险就会越高。如果你的service被启动了,那么你就应该考虑到其被系统kill的情况。如果系统kill了一个service,那么在资源宽松的情况下,系统会重启它(这个需要根据你在onStartCommand()的返回值决定重启的策略)。

Service在清单文件中的申明

和activity一样,你需要在清单文件中申明service。

<manifest ... >
  ...
  <application ... >
      <service android:name=".ExampleService" />
      ...
  </application>
</manifest>

在service节点中可以申明一些其他的属性。这些属性都是可选的。只有android:name这一属性是必须的——该属性用来描述一个唯一的service类名,你应该确保不去修改该类名。

为了确保你的应用的安全性,应该使用显式意图来启动或者绑定service,并且不在service中申明intent-filters。

此外,你可以通过设置android:exported属性为false来确保你的service仅可以在你自己的应用中被使用。这可以有效得阻止其他应用使用你的service,即使通过显式意图也不可以。

以启动方式创建service

可以通过startService()来启动service,你可以监听到onStartCommand()回调。

当一个service被启动后,它将拥有独立的生命周期并且独立的运行在后台,即使开启它的组件被销毁。这种情况下,你需要在合适的时机调用stopSelf()来结束它或者通过调用stopServie()来结束它。

调用startService()时传递的Intent会在onStartCommand()回调时接收到。

注意:service会默认运行在申明service的那个应用进程中,并且会运行在主线程中。所以如果你的service在执行一些密集或阻塞的操作,那么可能会造成ANR现象。为了避免这种情况,你需要开启一个新的线程。

一般来说,你可以通过继承IntentService类来加速你的开发。

继承IntentService类

由于大部分的service都不需要处理并发请求,因此你可以通过继承IntentService类来加速你的开发。

IntentService有以下特性:

1.创建了一个工作线程来执行由onStartCommand()中传递的intent,该线程是和主线程分离的。

2.创建了一个工作队列用来依次执行intent,因此你不需要考虑多线程问题。

3.当所有任务执行结束后会自动的调用stopSelf()。

4.提供了onBind()的默认实现(return null)

5.提供了onStartCommand()的默认实现,发送任务到任务队列中并且回调onHandleIntent()

上述这些特性使得你只需要实现onHandleIntent()就可以完成client端的任务(你还需要提供一个简单的构造函数)

以下是IntentService的一个实现:

public class HelloIntentService extends IntentService {

  /**
   * A constructor is required, and must call the super IntentService(String)
   * constructor with a name for the worker thread.
   */
  public HelloIntentService() {
      super("HelloIntentService");
  }

  /**
   * The IntentService calls this method from the default worker thread with
   * the intent that started the service. When this method returns, IntentService
   * stops the service, as appropriate.
   */
  @Override
  protected void onHandleIntent(Intent intent) {
      // Normally we would do some work here, like download a file.
      // For our sample, we just sleep for 5 seconds.
      try {
          Thread.sleep(5000);
      } catch (InterruptedException e) {
          // Restore interrupt status.
          Thread.currentThread().interrupt();
      }
  }
}

对比一下,如果你继承自service要实现相同功能所需写的代码:

public class HelloService extends Service {
  private Looper mServiceLooper;
  private ServiceHandler mServiceHandler;

  // Handler that receives messages from the thread
  private final class ServiceHandler extends Handler {
      public ServiceHandler(Looper looper) {
          super(looper);
      }
      @Override
      public void handleMessage(Message msg) {
          // Normally we would do some work here, like download a file.
          // For our sample, we just sleep for 5 seconds.
          try {
              Thread.sleep(5000);
          } catch (InterruptedException e) {
              // Restore interrupt status.
              Thread.currentThread().interrupt();
          }
          // Stop the service using the startId, so that we don‘t stop
          // the service in the middle of handling another job
          stopSelf(msg.arg1);
      }
  }

  @Override
  public void onCreate() {
    // Start up the thread running the service.  Note that we create a
    // separate thread because the service normally runs in the process‘s
    // main thread, which we don‘t want to block.  We also make it
    // background priority so CPU-intensive work will not disrupt our UI.
    HandlerThread thread = new HandlerThread("ServiceStartArguments",
            Process.THREAD_PRIORITY_BACKGROUND);
    thread.start();

    // Get the HandlerThread‘s Looper and use it for our Handler
    mServiceLooper = thread.getLooper();
    mServiceHandler = new ServiceHandler(mServiceLooper);
  }

  @Override
  public int onStartCommand(Intent intent, int flags, int startId) {
      Toast.makeText(this, "service starting", Toast.LENGTH_SHORT).show();

      // For each start request, send a message to start a job and deliver the
      // start ID so we know which request we‘re stopping when we finish the job
      Message msg = mServiceHandler.obtainMessage();
      msg.arg1 = startId;
      mServiceHandler.sendMessage(msg);

      // If we get killed, after returning from here, restart
      return START_STICKY;
  }

  @Override
  public IBinder onBind(Intent intent) {
      // We don‘t provide binding, so return null
      return null;
  }

  @Override
  public void onDestroy() {
    Toast.makeText(this, "service done", Toast.LENGTH_SHORT).show();
  }
}

是不是累觉不爱,果断IntentService好啊。

然而,如果你希望实现并发操作,即不等上一个请求执行完毕就进行下一个请求的话,那么直接继承service是有必要的。

注意到onStartCommand()方法必须返回一个整型变量。这个整型变量用来指定当系统杀死service后应当如何返回。以下是各个返回值:

START_NOT_STICKY

系统杀死service后不会重新创建该service,除非需要传递pending intents。适用于当你的程序可以简单的重启未完成任务的service。

START_STICKY

如果系统杀死了service,那么之后会重启该service并且调用onStartCommand(),但是不会重新发送上一个intent,而是返回一个null的intent(除非是一个pending intents。)这种模式很适合音乐播放器这种不需要执行commands,但是需要独立运行并且等待任务的service。

START_REDELIVER_INTENT

如果系统杀死了service,那么之后会重启该service并且掉哦那个onStartCommand(),并且会传递上一个intent。这中模式适合那些需要立即返回的service,例如下载文件。

以绑定方式启动service

详见Android开发文档翻译之-Bound Services

给用户发送通知

一旦service运行,你可以通过Toast Notifications或者Status Bar Notifications来告知用户某些事件。

Toast Notifications是一种短时间内出现在当前窗口表面的一条消息。Status Bar Notifications是一种提供了图标和消息的通知栏,用户可以通过点击来执行某个动作(例如开启一个activity)

前台Service

前台Service通常用来执行一些需要用户意识到正在执行的一些操作,因此系统在低内存状态时也不会kill掉该service。前台Service需要在状态栏上提供一个通知,该通知不会消失,直到service被停止或者从前台移除。

例如,音乐播放器Service应该是被设置为运行在前台的service,因为用户应该一直意识到这个操作。状态栏应该显示当前正在播放的歌曲,并且当前点击后应该跳转到能和用户进行交互的activity。

通过调用startForeground()函数可以让你的service运行在前台。使用示例如下:

Notification notification = new Notification(R.drawable.icon, getText(R.string.ticker_text),
        System.currentTimeMillis());
Intent notificationIntent = new Intent(this, ExampleActivity.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0, notificationIntent, 0);
notification.setLatestEventInfo(this, getText(R.string.notification_title),
        getText(R.string.notification_message), pendingIntent);
startForeground(ONGOING_NOTIFICATION_ID, notification);

管理Service的生命周期

Service的生命周期相对Activity要简单的多。但是却更需要你注意,因为通常service是运行在后台的。

Service的生命周期一般而言分为以下两种:

Service的生命周期如上图所示。

原文链接:Android API文档之Services

时间: 2024-10-22 09:55:23

Android开发文档翻译之-Services的相关文章

android开发文档翻译

============问题描述============ 这段话麻烦谁能准确翻译一下. The other component type, content provider, is not activated by intents. Rather, it is activated when targeted by a request from a ContentResolver. The content resolver handles all direct transactions with 

android &lt;application&gt; 开发文档翻译

由于本人英文能力实在有限,不足之初敬请谅解 本博客只要没有注明"转",那么均为原创,转贴请注明本博客链接链接 <application>语法:    <application android:allowTaskReparenting=["true" | "false"]                 android:allowBackup=["true" | "false"]      

Android开发之手把手教你写ButterKnife框架(二)

欢迎转载,转载请标明出处: http://blog.csdn.net/johnny901114/article/details/52664112 本文出自:[余志强的博客] 上一篇博客Android开发之手把手教你写ButterKnife框架(一)我们讲了ButterKnife是什么.ButterKnife的作用和功能介绍以及ButterKnife的实现原理. 本篇博客主要讲在android studio中如何使用apt. 一.新建个项目, 然后创建一个module名叫processor 新建m

Android开发快速入门(环境配置)

Android是一种激动人心的开源移动平台,它像手机一样无处不在,得到了Google以及其他一些开放手机联盟成员(如三星.HTC.中国移动.Verizon和AT&T等)的支持,因而不能不加以学习,否则你承担不起为此付出的代价. 好在Android开发入门很容易,即使没有Android手机都没关系,只需有一台可供安装Android SDK和设备模拟器的计算机即可. 本章首先介绍如何安装所有的开发工具,然后再创建一个可运行的应用——Android版“Hello, World”.如果你并非Androi

ArcGIS Runtime for Android开发教程V2.0(3)基础篇---Hello World Map

原文地址: ArcGIS Runtime for Android开发教程V2.0(3)基础篇---Hello World Map - ArcGIS_Mobile的专栏 - 博客频道 - CSDN.NET http://blog.csdn.net/arcgis_mobile/article/details/8124005 通过上面章节,我们已经了解如何配置一个ArcGIS Runtime for Android开发环境,下面我们将介绍如何使用Eclipse创建一个ArcGIS移动项目Hello W

《ArcGIS Runtime SDK for Android开发笔记》——(9)、空间数据的容器-地图MapView

1.前言 在上一篇内容里介绍了 关于ArcGIS Android开发的未来(“Quartz”版Beta)相关内容,期间也提到了关于API接口的重构,开发思路的调整,根据2015UC资料也可以知道新版预计将在明年的时候推出.届时在开发思路上将会往新版迁移. 总的来说,虽然“Quartz”版的开发思路有所变化,但总体变化不大,这里我将继续以现有正式发布版本为主梳理ArcGIS Runtime SDK for Android 开发内容. 参考API版本号:version 10.2.7.后续内容若不做特

【转】Android开发工具--android-studio-bundle-141.2288178

原文网址:http://www.androiddevtools.cn/ AndroidDevTools简介 Android Dev Tools官网地址:www.androiddevtools.cn 收集整理Android开发所需的Android SDK.开发中用到的工具.Android开发教程.Android设计规范,免费的设计素材等. 欢迎大家推荐自己在Android开发过程中用的好用的工具.学习开发教程.用到设计素材,欢迎Star.Fork ?. 如果你对翻译英文的Android开发技术文章

ArcGIS Runtime for Android开发教程V2.0(4)基础篇---MapView

原文地址: ArcGIS Runtime for Android开发教程V2.0(4)基础篇---MapView - ArcGIS_Mobile的专栏 - 博客频道 - CSDN.NET http://blog.csdn.net/arcgis_mobile/article/details/8147328 MapView是ArcGIS Runtime SDK forAndroid的核心组件,通过MapView可以呈现地图服务的数据,并且在MapView中定义了丰富的属性.方法和事件,用户通过Map

android开发中遇到的问题汇总【九】

244.http请求的url含有中字符时.须要Uri编码.Uri.encoder() 245.使用androidstudio时,不知道什么原因svn不见了 Android Studio missing Subversion plugin Please make sure that the "SubversionIntegration" plugin is enabled in Preferences > Plugins 246.Error:Execution failed for