一 Service
Service和其他组件一样,都是运行在主线程中,因此不能用它来做耗时的请求或者动作。你可以在服务中开一个线程,在线程中做耗时动作。
1.1 生命周期:
(1)单独使用startService():
onCreate()->onStartCommand()->Service running->onDestroy()->Service shut down
用stopService来结束service,调用完之后就与调用者无关了,记得服务完毕后及时关闭
(2)单独使用bindService():
onCreate()->onBind()->Clients are bound to service->onUnbind()->onDestroy()->Service shut down
1.2 对同一个service进行start和bind操作,生命周期和执行顺序
(1)startServic:调用onCreate()->onStartCommand()
(2)bindService:调用onBind()
(3)stopService:没有调用onDestory() Service仍然在运行!
(4)unbindService:调用onUnbind()->onDestory() 此时Service关闭!
若被停止的服务依然有ServiceConnection 与其绑定,则服务不能销毁,直至我们把所有ServiceConnection 解绑
** 1.3 startService和binderService区别 **
startService启动过后,用stopService来结束service,调用完之后就与调用者无关了,记得服务完毕后及时关闭,startservice并不能解决我们所有的需求,比如,我有时候,需要service的返回结果,我需要和service交互,startservice显然不能完成。那么我们可以使用到bindservice
3.3 前台Service
例子:音乐播放。将一个服务设置为前台服务,只需要在绑定时调用startForeground
将自己设置为前台服务即可
@Override
public IBinder onBind(Intent intent) {
//设置为前台服务
Notification.Builder builder = new Notification.Builder(this);
builder.setContentTitle("播放音乐中..").setContentText("Diamonds").setWhen(System.currentTimeMillis()).setLargeIcon(BitmapFactory.decodeResource(getResources(), R.mipmap.ic_launcher));
Notification notifation = builder.getNotification();
startForeground(2, notifation);
return mBinder;
}
@Override
public void onDestroy() {
super.onDestroy();
if (mediaPlayer != null)
mediaPlayer.release();
stopForeground(true);
}
二 IntentService
IntentService是Service类的子类,用来处理异步请求。客户端通过startService(Intent)方法传递请求给IntentService,在 IntentService 内有一个工作线程来处理耗时操作,启动 IntentService 的方式和启动传统 Service 一样,同时,当任务执行完后,IntentService 会自动停止,而不需要我们去手动控制。另外,可以启动 IntentService 多次,而每一个耗时操作会以工作队列的方式在IntentService 的 onHandleIntent 回调方法中执行,并且,每次只会执行一个工作线程
它的优先级高于Service。IntentService通过worker thread处理每个Intent对象,执行完所有工作后自动停止Service。
使用方法:
1、创建一个类并继承IntentService,重写onHandleIntent(),这里面做具体任务,构造函数super(“线程名”);
2、在AndroidManifest.xml里注册,同Service;
3、通过startService()启动。
三 系统服务 getSystemService()
四 通信
5.1 Activity 和 Service 之间的通信
(1)直接通过Intent进行传值,性能不高。intent会在onStartComment时候得到。是Activity传给Service
(2)(适用于bindservice)通过binder, service类里onbind 返回一个当前的service,然后Activity 启动 ServiceConnection,必须实现两个方法onServiceConnection(ComponentName,IBinder) 和 onServiceDisconnection。前者的IBinder就是service 里面onBind 的返回值,所以通过这个可以进行通信,二维码服务就是这样做的,这个相当于服务通知Activity消息。但是这个需要Activity每次去拿消息。
(3)(适用于bindservice)加接口,service 注册接口回调方法供外部使用,service中进度发生变化就调用接口里的抽象方法,由于Activity实现了这个接口(在onServiceConnected里面实现),所以发生变化就会改变。然后通过Handler告诉主线程发生了变化。这个做法是Service中进度发生变化主动通知Activity。
(4)通过broadcast(广播)
五 面试问题
Service的多进程模式 & 不死进程
Activity和Service之间的通信
Android N,O,P上面service是不同的,有什么不同
除了普通 service和IntentService,你还知道什么Service,不包括自定义的。
AIDL
如何保证一个后台服务不被杀死,比较省电的方式是什么
- 修改onStartCommand(…)方法的返回值为START_STICKY可实现停止服务之后重启服务。
1):START_STICKY:如果service进程被kill掉,保留service的状态为开始状态,但不保留递送的intent对象。随后系统会尝试重新创建service,由于服务状态为开始状态,所以创建服务后一定会调用onStartCommand(Intent,int,int)方法。如果在此期间没有任何启动命令被传递到service,那么参数Intent将为null。
2):START_NOT_STICKY:“非粘性的”。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统不会自动重启该服务
3):START_REDELIVER_INTENT:重传Intent。使用这个返回值时,如果在执行完onStartCommand后,服务被异常kill掉,系统会自动重启该服务,并将Intent的值传入。
4):START_STICKY_COMPATIBILITY:START_STICKY的兼容版本,但不保证服务被kill后一定能重启。 - 提升service优先级:AndroidManifest.xml文件中对于intent-filter可以通过android:priority = "1000"这个属性设置最高优先级
- 提升service进程优先级:设置为前台服务,依附于和用户交互的前台进程。
- onDestroy方法里重启service:
public void onDestroy(){
Intent localIntent = new Intent();
localIntent.setClass(this, MyService.class); // 销毁时重新启动Service
this.startService(localIntent);
}
- 就是在service的onCreate方法里边
startForeground(1, notice);
第一个参数是不为零的数,代表通知ID
第二个参数是通知的内容
@Override
public void onCreate() {
// TODO Auto-generated method stub
super.onCreate();
Notification notice = new Notification();
startForeground(1, notice);
}
- 8.0 以后不希望后台应用运行后台服务,除非特殊条件
- 一旦通过startForegroundService() 启动前台服务,必须在service 中有startForeground() 配套,不然会出现ANR 或者crash
- startForeground() 中的id 和notification 不能为0 和 null