一、service 简述
后台开启 程序退出后仍然可以人为进行操作运行
是一种可以在后台执行长时间运行操作而没有用户界面的应用组件
运行在UI线程不能做耗时操作
二、service与Thread区别
它们之间没有任何关系
Thread 是运行相对独立 程序执行的最小单元 可以通过开启一个子线程来做耗时操作
service运行依托于主线程 不能做耗时操作 否则会报ANR
三、service启动方式startService和bindService
startService
生命周期: onCreate()->onStartCommand()->onDestory()
在第一次启动时调用onCreate 之后调用多次都不会再调onCreate
无论运行startService多少次,只要调用一次stopService或者stopSelf,Service都会停止。
用法:
<1>继承service
<2>在清单文件中注册service
<3>使用startService(intent)启动service
<4>不在使用时,调用stopService/stopSelf来停止服务
onStartCommand方法返回值int 可选值及含义如下:
START_NOT_STICKY:当Service因为内存不足而被系统kill后,接下来未来的某个时间内,即使系统内存足够可用,系统也不会尝试重新创建此Service。除非程序中Client明确再次调用startService(...)启动此Service。
START_STICKY:当Service因为内存不足而被系统kill后,接下来未来的某个时间内,当系统内存足够可用的情况下,系统将会尝试重新创建此Service,一旦创建成功后将回调onStartCommand(...)方法,但其中的Intent将是null,pendingintent除外。
START_REDELIVER_INTENT:与START_STICKY唯一不同的是,回调onStartCommand(...)方法时,其中的Intent将是非空,将是最后一次调用startService(...)中的intent。
START_STICKY_COMPATIBILITY:不常用
注:
1、onStartCommand(…)可以多次被调用,onDestroy()与onCreate()想匹配,当用户强制kill掉进程时,onDestroy()是不会执行的。
2、对于同一类型的Service,Service实例一次永远只存在一个,而不管Client是否是相同的组件,也不管Client是否处于相同的进程中。
3、Service通过startService(…)启动Service后,此时Service的生命周期与Client本身的什么周期是没有任何关系的,只有Client调用stopService(…)或Service本身调用stopSelf(…)才能停止此Service。当然,当用户强制kill掉Service进程或系统因内存不足也可能kill掉此Service。
4、Client A 通过startService(…)启动Service后,可以在其他Client(如Client B、Client C)通过调用stopService(…)结束此Service
5、Client调用stopService(…)时,如果当前Service没有启动,也不会出现任何报错或问题,也就是说,stopService(…)无需做当前Service是否有效的判断
6、startService(Intent serviceIntent),其中的intent既可以是显式Intent,也可以是隐式Intent,当Client与Service同处于一个App时,一般推荐使用显示Intent。当处于不同App时,只能使用隐式Intent。
bindService
生命周期:onCreate()->onBind()->onUnbind()->onDestory()
以bindService()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止。
onBind()只有采用Context.bindService()方法启动服务时才会回调该方法。
通过Service中的Binder对象可以较为方便进行Client-Service通信
使用过程:
1、继承基类Service,并重写onBind(Intent intent)方法,此方法中需要返回具体的Binder对象
2、通过bindService方法启动service
3、实现ServiceConnection接口,通过onServiceConnected(ComponentName name, IBinder binder)方法,获取Service端Binder实例;
4、通过获取的Binder实例进行Service端其他公共方法的调用,以完成Client-Service通信;
5、当Client退出时,此时需要调用函数unbindService(),解绑之前已经绑定的Service。
四、IntentService
是一种特殊的service。可用于在后台执行一些耗时的操作,当任务执行完成后会自动停止。由于IntentService是一种服务,这样它的优先级要高于单纯的线程,所以比较适合执行一些高优先级的后台任务
使用:
继承IntentService,实现其的onHandleIntent()方法,在该方法中去做一些耗时操作
它的内部是通过HandleThread和Handle实现的。
1、在onCreate方法中创建HandleThread,使用HandleThread的getLooper方法创建Looper对象,通过该Looper对象创建该线程的Handle。
2、onStartCommand方法中调用onstart方法
3、onStart方法中发送message将Intent发送给Handle
4、Handle的handleMessage方法中调用onHandleIntent((Intent)msg.obj);执行耗时操作,执行完毕后调用stopSelf自动停止
五、前台Service
由于Service的优先级很低,所以在手机灭屏一段时间后,service很可能就被系统干掉回收了,为了保证service不会被系统回收,我们需要将service设置为前台服务
使用:
1、创建 Build Notification.Builder builder = new Notification.Builder(this);
2、设置 build的信息
3、获取 notification Notification notification = builder.build();
4、启动前台服务 Service.startForeground(100, notification);
service更新notification 比如:实现实时更新进度条的进度:
1、创建NotificationManager:
NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
2、设置更新的build数据
3、发送通知消息:notificationManager.notify(100,notification);
自定义notification的view
1、创建RemoteViews实例:
RemoteViews remoteViews = new RemoteViews(this.getPackageName(),R.layout.notification_layout);
// 获取remoteViews(参数一:包名;参数二:布局资源)
2、设置自定义的Notification内容: builder.setCustomContentView(remoteViews);
3、为自定义通知内容上的控件绑定点击事件(使用广播.可以针对不同的控件id创建不同的广播)
<1> 指定操作意图:
Intent intentPlay = new Intent(ACTION_PLAY);//设置对应的行为ACTION
<2> 发送一个广播:
PendingIntent pIntentPlay = PendingIntent.getBroadcast(this.getApplicationContext(),1, intentPlay, PendingIntent.FLAG_UPDATE_CURRENT);
<3> 绑定点击事件:
remoteViews.setOnClickPendingIntent(R.id.iv_pause, pIntentPlay);//(参数一:// 控件id;参数二:对应触发的PendingIntent)
4、监听对应广播
六、保证service不被"杀死"
1、onStartCommand的返回值设置为START_STICKY
2、<intent-filter>设置service优先级
3、设置service为前台service
4、在onDestory方法中发送广播再次启动service或直接启动service
......