定义
服务,Android四大组件之一,属于计算型组件
作用
提供需长期在后台运行的的服务
特点
无用户界面,在后台运行,生命周期长
生命周期
Service服务有两种启动的方式:
- 通过调用startService()启动服务
- 通过调用bindService()启动服务
通过startService()启动服务的生命周期
1.手动调用 startService() 方法
2.onCreate()
3.onStartCommand()
4.手动调用 stopService() 方法
5.onDestroy()通过bindService()启动服务的生命周期
1.手动调用 bindService() 方法
2.onCreeate()
3.onBind()
4.手动调用 unbindService() 方法
5.onUnbind()
6.onDestroy()
Service服务的生命周期还有一种情况:先调用starService()启动服务后,再调用bindService()进行绑定
- 先调用startService()启动服务,后调用bindService()绑定服务的生命周期
1.手动调用 starService() 方法
2.onCreate()
3.onStartCommand()
4.服务运行中,手动调用 bindService() 方法
5.onBind()
6.绑定完成,服务运行中,手动调用 unbindService() 方法
7.onUnbind()
8.解除绑定完成,手动调用 stopService() 方法
9.onDestroy()
生命周期中4个手动调用的方法
1.startService()
2.stopService()
3.bindService()
4.unbindService()
1.startService()
- 作用:启动服务
- 自动调用的方法:onCreate() 、onStartCommand()
- 备注:onCreate()方法在生命周期中只调用一次,若 非首次调用 startService(),则跳过onCreate()方法直接调用onStartCommand()
onStartCommand()方法必须返回一个整数:描述在系统杀死服务后该如何继续运行
a. START_NOT_STICKY:不会重建服务,除非还存在未发送的intent,当服务不再是必须的,并且应用程序能够简单的重启那些未完成的工作时,这是避免服务运行的最安全的选项
b. START_STICKY:重建服务且调用onstartCommand(),但不会再次送入上一个intent,而是用一个null的intent来调用startCommand()。除非还有启动服务的intent未发送完,那么这些剩下的intent会继续发送
c. START_REDELIVER_INTENT:重建服务并用上一个已送过的intent调用onStartCommand() 。任何未发送完的intent也都会依次送入(适用于那些需要立即恢复工作的活跃服务,比如下载文件)
2.stopService()
- 作用:停止服务
- 自动调用的方法:onDestroy()
启动后绑定同个Service,若无解绑的前提下调用stopService()方法是无法停止服务的
3.bindService()
- 作用:绑定服务
- 自动调用的方法:onCreate() 、onBind()
4.unbindService()
- 作用:解绑服务
- 自动调用的方法:onUnbind() 、onDestroy()
Service的分类
类型
Service可按照运行地点、运行类型、功能进行分类
- 运行地点:本地服务 、远程服务
- 运行类型:前台服务、后台服务
- 功能:可通信服务、不可通信服务
详细介绍
1.按 运行地点 分类
- 本地服务
- 特点:运行在主线进 、 主线程终止后,服务也会停止
- 优点:节约资源 、 通信方便(由于在同一进程因此不需要IPC和AIDL进行通信)
- 缺点:限制性大(主线程终止后,服务也停止)
- 应用场景:需依附某个进程的服务
- 远程服务
- 特点:运行在独立进程 、 服务常驻后台,不受Activity影响
- 优点:灵活(服务常驻在后台,不受其他Activity影响)
- 缺点:消耗资源 、 通信复杂(AIDL或IPC)
- 应用场景:系统级别服务
2.按 运行类型 分类
-
前台服务
- 特点:在通知栏显示通知(用户可看到)
- 应用场景:服务使用时,需让用户知道并进行相关的操作(如:音乐播放服务)
-
后台服务
- 特点:处于后台的服务(用户无法看到)
- 应用场景:服务使用时不需要让用户知道并进行相关的操作(如:天气的更新、日期同步)
3.按照 功能 分类
- 不可通信服务
- 特点:用startService()启动,调用者推出后Service仍然存在
- 应用场景:服务不需与Activity或Service通信
- 可通信服务
-
通过调用bindService()启动
- 特点:调用者退出后,随着调用者销毁
- 应用场景:服务需与Activity通信,需控制服务开始时刻
- 节约系统资源 = 第一次bindService()时才会创建服务的实例并运行:特别当服务 = Remote Service时,该效果越明显
- 服务只是公开一个远程接口,供客户端远程调用执行方法
-
通过调用startService() 、 bindService()启动
- 特点:调用者退出后 ,随着调用者销毁
- 应用场景:需与Activity通信,不需要控制服务开始时刻(服务一开始就运行)
-
使用讲解
-
本地服务:这是最普通、最常用的后台服务
-
使用步骤:
1.新建子类继承Service类
2.构建用于启动Service的Intent对象
3.调用startService()启动Service,调用stopService()停止Service
4.在清单配置文件 AndroidMainfest.xml里注册Service//注册Service服务 <service android:name=".MyService"//Service的类名 android:label="xxxx"///Service的名字,若不设置,默认Service类名 android:icon="xxxxxx"//Service图标 android:permission="xxxxxx"//申明此Service的权限,有提供了该权限的应用才能控制或连接此服务 android:process="xxxxxx"//表示该服务时候在另一个进程中运行(远程服务)。默认本地服务,remote则设置远程服务 android:enabled="true"//系统默认启动 android:exported="xxxxx"//该服务时候能够被其他应用程序所控制或连接 > </service>
-
-
可通讯的Service
上述本地Service只能单机使用,不能用于通信
通过 bindService() 方法绑定的服务能达到通信功能
-
步骤:
1.新建子类MyService类继承Service类的类,并新建一个子类继承Binder类,写入与Acticity关联需要的方法,创建实例。public class MyService extends Service { private MyBinder mBinder = new MyBinder(); //.....这里省略其他方法...... //新建一个子类继承自Binder类 class MyBinder extends Binder { public void service_connect_Activity() { System.out.println("Service关联了Activity,并在Activity执行了Service的方法"); } } }
2.构建启动Service的Intent对象,创建ServiceConnection的匿名类
//创建ServiceConnection的匿名类 private ServiceConnection connection = new ServiceConnection() { //重写onServiceConnected()方法和onServiceDisconnected()方法 //在Activity与Service建立关联和解除关联的时候调用 @Override public void onServiceDisconnected(ComponentName name) { } //在Activity与Service解除关联的时候调用 @Override public void onServiceConnected(ComponentName name, IBinder service) { //实例化Service的内部类myBinder //通过向下转型得到了MyBinder的实例 myBinder = (MyService.MyBinder) service; //在Activity调用Service类的方法 myBinder.service_connect_Activity(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Intent bindIntent = new Intent(this, MyService.class); //调用bindService()方法,以此启动服务 bindService(bindIntent,connection,BIND_AUTO_CREATE); //参数说明 //第一个参数:Intent对象 //第二个参数:上面创建的Serviceconnection实例 //第三个参数:标志位 //这里传入BIND_AUTO_CREATE表示在Activity和Service建立关联后自动创建Service //这会使得MyService中的onCreate()方法得到执行,但onStartCommand()方法不会执行 }
前台服务
前台服务于后台服务最大的区别就在于:前台服务在下拉通知栏有显示通知,后台服务没有
此外,前台服务的优先级比较高,不会因为系统内存不足而被回收
-
使用:在原有的Service类对onCreate()方法进行稍微修改即可
@Override public void onCreate() { super.onCreate(); System.out.println("执行了onCreat()"); //添加下列代码将后台Service变成前台Service //构建"点击通知后打开MainActivity"的Intent对象 Intent notificationIntent = new Intent(this,MainActivity.class); PendingIntent pendingIntent = PendingIntent.getActivity(this,0,notificationIntent,0); //新建Builer对象 Notification.Builder builer = new Notification.Builder(this); builer.setContentTitle("前台服务通知的标题");//设置通知的标题 builer.setContentText("前台服务通知的内容");//设置通知的内容 builer.setSmallIcon(R.mipmap.ic_launcher);//设置通知的图标 builer.setContentIntent(pendingIntent);//设置点击通知后的操作 Notification notification = builer.getNotification();//将Builder对象转变成普通的notification startForeground(1, notification);//让Service变成前台Service,并在系统的状态栏显示出来 }
对于安卓8.0及以上的版本:调用 startForeground(1,notification) 方法可能会报错
Service与Thread的区别
相同点
- Service与Thread的作用都是进行 异步操作 。
不同点
- Service是运行在 进程 的 主线程 上(依赖于进程),只要进程在,Service就可以继续运行。所有Activity都可以与Service关联,获得Binder实例后操作其中的方法。若要进行耗时操作需创建子线程。
- Thread是运行在 Activity 上的 工作线程 上(依赖于某一Activity),无法跨Activity操作子线程。当Activity销毁后,就无法获取到子线程的实例。
实际开发中一般会将Service与Thread相结合,即在Service中创建一个工作线程进行耗时操作。
多线程
- 多线程的应用在开发中非常常见,主要有:
1.继承Thread类
2.实现Runnable接口
3.AsyncTask
4.Handler
5.HandlerThread
6.IntentService
感谢
文章出处:简书大神Carson_Ho
博客地址://www.greatytc.com/p/d963c55c3ab9