Service是android系统中的四大组件之一,它是一种长生命周期的、没有可视化界面、运行于后台的一种服务程序。主要负责更新数据源和可见的Activity,以及触发通知。服务可由其他应用组件启动(如Activity),服务一旦被启动将在后台一直运行
与activity、application一样继承了Context抽象类。 Service本身就是Context的实现,所以只需要调用this.
服务可由其他应用组件启动(如Activity),服务一旦被启动将在后台一直运行,即使启动服务的组件(Activity)已销毁也不受影响。 此外,组件可以绑定到服务,以与之进行交互,甚至是执行进程间通信 (IPC)。 例如,服务可以处理网络事务、播放音乐,执行文件 I/O 或与内容提供程序交互,而所有这一切均可在后台进行。
进程拉活
不管哪种启动方式,都需要在xml里注册Service:
<service android:name=".packnameName.youServiceName" android:enabled="true" />通过public ComponentName startService(Intent service)方法去启动一个Service,此时Service的生命周期与启动它的Context无关。
开启Service,调用者退出后Service仍然存在,需手动调用才可以停止服务。 当应用组件(如 Activity)通过调用 startService() 启动服务时,服务即处于“启动”状态。 已启动的服务通常是执行单一操作,而且不会将结果返回给调用方。
通过public boolean bindService(Intent service,ServiceConnection conn,int flags) 方法来进行Service与Context的关联并启动,并且Service的生命周期依附于Context。 开启Service,调用者退出后Service也随即退出。 当应用组件通过调用 bindService() 绑定到服务时,服务即处于“绑定”状态。绑定服务提供了一个客户端-服务器接口,允许组件与服务进行交互、发送请求、获取结果,甚至是利用进程间通信 (IPC) 跨进程执行这些操作。 仅当与另一个应用组件绑定时,绑定服务才会运行。 多个组件可以同时绑定到该服务,但全部取消绑定后,该服务即会被销毁。
通过bindService的方式,可是实现Activity如与Service通信: 先在Activity里实现一个ServiceConnection接口,并将该接口传递给bindService()方法,在ServiceConnection接口的onServiceConnected()方法里执行相关操作。
通过在AndroidManifest.xml中可以申明android:process是否remote Service。
对应的Service运行在主进程的main线程上的。如:onCreate,onStart这些函数在被系统调用的时候都是在主进程的main线程上运行的。
对应的Service运行在独立进程的main线程上。单独在进程中运行。
为了在使用Service时,系统能够找到此自定义Service。
首次创建服务时,系统将调用此方法来执行一次性设置程序(在调用 onStartCommand() 或onBind() 之前)。如果服务已在运行,则不会调用此方法,该方法只调用一次。
onStart已经deprecated,在Android2.0以下版本使用,建议使用onStartCommand替代。 onStart和onStartCommand两个方法放在一起使用时,不会产生冲突。
当另一个组件(如 Activity)通过调用 startService() 请求启动服务时,系统将调用此方法。一旦执行此方法,服务即会启动并可在后台无限期运行。 如果自己实现此方法,则需要在服务工作完成后,通过调用 stopSelf() 或 stopService() 来停止服务。(在绑定状态下,无需实现此方法。)
当服务不再使用且将被销毁时,系统将调用此方法。服务应该实现此方法来清理所有资源,如线程、注册的侦听器、接收器等,这是服务接收的最后一个调用。 在服务的外部,必须使用stopService()方法停止,在服务的内部可以调用stopSelf()方法停止当前服务。
当另一个组件想通过调用 bindService() 与服务绑定(例如执行 RPC)时,系统将调用此方法。在此方法的实现中,必须返回 一个IBinder 接口的实现类,供客户端用来与服务进行通信。无论是启动状态还是绑定状态,此方法必须重写,但在启动状态的情况下直接返回 null。
两种启动类型,都是通过继承Service基类自定义而来。
开启Service,调用者退出后Service仍然存在。 context.startService() –> onCreate() –> onStart() (可多次调用) –> Service running context.stopService() –> onDestroy() –> Service stop
开启的service通过其他组件调用 context.startService(Intent serviceIntent)。
这种service可以无限地运行下去,必须调用stopSelf()方法(在Service内部)或者其他组件调用context.stopService(Intent serviceIntent)方法来停止它。
当service被停止时,系统会销毁它
无法设置Service粘性。开启Service,调用者退出后Service也随即退出。
bindService()方法执行成功同时onBind()方法返回非空IBinder对象,触发ServiceConnection接口的onServiceConnected()方法。 context.bindService() –> onCreate() –> onBind() –> Service running onUnbind() –> onDestroy() –> Service stop
被绑定的service是当其他组件(一个客户)调用bindService()来创建的。
客户可以通过一个IBinder接口和service进行通信。
客户可以通过 unbindService()方法来关闭这种连接。
一个service可以同时和多个客户绑定,当多个客户都解除绑定之后,系统会销毁service。
onCreate() -> onStartCommnad() -> onBind() -> onUnBind() -> onDestory
首先,一定要说的是,两者没有半毛线关心。
①Thread 是程序执行的最小单元,它是分配CPU的基本单位,android系统中UI线程也是线程的一种,当然Thread还可以用于执行一些耗时异步的操作。 ②Service是Android的一种机制,服务是运行在主线程上的,它是由系统进程托管。它与其他组件之间的通信类似于client和server,是一种轻量级的IPC通信,这种通信的载体是binder,它是在linux层交换信息的一种IPC,而所谓的Service后台任务只不过是指没有UI的组件罢了。
在android系统中,线程一般指的是工作线程(即后台线程),而主线程是一种特殊的工作线程,它负责将事件分派给相应的用户界面小工具,如绘图事件及事件响应,因此为了保证应用 UI 的响应能力主线程上不可执行耗时操作。如果执行的操作不能很快完成,则应确保它们在单独的工作线程执行。
Service 则是android系统中的组件,一般情况下它运行于主线程中,因此在Service中是不可以执行耗时操作的,否则系统会报ANR异常,之所以称Service为后台服务,大部分原因是它本身没有UI,用户无法感知(当然也可以利用某些手段让用户知道),但如果需要让Service执行耗时任务,可在Service中开启单独线程去执行。 所以在使用中,需要在Service中再创建一个子线程,然后在这里去处理耗时逻辑。
Service用于后台操作。 Android的后台就是指,它的运行是完全不依赖UI的。即使Activity被销毁,或者程序被关闭,只要进程还在,Service就可以继续运行。比如说一些应用程序,始终需要与服务器之间始终保持着心跳连接,就可以使用Service来实现。 使用Service来处理后台任务,Activity就可以放心地finish,完全不需要担心无法对后台任务进行控制的情况。
当要执行耗时的网络或者数据库查询以及其他阻塞UI线程或密集使用CPU的任务时,都应该使用工作线程(Thread),这样才能保证UI线程不被占用而影响用户体验。
在应用程序中,如果需要长时间的在后台运行,而且不需要交互的情况下,使用服务。比如播放音乐,通过Service+Notification方式在后台执行同时在通知栏显示着。
这是因为Activity很难对Thread进行控制,当Activity被销毁之后,就没有任何其它的办法可以再重新获取到之前创建的子线程的实例。而且在一个Activity中创建的子线程,另一个Activity无法对其进行操作。但是Service就不同了,所有的Activity都可以与Service进行关联,然后可以很方便地操作其中的方法,即使Activity被销毁了,之后只要重新与Service建立关联,就又能够获取到原有的Service中Binder的实例。因此,使用Service来处理后台任务,Activity就可以放心地finish,完全不需要担心无法对后台任务进行控制的情况。
Service的系统优先级比较低,当系统出现内存不足情况时,就有可能会回收掉正在后台运行的Service。 如果要Service一直保持运行状态,而不会由于系统内存不足的原因导致被回收,就可以考虑使用前台Service。
前台Service会一直有一个正在运行的图标在系统的状态栏显示,下拉状态栏后可以看到更加详细的信息,非常类似于通知的效果。当然有时候你也可能不仅仅是为了防止Service被回收才使用前台Service,有些项目由于特殊的需求会要求必须使用前台Service,比如说墨迹天气,它的Service在后台更新天气数据的同时,还会在系统状态栏一直显示当前天气的信息。
在ForegroundService类中,创建了一个notification的通知,并通过启动Service时传递过来的参数判断是启动前台服务还是关闭前台服务,最后在onDestroy方法被调用时,也应该移除前台服务。
public class ForegroundService extends Service { /** * id不可设置为0,否则不能设置为前台service */ private static final int NOTIFICATION_DOWNLOAD_PROGRESS_ID = 0x0001; private boolean isRemove=false;//是否需要移除 /** * Notification */ public void createNotification(){ //使用兼容版本 NotificationCompat.Builder builder=new NotificationCompat.Builder(this); //设置状态栏的通知图标 builder.setSmallIcon(R.mipmap.ic_launcher); //设置通知栏横条的图标 builder.setLargeIcon(BitmapFactory.decodeResource(getResources(),R.drawable.screenflash_logo)); //禁止用户点击删除按钮删除 builder.setAutoCancel(false); //禁止滑动删除 builder.setOngoing(true); //右上角的时间显示 builder.setShowWhen(true); //设置通知栏的标题内容 builder.setContentTitle("I am Foreground Service!!!"); //创建通知 Notification notification = builder.build(); //设置为前台服务 startForeground(NOTIFICATION_DOWNLOAD_PROGRESS_ID,notification); } @Override public int onStartCommand(Intent intent, int flags, int startId) { int i=intent.getExtras().getInt("cmd"); if(i==0){ if(!isRemove) { createNotification(); } isRemove=true; }else { //移除前台服务 if (isRemove) { stopForeground(true); } isRemove=false; } return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { //移除前台服务 if (isRemove) { stopForeground(true); } isRemove=false; super.onDestroy(); } @Nullable @Override public IBinder onBind(Intent intent) { return null; } } public class ForegroundActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_foreground); Button btnStart= (Button) findViewById(R.id.startForeground); Button btnStop= (Button) findViewById(R.id.stopForeground); final Intent intent = new Intent(this,ForegroundService.class); btnStart.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { intent.putExtra("cmd",0);//0,开启前台服务,1,关闭前台服务 startService(intent); } }); btnStop.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { intent.putExtra("cmd",1);//0,开启前台服务,1,关闭前台服务 startService(intent); } }); } }IntentService是Service的子类,是一个异步的,会自动停止的服务,很好解决了传统的Service中处理完耗时操作忘记停止并销毁Service的问题。
底层用到了线程。内部采用HandlerThread来执行任务,当任务执行完毕后IntentService会自动退出。
IntentService是一种特殊的Service,是继承了Service的抽象类。
①不需要自己去new Thread ②不需要考虑在什么时候关闭该Service ③IntentService是一种服务,不轻易被系统杀死。而HandlerThread是一个后台进程,优先级很低,容易被系统杀死。
IntentService用于执行后台耗时任务,当任务执行后会自动停止。 适合执行优先级高的后台任务。
节制的使用Service,当启动一个Service时,系统总是倾向于保留这个Service依赖的进程,这样会造成系统资源的浪费,可以使用IntentService,执行完成任务后会自动停止。
在子线程的handler中回调。
