自以下总结:
Android下的Service组件,对于Service组件,有点类似于Windows下的服务。Service是Android
四大组件中与Activity最相似的组件,它们的区别在于:Service一直在后台运行,它没有用户界面。一旦Service被启动起来 之后,它就与Activity一样,也具有自己的生命周期。
在开发过程中,对于Activity与Service的选择标准是:如果某个程序组件需要在运行时向用户呈现某种界面,或
者该程序需要与用户交互,就需要使用Activity,否则就应该考虑使用Service。
Service概述
与开发一个Activity类似,它需要继承Service这个抽象类,并在实现类中,需要重写一些回调方法,用于处理
Service的生命周期各部分的操作。而Service也是继承自Context,因此它也可以调用Context里定义的如getResource()、
getContentResolver()等方法。
Service中定义的生命周期方法,对Service服务的开发大部分工作就围绕以下几个方法进行操作:
void onCreate():当该Service第一次被创建后将立即回调该方法。通过服务的启动方式与适用范围,可将服务分为两类服务:
void onStartCommand(Intent intent,int flags,int startId):每次通过startService()方法启动Service时都会被回调。
void onDestroy():当Service被关闭前会被回调。
abstract IBinder onBind(Intent intent):该方法是Service子类必须实现的方法,如果不需要通过绑定的方式启动服务,可以返回Null。
boolean onUnbind(Intent intent):当Service上绑定的所有客户端都断开连接将回调该方法。
start:启动服务,当一个Android组件(如一个Activity)调用startService()的时候,启动一个服务。服务一旦启
动,就可以一直在后台运行下去,即使这个启动它的组件被摧毁。这样的服务模式,通常用于执行一个操作而不需要返回结果给调用者。
Bound:绑定服务,当一个Android组件(如一个Activity)调用bindService()。一个绑定服务提供了一个客户端到服务端的接口,允许组件与服务之间进行交互,这样可以实现跨进程的通信。绑定服务的生命周期默认是跟随它的绑定组件的,但是一个绑定服务可以绑
定多个Android组件,如果这些Android组件都被销毁,那么这个绑定服务也将被销毁。
虽然上面提到了服务有两种类别,但是一个服务类所要继承的类是一样的,都是Service类。也就是说,一个服
务,可以包含上面两种运行方式的服务,只是与它重载的方法有关,如果重写了onStartCommand()即支持启动服务,如果重写onBiind()即支持绑定服务,所以如果同时重载实现这两个方法即可实现两种服务。
清单文件的配置
Service是Android四大组件之一,所以它也必须在 AndroidManifest清单文件中进行配置,否则系统将找不到这
个服务。与Activity一样,Service的配置也是在<application/>节点下,使用<service/>配置,其中android:name属性为Service类。
如果开发的服务需要被外部应用操作,还需要配置<intent-filter/>节点,但是如果仅本程序使用,则无需配置
它也可以。
如果这个服务强制仅本应用操作,可以配置<service/>节点的android:exported属性为false,这样即使配置
了<intent-filter/>,外部应用也无法操作这个服务,android:exported属性默认为true。
<application>
<!-- 普通的服务 -->
<service android:name=".Service1"></service>
<!-- 可被外部应用访问的服务 -->
<service android:name=".Service2">
<intent-filter >
<action android:name="com.bgxt.Service2"/>
</intent-filter>
</service>
<!-- 无法被外部应用访问的服务 -->
<service android:name=".Service3" android:exported="false">
<intent-filter >
<action android:name="com.bgxt.Service3"/>
</intent-filter>
</service>
</application>
Service的开发步骤
既然Service是一个与Activity类似的Android组件,所以它的开发步骤大致也为一下几步:
1.开发一个服务类,需要继承Service或者IntentService。
2.在AndroidManifest清单文件中注册Service组件。
3.在一个Android组件中启动这个开发的Service组件。
4.服务使用完成之后,需要停止这个服务。
启动服务
启动服务必须实现Service.onStartCommond()方法。启动服务使用startService(Intent intent)方法开启一个服务,
仅需要传递一个Intent对象即可,在Intent对象中指定需要启动的服务。而使用startService()方法启动的服务,在服务的外部,必须使用stopService()方法停止,在服务的内部可以调用stopSelf()方法停止当前服务。一旦使用startService()或者stopSelf()方法请求停止服务,系统会就会尽快销毁这个服务。
绑定服务
如果Service和宿主之间需要进行方法调用或者数据交换,则应该使用Context对象的bindService()和unbindService()方法 来绑定和解除绑定服务。
Context的bindService()方法的完整方法签名为:
bindService(Intent service,ServiceConnection conn,int flags)
下面简单介绍一下这个方法的三个参数的意义:
service:通过Intent指定要绑定的Service。
conn:一个ServiceConnection对象,该对象用于监听访问者与Service对象的onServiceConnected()方法。
flags:指定绑定时是否自动创建Service。0不自动创建、BIND_AUTO_CREATE,自动创建。
从上面的bindService方法可以看出,绑定一个服务于宿主交互,依托于一个ServiceConnection接口,这个接口
对象必须声明在主线程中,通过实现其中的两个方法,来实现与Service的交互,下面分别介绍一下这两个方法:
void onServiceConnection(ComponentName name,IBinder service):绑定服务的时候被回调,在这个方法获取绑
定Service传递过来的IBinder对象,通过这个IBinder对象,实现宿主和Service的交互。
void onServiceDisconnected(ComponentName name):当取消绑定的时候被回调。但正常情况下是不被调用的,
它的调用时机是当Service服务被意外销毁时,例如内存的资源不足时这个方法才被自动调用。
在使用绑定的服务的时候,该Service类必须提供一个IBinder onBind(Intent intent)方法,在绑定本地Service的情
况下,onBind()方法说返回的IBinder对象会传给宿主的ServiceConnection.onServiceConnected()方法的service参数,这样宿主就可以通过IBinder对象与Service进行通信。实际开发中一般会继承Binder类(IBinder的实现类)的方式实现自己的IBinder对象。
需要注意的是,如果绑定服务提供的onBind()方法返回为Null,则也可以使用bindService()启动服务,但不会
绑定上Service,因此宿主的ServiceConnection.onServiceConnected()方法不会被执行,也就不存在于宿主与服务的交互。
Service的选用
对于选用startService()还是使用bindService(),有一些原则需要讲明。如果仅仅是想要启动一个后台服务长期驻
留在内存中执行某项任务,那么仅使用startService()启动一个服务即可。但是如果想要与正在运行的服务进行交互,一种方式是使用broadcast,这个以后再介绍,另外一种方式就是使用bindService()绑定一个服务到组件上,使用broadcast的缺点是如果数据交互频繁,容易造成性能上的问题,并且BroadcastReceiver本身执行代码的时间不确定,也许代码执行到一半,后面的代码将不被执行,但是使用bindService()绑定服务即没有这些问题。另外,如果一个服务是依托于某项应用的,那么也最好使用绑定服务,在依托的应用启动的时候绑定服务,这样可以在不使用的时候避免浪费系统资源。
值得注意的是,Android下的Service组件也是运行在主线程中的,所以一些Android4.0+无法在主线程上
进行的操作,在Service中也必须另外开启线程来完成,如访问网络,还可以使用继承Service的子类IntentService来实现,这个内容会在之后的博客中介绍。Android系统本身还提供了大量的Service组件,开发人员可以通过这些系统Service来操作Android系统本身.
public class ItService extends Service {
private int count=0;
MyBinder binder=new MyBinder();
private boolean quit=false;
class MyBinder extends Binder
{
public int getCount(){
return count;
}
}
@Override
public IBinder onBind(Intent intent) {
Log.d("SERVICE","onBind");
return binder;
}
@Override
public void onCreate() {
super.onCreate();
new Thread(new Runnable() {
@Override
public void run() {
while(!quit) {
try {
Thread.sleep(100);
count++;
}catch (InterruptedException e){e.printStackTrace();}
}
}
}).start();
}
@Override
public void onDestroy() {
Log.d("SERVICE","onDestroy");
super.onDestroy();
binder=null;
quit=true;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d("SERVICE","onStartCommand");
return super.onStartCommand(intent, flags, startId);
}
@Override
public boolean onUnbind(Intent intent) {
Log.d("SERVICE", "onUnbind");
return super.onUnbind(intent);
}
}
public class ServiceActivity extends AppCompatActivity {
ItService.MyBinder binder=null;
ServiceConnection con=new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
binder=(ItService.MyBinder)service;
Log.d("SERVICE","connected");
}
@Override
public void onServiceDisconnected(ComponentName name) {
Log.d("SERVICE", "onServiceDisconnected");
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_service);
final Intent intent=new Intent(ServiceActivity.this,ItService.class);
Button bindServiceButton=(Button)findViewById(R.id.bindService);
Button unbindServiceButton=(Button)findViewById(R.id.unbindService);
Button getServiceStatusButton=(Button)findViewById(R.id.getServiceStatus);
bindServiceButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
bindService(intent,con,BIND_AUTO_CREATE);
}
});
unbindServiceButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
unbindService(con);
}
});
getServiceStatusButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if(binder==null){
Log.d("SERVICE","未绑定");
}
else{
Log.d("SERVICE","count=:"+binder.getCount());
Toast.makeText(ServiceActivity.this,
binder.getCount()+"",Toast.LENGTH_SHORT).show();
}
}
});
}
}
IntentService
对于Service而言,它依然是运行在主线程之上,所以一些无法在主线程上完成的功能,依然需要另外开启工作
线程来完成,并且一些耗时操作,如果直接放在Service的主线程中完成的话,会影响设备的运行流畅度。对于这样的问题,有两种解决方案,一种是在Service主线程中额外开启一条工作线程,如何开启工作线程的方法在以前的博客中已经介绍过了,这里不再重复介绍;另外一个方法就是使用IntentService这个父类来实现Service业务类,这里着重讲解这个IntentService。
IntentService是一个服务基类,直接继承于Service,在需要的时候通过异步调用的方式处理请求。要使用
IntentService启动一个服务进行异步调用,需要实现它的一个抽象方法:onHandleIntent(Intent intent),在这个方法里,可以获得访问这传来的Intent对象,并在其中进行异步操作的实现。对于IntentService而言,因为其继承自Service类,所以其他的Service的声明周期方法在此类中也适用,访问者可以通过调用Context.startService(Intent intent)方法来启动这个服务。
使用IntentService作为服务基类,在其内部其实也是重新开启了一条线程来完成操作,只是这里使用
IntentService进行了封装,并且它自己管理服务的结束。使用IntentService的服务类,在执行结束后执行结束,无需人为的结束它,比较适用于一些无需管理,但是又比较耗时的操作!
下面通过一个小示例演示IntentService的操作,在这个示例中,下载一张网络上的图片,保存在设备的本地
目录下。其中涉及到的本地存储和访问网络下载图片的内容,如果你不了解的朋友,可以查看另外两篇博客:Android--数据持久化、Android--HTTPClient。
package cn.bgxt.servicedemohigh;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.MalformedURLException;
import java.net.URL;
import android.app.IntentService;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;
public class IntentSer extends IntentService {
private final static String TAG = "main";
private String url_path="http://ww2.sinaimg.cn/bmiddle/9dc6852bjw1e8gk397jt9j20c8085dg6.jpg";
public IntentSer() {
super("IntentSer");
}
@Override
public void onCreate() {
Log.i(TAG, "Service is Created");
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.i(TAG, "Service is started");
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
Log.i(TAG, "Service is Destroyed");
super.onDestroy();
}
@Override
protected void onHandleIntent(Intent intent) {
Log.i(TAG, "HandleIntent is execute");
try {
// 在设备应用目录下创建一个文件
File file=new File(this.getFilesDir(), "weibo.jpg");
FileOutputStream fos=new FileOutputStream(file);
// 获取网络图片的输入流
InputStream inputStream = new URL(url_path).openStream();
// 把网络图片输入流写入文件的输出流中
byte[] date=new byte[1024];
int len=-1;
while((len=inputStream.read(date))!=-1){
fos.write(date, 0, len);
}
fos.close();
inputStream.close();
Log.i(TAG, "The file download is complete");
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
}
编写好服务类,仅需要适用一个Android组件即可启动服务,这里使用一个Activity中来启动服务,下
面是主要代码。
btnDownload=(Button)findViewById(R.id.btnDownload);
btnDownload.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
Intent service=new Intent(MainActivity.this,IntentSer.class);
startService(service);
}
});
Service与Thread的区别
对Service了解后,会发现它实现的大部分功能使用Thread也可以解决,并且Thread使用起来比Servic
e方便的多,那么为什么还需要使用Service呢,下面来详细解释一下。
首先,Thread是程序执行的最小单元,它是分配系统资源的基本单位,主要用于执行一些异步的操作。
而Service是Android的一种机制,当它使用bindService()被绑定的时候,是运行在宿主主进程的主线程上的,
当使用startService()启动服务的时候,是独立运行在独立进程的主线程上的,因此它们的核心没有任何关系。
其次,对于Thread而言,它是独立于启动它的组件的,如使用一个Activity启动了一个Thread,当这个
Activity被销毁前,没有主动停止Thread或者Thread的run()方法没有执行完毕的话,Thread也会一直执行下去
,这样就很容易导致一些问题,当这个Activity被销毁之后,将不再持有这个Thread的引用,也就是说,无
法再在另外一个Activity中对同一个Thread进行控制。而Service不同,在Android系统中,无论启动或绑定
几次,只会创建一个对应的Service实例,所以只要这个Service在运行,就可以在能获取到Context对象的地
方控制它,这些特点是Thread无法做到的。
不少Android初学者都可能会有这样的疑惑,Service和Thread到底有什么关系呢?什么时候应该用
Service,什么时候又应该用Thread?答案可能会有点让你吃惊,因为Service和Thread之间没有任何关
系!之所以有不少人会把它们联系起来,主要就是因为Service的后台概念。Thread我们大家都知道,
是用于开启一个子线程,在这里去执行一些耗时操作就不会阻塞主线程的运行。而Service我们最初理解
的时候,总会觉得它是用来处理一些后台任务的,一些比较耗时的操作也可以放在这里运行,这就会让人
产生混淆了。但是,如果我告诉你Service其实是运行在主线程里的,你还会觉得它和Thread有什么关系
吗?让我们看一下这个残酷的事实吧。
可以看到,它们的线程id完全是一样的,由此证实了Service确实是运行在主线程里的,也就是
说如果你在Service里编写了非常耗时的代码,程序必定会出现ANR的。你可能会惊呼,这不是坑爹么!?
那我要Service又有何用呢?其实大家不要把后台和子线程联系在一起就行了,这是两个完全不同
的概念。Android的后台就是指,它的运行是完全不依赖UI的。即使Activity被销毁,或者程序被关闭,
只要进程还在,Service就可以继续运行。比如说一些应用程序,始终需要与服务器之间始终保持着
心跳连接,就可以使用Service来实现。你可能又会问,前面不是刚刚验证过Service是运行在主线程
里的么?在这里一直执行着心跳连接,难道就不会阻塞主线程的运行吗?当然会,但是我们可以
在Service中再创建一个子线程,然后在这里去处理耗时逻辑就没问题了。
额,既然在Service里也要创建一个子线程,那为什么不直接在Activity里创建呢?这是因为Activity
很难对Thread进行控制,当Activity被销毁之后,就没有任何其它的办法可以再重新获取到之前创建的子
线程的实例。而且在一个Activity中创建的子线程,另一个Activity无法对其进行操作。但是Service就
不同了,所有的Activity都可以与Service进行关联,然后可以很方便地操作其中的方法,即使Activity
被销毁了,之后只要重新与Service建立关联,就又能够获取到原有的Service中Binder的实例。因此,
使用Service来处理后台任务,Activity就可以放心地finish,完全不需要担心无法对后台任务进行控制的情况。
Service生命周期详解
从上图可以看出,对于启动服务和绑定服务存在不同的生命周期,但是大部分调用的生命周期方法是一样
的,如onCreate()、onDestroy()等,并且无论是启动或是绑定多次同一个服务,onCreate()、onDestroy()等这些
共用的生命周期方法也仅被调用一次。它们唯一的区别就是当使用startService()启动服务的时候,回调的是
onStatrCommand()方法,而使用bindService()绑定服务的时候,回调的是onBind()方法,并且解除绑定的时
候还会回调onUnbind()方法。
启动服务:如果一个Service被Android组件调用startService()方法启动,那么不管这个Service对象是否
使用bindService()方法被访问者绑定过,该Service都会在后台运行。因为Android系统只会为一个Service服务创
建一个实例,所以无论启动几次,onCreate()方法仅执行一次,但是每次启动都会执行onStartCommand()方
法,一旦服务启动,不管访问者是否被销毁,服务将一直执行下去,除非被调用stopService()方法或者服务自
身的stopSelf()方法,当然系统资源不足的时候,也有可能回收结束服务回收资源。
绑定服务:如果一个Service被某个Android组件调用bindService()方法绑定服务,同样因为一个Service
只会被创建一个实例,所以不管bindService()被不同的组件调用几次,onCreate()方法都只被回调一次,
转而还会执行onBind()方法进行Binder对象的绑定。在绑定连接被建立后,Service将一直运行下去,除非
宿主调用unbindService()方法断开连接或者之前的宿主被销毁了,这个时候系统会检测这个Service是否
存在宿主绑定,当宿主绑定的数量为0的时候,系统将会自动停止服务,对应的onDestroy()将被回调。
正如上面提到的,Android系统仅会为一个Service创建一个实例,所以不管是使用启动服务或是绑定服务,
都操作的是同一个Service实例。但是如果两种服务运行方式均被调用,那么绑定服务将会转为启动服务运行
,这时就算之前绑定的宿主被销毁了,也不会影响服务的运行,而启动服务并不会因为有宿主调用了bindService()
方法而把原本的启动服务转为绑定服务,但是还是会与宿主产生绑定,但这时即使宿主解除绑定后,服务依然按
启动服务的生命周期在后台运行,直到有Context调用了stopService()或是服务本身调用了stopSelf()方法才会真正
销毁服务。这样理解感觉启动服务的优先级要比绑定服务高,当然不管哪种情况,被系统回收的资源不在此讨论的范围内。
所以综上所述,对于一个既使用startService()启动又使用bindService()绑定的服务,除非这个服务的两条生命周期
均完结,否则不会被销毁。也就是说,在不考虑系统在资源不足的时候,主动回收资源销毁服务的情况下,使用
startService()启动的服务,必须使用stopService()或是服务本身的stopSelf()停止服务,使用bindService()绑定的服务,
必须使用unbindService()或是销毁宿主来解除绑定,否则服务一直运行。
在实际项目中,经常会使用开始服务于绑定服务混合使用,这样既保证了一个有效的服务在后台长期运行,
又可以在需要的时候通过bindService()绑定服务,从而与服务进行交互。
前台服务
一个Service不管是被启动或是被绑定,默认是运行在后台的,但是有一种特殊的服务叫后台服务,它是一种能被
用户意识到它存在的服务,因此系统默认是不会自动销毁它的,但是必须提供一个状态栏通知,Notification,在通知
栏放置一个持续的标题,所以这个通知是不能被忽略的,除非服务被停止或从前台删除。关于通知栏的内容,可以查
看另外一篇博客:Android--通知之Notification。
这类服务主要用于一些需要用户能意识到它在后台运行,并且随时可以操作的业务,如音乐播放器,设置为
前台服务,使用一个Notification显示在通知栏,可以试用户切歌或是暂停之类的。
前台服务与普通服务的定义规则是一样的,也是需要继承Service,这里没有区别,唯一的区别是在服务里需要
使用Service.startFroeground()方法设置当前服务为一个前台服务,并为其制定Notification。下面是startForeground()
的完整签名。
public final void startForeground(int id,Notification notification)
其中的参数id是一个唯一标识通知的整数,但是这里注意这个整数一定不能为0,notification为前台服务的通知,
并且这个notification对象只需要使用startForeground()方法设置即可,无需像普通通知一样使用NotificationManager
对象操作通知。
前台服务可以通过调用stopService(boolean bool)来使当前服务退出前台,但是并不会停止服务,传递false即可。
有一点需要声明一下,startForeground()需要在Android2.0之后的版本才生效,在这之前的版本使用
setForeground()来设置前台服务,并且需要NotificationManager对象来管理通知,但是现在市面上的设备基本上已经很少有2.0或一下的设备了,所以也不用太在意。
前台服务--示例
下面通过一个示例来演示一个简单的前台服务,这个前台服务展示为一个通知,并且点击通知的时候会
开启一新的Activity
package cn.bgxt.servicedemohigh;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.app.Service;
import android.content.Context;
import android.content.Intent;
import android.os.IBinder;
import android.support.v4.app.NotificationCompat;
public class ForegroundSer extends Service {
private Notification notification;
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
// 声明一个通知,并对其进行属性设置
NotificationCompat.Builder mBuilder=new NotificationCompat.Builder(ForegroundSer.this)
.setSmallIcon(R.drawable.ic_launcher)
.setContentTitle("Foreground Service")
.setContentText("Foreground Service Started.");
// 声明一个Intent,用于设置点击通知后开启的Activity
Intent resuliIntent=new Intent(ForegroundSer.this, IntentSerActivity.class);
PendingIntent resultPendingIntent=PendingIntent.getActivity(ForegroundSer.this, 0, resuliIntent, PendingIntent.FLAG_CANCEL_CURRENT);
mBuilder.setContentIntent(resultPendingIntent);
notification=mBuilder.build();
// 把当前服务设定为前台服务,并指定显示的通知。
startForeground(1,notification);
}
@Override
public void onDestroy() {
super.onDestroy();
// 在服务销毁的时候,使当前服务推出前台,并销毁显示的通知
stopForeground(false);
}
}
public class ForegroundActivity extends Activity {
private Button btnForeStart,btnForeStop;
private Intent service;
@Override
protected void onCreate(Bundle savedInstanceState) {
// TODO Auto-generated method stub
super.onCreate(savedInstanceState);
setContentView(R.layout.layout_foreground);
btnForeStart=(Button)findViewById(R.id.btnForeStart);
btnForeStop=(Button)findViewById(R.id.btnForeStop);
service=new Intent(ForegroundActivity.this, ForegroundSer.class);
btnForeStart.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 开始服务
startService(service);
}
});
btnForeStop.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// 停止服务
stopService(service);
}
});
}
}
服务资源被系统意外回收
众所周知,Android系统会在系统资源不足的时候回收系统资源,如CPU、内存。这个时候就会强制销毁一
些优先级不高的后台组件,所以很可能用户启动的服务在还没有完成既定的业务的时候就被系统给回收了,这个时候需要制定当Service被意外销毁的时候,如何处理接下来的事情。
使用bindService()绑定的Service是与宿主组件相关的,所有如果宿主组件没有被系统回收销毁,这个服务除非宿
主主动解除绑定,直到这个服务没有宿主绑定,即才会被销毁,这种情况只需要关心与它绑定的组件的是否被销毁即
可。而对于使用startService()开启的服务而言,服务一旦开启,将与宿主无关,所以除了宿主调用stopService()或者服
务自己调用stopSelf()外,它很可能在系统资源不足的时候被回收,一般如果一些比较重要的任务,比如说下载文件、
发送备份数据等一些操作,是不允许服务被系统停止的,这里就需要设置服务被系统销毁后,如何处理的问题。
服务被系统销毁后,如何继续服务,可以使用Service.onStartCommand()方法的返回值设定,这个方法必须返回一
个整型,用于设定系统在销毁服务后如何处理,这些返回的整型被系统封装成了常量,一般常用的有:
START_NOT_STICKY:在系统销毁服务后,不重新创建服务,除非有额外的Intent启动服务。
START_STICKY:在系统销毁服务后,重新创建服务和调用onStartCommand(),但会依照一个空的
Intent对象执行任务,就如仅开始服务,但不执行命令,等待服务的继续工作。
START_REDELIVER_INTENT:在系统销毁服务后,重新创建和调用onStartCommand()方法,依据之前
启动它的Intent对象开启服务,进行之前未执行完的任务,如下载文件。
不被销毁的服务
如果想使一个Service对象常驻后台运行,在任何时候都不被销毁,这里涉及的内容比较多,有时间再细细的写。
这里主要提一下思路,为了保持一个Service示例常驻后台,需要考虑几个问题:
开机启动:Android系统开启的时候会发送一个action为android.intent.action.BOOT_COMPLETED的广播,只需要
一个广播接受者来接受这个Action,然后在其中启动服务即可。
意外停止:对于意外停止的服务,可以在服务的onDestory()方法中重新启动服务,这样刚销毁又重新启动。
意外销毁:当Service被意外销毁的时候,会发布一个action为android.intent.action.PACKAGE_RESTARTED
的广播,只需监听这个广播,在其中重新启动服务即可。
系统回收:系统在资源不足的情况下会回收资源,但是也是有一定的规则的,回收的资源必定是优先级低
的资源,所以提高Service的优先级,也可以保证一定的常驻系统后台,服务的优先级可以在清单文件中,配置<service/>节点下的<intent-filter/>节点的时候增加android:priority属性,将其的数值设定的比较高,此处数值越高,优先级越高,上线为1000。
上面介绍的思路基本上已经涵盖了让Service不被销毁的主要内容,还有一种极端的情况,可以使服务一旦启动,
将不会被销毁,那在配置服务的清单文件的时候,在<application/>节点中增加android:persistent属性,并将其设置
为true。但是这是最极端的情况,也不推荐使用,因为如果系统中安装了大量常驻组件,将会影响系统的使用。