service是运行在ui线程中的一个服务,不是一个线程也不是一个进程。
启动
startService(intent);
该方式启动的Service会一直在后台运行,如果没关闭service的话,即使activity关闭还是在后台运行。也就是说启动service后就和当前的activity没关系了。
bindService(intent,ServiceConnection,flag);
方式启动的service是和当前的activity有绑定关系的,如果当前activity关闭并且没有unBind会抛出一个异常:android.app.ServiceConnectionLeaked: Activity xxx.MyActivity has leaked ServiceConnection.但是这个异常对前台没影响。
生命周期
startService
Context.startService启动:onCreate -> onStartCommand(onStart)
Context.stopService停止: onDestroy
1.多次启动service的话,只会执行一次onCreate,会多次执行onStartCommand方法(service没有被Destroy).
2.如果不手动关闭service的话,service会一直运行。除非调用stopServic())或者service执行完业务后通过stopSelf()关闭自己。
3.如果service中启动了一个线程,关闭service后,如果线程没有执行完的话还会继续执行,所以关闭service的时候一定要确保service中的业务已执行完成或者关闭。
bindService
onCreate -> onBind ->onUnbind(onReBind) ->onDestroy
bindService: onCreate -> onBind
unbindService: onUnbind -> onDestroy
1.多次绑定service的话,不会执行任何生命周期(service在bind状态),只会bind一次。
2.onReBind只会在混合启动时触发
混合启动
一个service启动时使用了startService和bindService。
分析:
- 通过startService启动的服务必须使用stopService停止。
- 通过bindService启动的服务必须使用unBindService停止。
- 不管是通过哪种方式启动的service首次会执行onCreate。
- 不管是通过哪种方式启动的service再次启动还是按自身的生命周期执行,startService(多次onStartCommand),bindService(一次onBind).
- 停止的时候必须调用两种方式自身的关闭事件才能完成整个生命周期。(startService-stopService),(bindService-unBindService).
- 因为startService没有onStop,是执行的onDestroy,所以只有最后一个关闭事件才会触发onDestroy事件。如果stopService不是最后一个关闭的话就不会触发service的生命周期。
测试日志:
// bind -> start
...bind click 1
....MyService onCreate=1
....MyService onBind=1
...onServiceConnected 1
...start click 1
....MyService onStartCommand=1
....MyService onStart=1
//start -> bind
...start click 1
....MyService onCreate=1
....MyService onStartCommand=1
....MyService onStart=1
...bind click 1
....MyService onBind=1
...onServiceConnected 1
// stop -> unbind
...stop click 1
...unbind click 1
....MyService onUnbind=1
....MyService onDestroy=1
// unbind -> stop
...unbind click 1
....MyService onUnbind=1
...stop click 1
....MyService onDestroy=1
- 关于onReBind, 要满足两个条件:
->onUnbind返回true,onReBind method later called when new clients bind to it。
->通过混合启动。如果仅仅是bindService启动的话,一unBind就destroy了。
这样的话如果unBind后,再次点击绑定就会执行onReBind.如果 onUnbind返回false,进行unBind后,再次绑定不会执行任何生命周期(直接建立ServiceConnection连接进行访问的服务,不会执行service的生命周期).
// onUnbind ->false
...bind click 1
....MyBinder getService=1
....MyService dosomething=1
...onServiceConnected 1
....MyBinder something=1
// onUnbind ->true
...bind click 1
....MyBinder getService=1
....MyService dosomething=1
...onServiceConnected 1
....MyBinder something=1
....MyService onRebind=1
不被回收处理
cpu休眠处理
IntentService
在service中创建了一个线程(HandlerThread),用来异步加载。执行完成后会自动关闭服务。
public abstract class IntentService extends Service{
private final class ServiceHandler extends Handler {
public ServiceHandler(Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
onHandleIntent((Intent)msg.obj);
stopSelf(msg.arg1);
}
}
public void onCreate() {
super.onCreate();
HandlerThread thread = new HandlerThread("IntentService[" + mName + "]");
thread.start();
mServiceLooper = thread.getLooper();
mServiceHandler = new ServiceHandler(mServiceLooper);
}
@Override
public void onStart(Intent intent, int startId) {
Message msg = mServiceHandler.obtainMessage();
msg.arg1 = startId;
msg.obj = intent;
mServiceHandler.sendMessage(msg);
}
}
其使用方法和普通service没区别,唯一的不同就是自身拥有一个异步方法(onHandleIntent)。
public class BaseIntentService extends IntentService {
private final String TAG = "BaseIntentService";
BaseIntentServiceBinder mBinder = new BaseIntentServiceBinder();
public BaseIntentService() {
super("isname");
}
@Override
protected void onHandleIntent(Intent intent) {
int order = intent.getIntExtra("order",-1);
Log.d(TAG, "BaseIntentService onHandleIntent order="+order);
Log.d(TAG, "BaseIntentService onHandleIntent thread->" + Thread.currentThread().getId()+",order="+order);
try {
Log.d(TAG, "BaseIntentService onHandleIntent do somethings...order="+order);
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
Log.d(TAG, "BaseIntentService onHandleIntent done order="+order);
}
@Override
public boolean onUnbind(Intent intent) {
Log.d(TAG, "BaseIntentService onUnbind");
return super.onUnbind(intent);
}
@Override
public void onDestroy() {
Log.d(TAG, "BaseIntentService onDestroy");
super.onDestroy();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
Log.d(TAG, "BaseIntentService onStartCommand startId="+startId);
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onCreate() {
Log.d(TAG, "BaseIntentService onCreate");
super.onCreate();
Log.d(TAG, "BaseIntentService onCreate thread->" + Thread.currentThread().getId());
}
@Override
public IBinder onBind(Intent intent) {
Log.d(TAG, "BaseIntentService onBind");
// return super.onBind(intent);
return mBinder;
}
public class BaseIntentServiceBinder extends Binder {
public int testMethod(int num) {
return num;
}
}
- 因为intentService里面是个消息队列,所以队列里面有消息的时候再添加消息,也是同一个线程在执行。
- 在工作线程中调用该方法。每一个时刻只能处理一个intent请求,当同时有多个intent请求时,也就是客户端同时多次调用Content#startService方法启动同一个服务时,这些请求就会放于消息队列中,直到前面的intent异步任务请求处理完成才会处理下一个intent请求。直到所有的intent请求结束之后,IntentService服务会调用stopSelf停止当前服务。也就是当intent异步任务处理结束之后,对应的IntentService服务会自动销毁,进而调用IntentService#onDestroy方法.
- 列外还有一个问题,这里onHandleIntent后就执行stopSelf,为什么请求多次的时候,第一次执行完没有stop,而是一直再遍历消息。这里要看service启动,停止的源码进行分析(启动服务的时候如果服务已经存在则会将该请求添加到ServiceRecord.deliveredStarts中,参照service的启动ActiveServices.sendServiceArgsLocked()).
service测试代码
public class MyService extends Service {
private boolean keepalive = false;
private MyBinder binder = new MyBinder();
private int count = 0;
private Thread mThread;
@Override
public IBinder onBind(Intent intent) {
LogUtil.debug("....MyService onBind=" + Thread.currentThread().getId());
return binder;
}
@Override
public void onCreate() {
LogUtil.debug("....MyService onCreate=" + Thread.currentThread().getId());
super.onCreate();
doBussness();
}
@Override
public void onDestroy() {
LogUtil.debug("....MyService onDestroy=" + Thread.currentThread().getId());
super.onDestroy();
if (keepalive) {
stopForeground(true);
}
if(mThread != null && mThread.isAlive()){
LogUtil.debug("....MyService onDestroy thread isAlive");
mThread.interrupt();
}else{
LogUtil.debug("....MyService onDestroy thread not alive");
}
}
@Override
public boolean onUnbind(Intent intent) {
LogUtil.debug("....MyService onUnbind=" + Thread.currentThread().getId());
// return super.onUnbind(intent);
return true;
}
@Override
public void onRebind(Intent intent) {
LogUtil.debug("....MyService onRebind=" + Thread.currentThread().getId());
super.onRebind(intent);
}
@Override
@Deprecated
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
LogUtil.debug("....MyService onStart=" + Thread.currentThread().getId());
if (keepalive) {
LogUtil.debug("....MyService startForeground=" + Thread.currentThread().getId());
startForeground(0, null);
}
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
LogUtil.debug("....MyService onStartCommand=" + Thread.currentThread().getId());
return super.onStartCommand(intent, flags, startId);
}
private void doBussness() {
if(mThread != null && mThread.isAlive()){
return;
}
mThread = new Thread(new Runnable() {
@Override
public void run() {
while (!mThread.isInterrupted()) {
LogUtil.debug("count=" + count);
try {
Thread.sleep(1000);
count++;
} catch (InterruptedException e) {
e.printStackTrace();
mThread.interrupt();
}
}
}
});
mThread.start();
}
public void dosomething() {
LogUtil.debug("....MyService dosomething=" + Thread.currentThread().getId());
}
class MyBinder extends Binder {
public MyService getService() {
LogUtil.debug("....MyBinder getService=" + Thread.currentThread().getId());
return MyService.this;
}
public void something() {
LogUtil.debug("....MyBinder something=" + Thread.currentThread().getId());
}
}
}