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

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

  1. Android 开发环境搭建以及工具(不断更新)

    学习android需要学习的编程知识 https://wiki.cyanogenmod.org/w/Doc:_Development_Resources 从http://source.android. ...

  2. [译]:Xamarin.Android开发入门——Hello,Android Multiscreen深入理解

    原文链接:Hello, Android Multiscreen_DeepDive. 译文链接:Xamarin.Android开发入门--Hello,Android Multiscreen深入理解. 本 ...

  3. Android开发学习清单

    目录: 第1章 Android应用与开发环境1.1 Android的发展和历史1.1.1 Android的发展和简介1.1.2 Android平台架构及特性1.2 搭建Android开发环境1.2.1 ...

  4. Android开发快速入门(环境配置、Android Studio安装)

    Android是一种激动人心的开源移动平台,它像手机一样无处不在,得到了Google以及其他一些开放手机联盟成员(如三星.HTC.中国移动.Verizon和AT&T等)的支持,因而不能不加以学 ...

  5. Android开发自学笔记(Android Studio1.3.1)—3.Android应用结构解析

    一.R文件是什么?      如上图所示,我们可以通过findViewById方法通过传入R.id.show找到我们的TextView元素,findViewById方法也很好理解,从View中通过Id ...

  6. 一个帖子学会Android开发四大组件

    来自:http://www.cnblogs.com/pepcod/archive/2013/02/11/2937403.html 这个文章主要是讲Android开发的四大组件,本文主要分为 一.Act ...

  7. Android开发-API指南-服务

    Service 英文原文:http://developer.android.com/guide/components/services.html 采集(更新)日期:2014-12-23 原博客:htt ...

  8. Android开发-API指南-应用程序开发基础

    Application Fundamentals 英文原文:http://developer.android.com/guide/components/fundamentals.html 采集(更新) ...

  9. 【Android 应用开发】Android 开发环境下载地址 -- 百度网盘 adt-bundle android-studio sdk adt 下载

    19af543b068bdb7f27787c2bc69aba7f Additional Download (32-, 64-bit) Package r10 STL debug info androi ...

随机推荐

  1. springmvc请求方法那些事

    @RequestMapping 用法详解之地址映射 (2013-08-11 16:06:58) 转载▼ 标签: it   前段时间项目中用到了RESTful模式来开发程序,但是当用POST.PUT模式 ...

  2. vue 父子组件的加载顺序

    一.加载渲染过程 父beforeCreate->父created->父beforeMount->子beforeCreate->子created->子beforeMount ...

  3. Python自动化测试框架——生成测试报告

    如何才能让用例自动运行完之后,生成一张直观可看易懂的测试报告呢? 小编使用的是unittest的一个扩展HTMLTestRunner 环境准备 使用之前,我们需要下载HTMLTestRunner.py ...

  4. Go:json(序列化、反序列化)

    一.示例 package main import ( "encoding/json" "fmt" ) type Person struct { Name str ...

  5. Nowcoder 106 C.Professional Manager(统计并查集的个数)

    题意: 给出四种操作: 1. 合并u,v两棵树 2. 从u所在的集合中删除u 3. 询问u所在集合有多少颗树 4. 询问 u,v是否在同一个集合 分析: 对于删除操作, 只要新开一个点代替原来的点即可 ...

  6. unittest多线程生成报告(BeautifulReport)

    前言 selenium多线程跑用例,这个前面一篇已经解决了,如何生成一个测试报告这个是难点,刚好在github上有个大神分享了BeautifulReport,完美的结合起来,就能生成报告了. 环境必备 ...

  7. 大数据学习——yum练习安装mysql

    1. 安装mysql 服务器端: yum install mysql-server yum install mysql-devel 2. 安装mysql客户端: yum install mysql 3 ...

  8. 【数据传输 1】服务器—>客户端之间的数据类型转换

    导读:在做项目的时候,在controller中,将List数据类型转换为了JSON字符串,那么,为什么要将其数据转换为JOSN呢?这样的转换是否是必须的,在这个转换过程中,又经过了那些步骤?注:本篇博 ...

  9. Thread 1 cannot allocate new log 的处理办法

    ALTER SYSTEM ARCHIVE LOG Thread 1 cannot allocate new log, sequence 2594 Checkpoint not complete 这个实 ...

  10. uva12558 Egyptian Fractions (HARD version)(迭代深搜)

    Egyptian Fractions (HARD version) 题解:迭代深搜模板题,因为最小个数,以此为乐观估价函数来迭代深搜,就可以了. #include<cstdio> #inc ...