将高级service开发简单化

作为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端的跨进程通信问题,框架已经打好,至于怎么玩出花样,且看下回分解















评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值