将高级service开发简单化

来源:互联网 发布:淘宝店铺退款怎么退款 编辑:程序博客网 时间:2024/05/18 01:01

作为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)

身为四大猛将之一,大家对这个包租婆(高音喇叭)应该有了解。如有不了解的,请出去左拐,看看其他大神的巨作~~我们重新创建一个service
public 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端收到的消息


actiivty端收到的消息

这里面涉及到三个知识: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端的跨进程通信问题,框架已经打好,至于怎么玩出花样,且看下回分解















原创粉丝点击