- Service是Android程序中四大基础组件之一
- 适用于去执行那些不需要和用户交互而且还要求长期运行的任务
- Service默认并不会运行在子线程中,它也不运行在一个独立的进程中,它同样执行在UI线程中,不要在Service中执行耗时的操作
1. Service分类
按运行地点分类:
按运行类型分类:
按使用方式分类:
2. Service 方法
手动调用:
自动调用:
3. Service 生命周期
- OnCreate()
系统在service第一次创建时执行此方法,来只运行一次的初始化工作。 - onStartCommand()
每次客户端调用startService()方法启动该Service都会回调该方法(多次调用)。一旦这个方法执行,service就启动并且在后台长期运行。通过调用stopSelf()或stopService()来停止服务。 - OnBind()
当组件调用bindService()想要绑定到service时(比如想要执行进程间通讯)系统调用此方法
(一次调用,一旦绑定后,下次再调用bindService()不会回调该方法)
在你的实现中,你必须提供一个返回一个IBinder来以使客户端能够使用它与service通讯,你必须总是实现这个方法,但是如果你不允许绑定,那么你应返回null。 - OnUnbind()
当前组件调用unbindService(),想要解除与service的绑定时系统调用此方法
(一次调用,一旦解除绑定后,下次再调用unbindService()会抛出异常) - OnDestory()
系统在service不再被使用并要销毁时调用此方法(一次调用)。service应在此方法中释放资源,比如线程,已注册的侦听器,接收器等等.这是service收到的最后一个调用。
生命周期的调用:
- 启动服务(startService)
完整:onCreate()->onStartCommand()->onDestroy()
单次:onCreate()->onStartCommand()
多次:onStartCommand()->onStartCommand()->…
多次启动时onCreate只执行一次,onStartCommand执行多次 - 停止服务(stopService)
onDestroy() - 绑定服务(bindService)
完整:onCreate()->onBind()->onUnbind()->onDestory
onCreate()->onBind() - 解绑服务(unbindService)
onUnbind()->onDestory() - 先绑定后启动
完整:onCreate()->onBind()->onStartCommand()->onUnbind()->onDestory
绑定:onCreate()->onBind()->onStartCommand()
解绑:onUnbind()->onDestory() - 先解绑再绑定
完整:onUnbind()->onRebind()
4. 实例
4.1 不可交互的后台Service
普通的Service,通过startService()方式开启。Service的生命周期很简单,分别为onCreate、onStartCommand、onDestroy这三个。
1.创建服务类:
public class BackService extends Service {
private Thread mThread;
public void onCreate() {
super.onCreate();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
System.out.println("onBind");
return null;
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
//执行耗时操作
mThread = new Thread() {
@Override
public void run() {
try {
while (true) {
//等待停止线程
if (this.isInterrupted()) {
throw new InterruptedException();
}
//耗时操作。
System.out.println("执行耗时操作");
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
};
mThread.start();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
//停止线程
mThread.interrupt();
}
}
2.配置服务:
<service android:name=".BackService">
</service>
如果想配置成远程服务,加如下代码:
android:process="remote"
配置好Service类,只需要在前台,调用startService()方法,就会启动耗时操作。
注意:
①在Service中创建了子线程来完成耗时操作。
②当Service关闭后,如果在onDestory()方法中不关闭线程,你会发现我们的子线程进行的耗时操作是一直存在的,此时关闭该子线程的方法需要直接关闭该应用程序。因此,在onDestory()方法中要进行必要的清理工作。
4.2 可交互的后台服务
可交互的后台服务是指前台页面可以调用后台服务的方法,通过bindService()方式开启。Service的生命周期很简单,分别为onCreate、onBind、onUnBind、onDestroy这四个。
可交互的后台服务实现步骤是和不可交互的后台服务实现步骤是一样的,区别在于启动的方式和获得Service的代理对象。
1.创建服务类
和普通Service不同在于这里返回一个代理对象,返回给前台进行获取,即前台可以
获取该代理对象执行后台服务的方法
public class BackService extends Service {
@Override
public void onCreate() {
super.onCreate();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
//返回MyBinder对象
return new MyBinder();
}
//需要返回给前台的Binder类
class MyBinder extends Binder {
public void showTip(){
System.out.println("我是来此服务的提示");
}
}
@Override
public void onDestroy() {
super.onDestroy();
}
}
2.前台调用
通过以下方式绑定服务:
bindService(mIntent,con,BIND_AUTO_CREATE);
第二个参数:con
private ServiceConnection con = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
BackService.MyBinder myBinder = (BackService.MyBinder) service;
myBinder.showTip();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
当建立绑定后,onServiceConnected中的service便是SerService类中onBind的返回值。如此便可以调用后台服务类的方法,实现交互。
当调用unbindService()停止服务,同时要在onDestory()方法中做好清理工作。
**注意:**通过bindService启动的Service的生命周期依附于启动它的Context。因此当前台调用bindService的Context销毁后,那么服务会自动停止。
4.3 混合型后台服务
将上面两种启动方式结合起来就是混合性交互的后台服务了,即可以单独运行后台服务,也可以运行后台服务中提供的方法,其完整的生命周期是:onCreate->onStartCommand->onBind->onUnBind->onDestroy
4.4 前台服务
- 通过一定的方式将服务所在的进程级别提升了。前台服务会一直有一个正在运行的图标在系统的状态栏显示,非常类似于通知的效果。
- 可以一直保持运行状态而不被系统回收。
1.前台服务创建
在Service的基础上创建一个Notification,然后使用Service的startForeground()方法即可启动为前台服务。
public class ForeService extends Service{
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void onCreate() {
super.onCreate();
beginForeService();
}
private void beginForeService() {
//创建通知
Notification.Builder mBuilder = new Notification.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentText("2017-2-27")
.setContentText("您有一条未读短信...");
//创建点跳转的Intent(这个跳转是跳转到通知详情页)
Intent intent = new Intent(this,NotificationShow.class);
//创建通知详情页的栈
TaskStackBuilder stackBulider = TaskStackBuilder.create(this);
//为其添加父栈 当从通知详情页回退时,将退到添加的父栈中
stackBulider.addParentStack(NotificationShow.class);
PendingIntent pendingIntent = stackBulider.getPendingIntent(0,PendingIntent.FLAG_UPDATE_CURRENT);
//设置跳转Intent到通知中
mBuilder.setContentIntent(pendingIntent);
//获取通知服务
NotificationManager nm = (NotificationManager) getSystem
Service(Context.NOTIFICATION_SERVICE);
//构建通知
Notification notification = mBuilder.build();
//显示通知
nm.notify(0,notification);
//启动前台服务
startForeground(0,notification);
}
}
2.启动前台服务
startService(new Intent(this, ForeService.class));
TaskStackBuilder在Notification通知栏中的使用
1.首先是用一般的PendingIntent来进行跳转
mBuilder = new NotificationCompat.Builder(this).setContent(view)
.setSmallIcon(R.drawable.icon).setTicker("新资讯")
.setWhen(System.currentTimeMillis())
.setOngoing(false)
.setAutoCancel(true);
Intent intent = new Intent(this, NotificationShow.class);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0,intent, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(pendingIntent);
运行效果:
首先发送了一条Notification到通知栏上,然后这时,退出程序,即MainActivity已经不存在了,回到home主菜单,看到Notification仍然存在;
当然,我们还没有点击或者cancel它,现在去点击Notification,跳转到NotificationShow界面,然后我们按下Back键,发现直接回到home菜单了。现在大多数android应用都是在通知栏中如果有Notification通知的话,点击它,然后会直接跳转到对应的应用程序的某个界面,这时如果回退,即按下Back键,会返回到该应用程序的主界面,而不是系统的home菜单。所以用上面这种PendingIntent的做法达不到目的
2.使用TaskStackBuilder
mBuilder = new NotificationCompat.Builder(this)
.setContent(view)
.setSmallIcon(R.drawable.icon).setTicker("新资讯")
.setWhen(System.currentTimeMillis())
.setOngoing(false)
.setAutoCancel(true);
Intent intent = new Intent(this, NotificationShow.class);
TaskStackBuilder stackBuilder = TaskStackBuilder.create(this);
stackBuilder.addParentStack(NotificationShow.class);
stackBuilder.addNextIntent(intent);
PendingIntent pendingIntent = stackBuilder.getPendingIntent(0, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(pendingIntent);
显示用TaskStackBuilder.create(this)创建一个stackBuilder实例,接下来addParentStack();
为跳转后的activity添加一个父activity,在activity中的manifest中添加parentActivityName即可。
<activity
android:name="com.lvr.service.NotificationShow"
android:parentActivityName=".MainActivity" >
</activity>