作为Android四大组件之一,各位大咖已经将service的外衣扒得体无完肤了,但是为什么还要来炒冷饭呢?这是十大未解之谜之一。我不管,看完本篇博文,你将学会以下内容(敲黑板!!!!)且看:
摘要
service即服务,隐形的,不可见的。为什么Google会把service作为四大组件之一呢?看看我国的四大产业架构,再看看Android的架构,你就会明白,服务业是必不可少的一大产业,它与人们的生活息息相关。没有服务,你找谁做饭(别说有女票,有女票也得自己做),你怎么出行?(好吧,身为程序员,我编不下去了~~),总之,service是灰常重要滴!!!!!有了service你可以边玩游戏边听歌,还能下载电影,不瞎扯,上干(gou)粮!!
一、service 的生命周期
service的生命周期很简单,就那么几个常用的:onCreate、onStartCommand,onBind、onUnbind、onDestroy,是不是很简单?在oncreate方法里面完成任务的初始化工作,在onBind获取整个service的实例(稍后讲解),在unBind方法将service解除绑定,在onDestroy方法里面将资源回收,完美!(额外再说一下,oncreate方法只在service没启动的时候走,onstartCommand是每一次startService都会调用,onBind只会在没有绑定的时候调用,同理onUnBind也只会调用一次,再次调用会报没有注册service的错, OnDestroy也只会走一次),如图,其中MyService是我们的service,ServiceView是一个activity
如果是直接绑定一个service,其生命周期为onCreate(),onBind(),unBind(),onDestroy(),与直接启动service还是有点区别的,直接绑定一个service,默认不走onStartCommand()方法的,并且在解除绑定时候,service直接被destroy掉,不需要我们额外的stopService。
至于service能不能执行耗时操作,我就上一张图好了,显然service与宿主activity是同一个thread
二、service的启动
启动service与启动一个activity是一样一样的只要两行(其实一行就就可以启动)代码:
Intent serviceInt = new Intent(this, MyService.class);
startService(serviceInt);
关闭service只要一行代码,不能再少了,除非砸手机
stopService(serviceInt);
当然,上面的做法是不负责任的表现,就像女票一样,追到手了不能不管他呀!你还需要管理他的事务,与他沟通,说白了就是要与service成为同一条船上的蚂蚱。于是就有下面的操作:
Intent serviceInt = new Intent(this, MyService.class);
bindService(serviceInt, connet, Service.BIND_AUTO_CREATE);
将当前activity与service绑定在一起,他们就在一起了。该bindService方法中第一个参数就是一个Intent,与上面一致,第二个是一个ServiceConnection接口,我们通过该接口获取service的实例,第三个就是启动的标志,我们常说的,某某某在此立下flag,启动不了service誓不罢休。当service启动成功了,就会回调我们传进去的接口,来看看怎么实现这个接口
private MyService myService;
private ServiceConnection connet = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myService = ((MyService.LocalBinder) service).getService();
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
现在大家能想象MyService长什么样么?估计泥萌猜出来了,对,就是这样
public class MyService extends Service {
private final IBinder mBinder = new LocalBinder();
@Override
public void onCreate() {
super.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
}
public class LocalBinder extends Binder {
public MyService getService() {
Log.i(TAG, "getService: ");
return MyService.this;
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
@Override
public void sendBroadcast(Intent intent) {
super.sendBroadcast(intent);
}
@Override
public boolean stopService(Intent name) {
return super.stopService(name);
}
}
我们重写了onBind方法并返回Binder的子类LocalBinder,我们可以在activity通过这个子类来获取service的实例,然后我们想让service干嘛就干嘛了~~比如让它自取灭亡
myService.stopService(serviceInt);
就看你怎么玩了~~
三、activity与service通信之一(Binder)
获取binder如上,不再赘述,上面我们通过重写Binder获取service的实例,然后activity就可以通过该实例与service进行通信了,那么,service怎么与activity通信呢?很简单,就按照常见的手法——接口,我们就定义一个接口获得service启动后的生命周期,定义如下
public interface ServiceLiftCycle {
void onCreate();
void onStartCommand();
void onBind();
void unBind();
void onDestory();
void onStopService();
}
修改一下service
public class MyService extends Service {
private final IBinder mBinder = new LocalBinder();
public ServiceLiftCycle myServiceLiftCycle ;
public void setServiceLiftCycle(ServiceLiftCycle listener){
this.myServiceLiftCycle = listener;
}
@Override
public void onCreate() {
super.onCreate();
if(myServiceLiftCycle != null)
myServiceLiftCycle.onCreate();
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (myServiceLiftCycle != null)
myServiceLiftCycle.onStartCommand();
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
if (myServiceLiftCycle != null)
myServiceLiftCycle.onDestory();
}
public class LocalBinder extends Binder {
public MyService getService() {
return MyService.this;
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}
@Override
public boolean onUnbind(Intent intent) {
if (myServiceLiftCycle != null)
myServiceLiftCycle.unBind();
return super.onUnbind(intent);
}
@Override
public void sendBroadcast(Intent intent) {
super.sendBroadcast(intent);
}
@Override
public boolean stopService(Intent name) {
if (myServiceLiftCycle != null)
myServiceLiftCycle.onStopService();
return super.stopService(name);
}
}
实现ServiceLiftCycle 接口
private class MyServiceLiftCycle implements ServiceLiftCycle {
@Override
public void onCreate() {
Log.i(TAG, "onCreate:-------------- ");
}
@Override
public void onStartCommand() {
Log.i(TAG, "onStartCommand: --------------");
}
@Override
public void onBind() {
Log.i(TAG, "onBind: --------------");
}
@Override
public void unBind() {
Log.i(TAG, "unBind: --------------");
}
@Override
public void onDestory() {
Log.i(TAG, "onDestory: --------------");
}
@Override
public void onStopService() {
Log.i(TAG, "onStopService: --------------");
}
}
ServiceConnection修改如下
private MyService myService;
private ServiceConnection connet = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
myService = ((MyService.LocalBinder) service).getService();
myService.setServiceLiftCycle(new MyServiceLiftCycle());
}
@Override
public void onServiceDisconnected(ComponentName name) {
unbind = true;
}
};
这样就可以在activity里面监听到service的生命周期了,当然,是activity与service绑定后的了,毕竟在绑定前myServiceLiftCycle为null的,这里只是提供一个思路,怎么玩就看各位看官了,总之,binder加上接口就可以实现一般业务的需求。什么?对binder不了解?没事,广播总有了解吧?四大组件之二!!!
四、activity与service的通信之二(broadcast)
身为四大猛将之一,大家对这个包租婆(高音喇叭)应该有了解。如有不了解的,请出去左拐,看看其他大神的巨作~~我们重新创建一个servicepublic class BroadCastService extends Service{
private String TAG = "BroadCastService";
public static final String SERVICE_INTENTFILTER = "com.android.broadcastService.intentFilter.";
@Override
public void onCreate() {
super.onCreate();
Log.i(TAG, "onCreate: ");
IntentFilter filter = new IntentFilter ();
filter.addAction(SERVICE_INTENTFILTER);
registerReceiver(MyReceiver ,filter);
}
boolean isSend = false;
BroadcastReceiver MyReceiver = new BroadcastReceiver(){
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "onReceive: 我收到来自activity那个傻蛋的消息了");
Intent intent1 = new Intent(ACTIIVTY_INTENTFILTER);
sendBroadcast(intent1);
Log.i(TAG, "onReceive: 我转发消息给activity了");
}
};
@Override
public void onDestroy() {
super.onDestroy();
unregisterReceiver(MyReceiver);
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
在activity加如下代码
public static final String ACTIIVTY_INTENTFILTER = "com.android.broadcastActivity.intentFilter.";
public void service(View view) {
Log.i(TAG, "service: ");
Intent serviceInt = new Intent(this, BroadCastService.class);
startService(serviceInt);
IntentFilter filter = new IntentFilter ();
filter.addAction(ACTIIVTY_INTENTFILTER);
registerReceiver(receiver ,filter);
}
activityReceiver receiver = new activityReceiver();
class activityReceiver extends BroadcastReceiver{
@Override
public void onReceive(Context context, Intent intent) {
Log.i(TAG, "onReceive: 我收到service发来的消息了");
}
};
public void send(View view) {
Intent intent1 = new Intent(SERVICE_INTENTFILTER);
sendBroadcast(intent1);
Log.i(TAG, "service: 我发消息给service了");
}
结果如下
五、activity与service的通信之三(messenger)
有些时候需要在service中执行繁重的任务,如果直接在应用所在的进程创建,容易导致crash,这时候我们为service创建新的进程,在配置文件上修改如下:
<service android:name=".service.MessengerService"
android:process=":MessengerService"/>
这个时候activity与service之间的通信再用第一种方式显然不行,毕竟跨进程了。用上面的广播可以实现跨进程通信,但有些时候并不希望其他应用也能截获广播,这时候可以考虑使用messenger来实现activity与service的通信问题 我们创建新的service对象:
public class MessengerService extends Service{
private String TAG = "MessengerService ";
public int mValue = 0;
public static final int MSG_REGISTER_CLIENT = 1;
public static final int MSG_UNREGISTER_CLIENT = 2;
public static final int MSG_SET_VALUE = 3;
public ArrayList<Messenger> mClients = new ArrayList<Messenger>();
class mServiceHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REGISTER_CLIENT:
Log.i(TAG, "handleMessage: 我收到了 MSG_REGISTER_CLIENT");
mClients.add(msg.replyTo);
break;
case MSG_UNREGISTER_CLIENT:
mClients.remove(msg.replyTo);
break;
case MSG_SET_VALUE:
Log.i(TAG, "handleMessage: 我收到了 MSG_SET_VALUE ");
mValue = msg.arg1;
for (int i=mClients.size()-1; i>=0; i--) {
try {
mClients.get(i).send(Message.obtain(null,
MSG_SET_VALUE, mValue, 0));
} catch (RemoteException e) {
mClients.remove(i);
}
}
break;
default:
super.handleMessage(msg);
}
}
}
final Messenger mServiceMessenger = new Messenger(new mServiceHandler());
@Override
public void onCreate() {
super.onCreate();
}
@Override
public void onStart(Intent intent, int startId) {
super.onStart(intent, startId);
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
return super.onStartCommand(intent, flags, startId);
}
@Override
public void onDestroy() {
super.onDestroy();
Toast.makeText(this, R.string.cancel , Toast.LENGTH_SHORT).show();
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mServiceMessenger.getBinder();
}
@Override
public boolean onUnbind(Intent intent) {
return super.onUnbind(intent);
}
}
修改activity的内容
boolean mIsBound = false;
Messenger mServiceMes = null;
class mClientHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MessengerService.MSG_SET_VALUE:
Log.i(TAG, "handleMessage: 我收到来自遥远的service端的消息了");
break;
default:
super.handleMessage(msg);
}
}
}
final Messenger mClientMessenger = new Messenger(new mClientHandler());
private ServiceConnection mMesConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
mIsBound = true;
Messenger mServiceMes = new Messenger(service);//获取MessengerService 里面的Messenger
try {
Message msg = Message.obtain(null,
MessengerService.MSG_REGISTER_CLIENT);
msg.replyTo = mClientMessenger;
mServiceMes.send(msg);
msg = Message.obtain(null,
MessengerService.MSG_SET_VALUE, this.hashCode(), 0);
mServiceMes.send(msg);
} catch (RemoteException e) {
}
Toast.makeText(ServiceView.this, "远程service已经连接上",
Toast.LENGTH_SHORT).show();
}
public void onServiceDisconnected(ComponentName className) {
Log.i(TAG, "onServiceDisconnected: MessengerService");
mServiceMes = null;
Toast.makeText(ServiceView.this, "断开连接",
Toast.LENGTH_SHORT).show();
}
};
public void bindMesService(View view){
bindService(new Intent(ServiceView.this,
MessengerService.class), mMesConnection, Context.BIND_AUTO_CREATE);
}
MessengerService端收到的消息
这里面涉及到三个知识:messenger,message,handler。messenger充当信息员,负责实现跨进程通信,即把message从本地进程携带到远程进程,message就是一个信封,里面包含了通信的信息,handler就是收信人,读取从messenger邮寄过来的message
先说client端(activity端)
在接口ServiceConnection的onServiceConnected方法里面我们拿到了远程的IBinder对象(准确的说IBinder是一个接口,将所有跨进程通信类都抽象出来了),我们通过IBinder对象获取到远程service端的messenger这样。我们就可以通过这个messenger对象向远程service 发消息了。首先,我们在client端拿到messenger
public void onServiceConnected(ComponentName className,
IBinder service) {
Messenger mServiceMes = new Messenger(service);//获取MessengerService 里面的Messenger
}
然后构建一个message对象,让mServiceMes 对象将message发送给service端
Message msg = Message.obtain(null,
MessengerService.MSG_REGISTER_CLIENT);
mServiceMes.send(msg);
各位看官不免会有疑问,系统怎么知道mServiceMes发送message到哪里呢?且慢,喝口茶。
接着来
把刚刚的问题放一边。
在service端,我们先创建一个handler,即收件人,与我们平常创建的handler大同小异
class mServiceHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REGISTER_CLIENT:
Log.i(TAG, "handleMessage: 我收到了 MSG_REGISTER_CLIENT");
mClients.add(msg.replyTo);
break;
}
}
}
然后我们通过这个handler来唯一创建一个mServiceMessenger ,表明该mServiceMessenger发送的所有消息,都会由该handler来处理,这下问题明了了
final Messenger mServiceMessenger = new Messenger(new mServiceHandler());
接着,我们重写service端的Onbind方法,把mMessenger的IBinder返回给client端
@Nullable
@Override
public IBinder onBind(Intent intent) {
return mServcieMessenger.getBinder();
}
通过上面的代码,我们就可以很顺利的拿到了service端的mMessengermServiceMessenger ,这样,我们在client端就可以通过messengermServiceMes 来给service端发消息了。
说完client端,我们再来看看service端是怎么获取到client端的messenger
细心的看官也许已经发现了,且看
同样,我们首先在client端创建一个handler对象
class mClientHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MessengerService.MSG_SET_VALUE:
Log.i(TAG, "handleMessage: 我收到来自遥远的service端的消息了");
break;
default:
super.handleMessage(msg);
}
}
}
与service端一样,通过handler创建唯一的messenger
final Messenger mClientMessenger = new Messenger(new mClientHandler());
这样,只要是mClientMessenger 发消息,我们的mClientHandler都可以处理(也只有他能处理),问题来了,我们在绑定service端的时候可以通过ServiceConnection回调里面的方法来获取一个Ibinder ,从而获取service端的messenger,那么service端是怎么获取client端的messenger的呢?
我们注意到下面两行代码
Message msg = Message.obtain(null,
MessengerService.MSG_REGISTER_CLIENT);
msg.replyTo = mClientMessenger;
这里,我们把在client端创建的mClientMessenger作为一个回复,返回给service端,就可以通过service端的mServiceHandler对象来拿到这个mClientMessenger,这里,我们用到ArrayList来保存client端的messenger,因为service可能对应多个client端
public ArrayList<Messenger> mClients = new ArrayList<Messenger>();
class mServiceHandler extends Handler {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case MSG_REGISTER_CLIENT:
Log.i(TAG, "handleMessage: 我收到了 MSG_REGISTER_CLIENT");
mClients.add(msg.replyTo);
break;
}
}
}
这样,service端也就顺利的拿到了client端的mClientMessenger对象,这样就意味着我们也可以在service端对client端发消息了
mClients.get(i).send(Message.obtain(null,
MSG_SET_VALUE, mValue, 0));
需要解除绑定,只需要调用该方法 unbindService(mMesConnection);
如果service端用list维护着多个messenger,client端还需要通知service解除messenger
Message msg = Message.obtain(null,
MessengerService.MSG_UNREGISTER_CLIENT);
msg.replyTo = mClientMessenger;
mServiceMes.send(msg);
service端将messenger解除即可
case MSG_UNREGISTER_CLIENT:
mClients.remove(msg.replyTo);
break;
至此,已经顺利打通了client端与service端的跨进程通信问题,框架已经打好,至于怎么玩出花样,且看下回分解