Android bind service讲解以及跨进程通信

来源:互联网 发布:电脑版淘宝店铺装修 编辑:程序博客网 时间:2024/05/01 06:01

**

Android bind service讲解以及Messenger跨进程通信

**
android service是运行在后台的程序,说白了,就是没有界面,这里我想强调的一点是,运行在后台不等于运行在非主线程,除了IntentService外,普通的service如果你没有开启新的线程,那么默认是运行在主线程中的。
service有两种启动方式,一个是bind,一个是start,两种启动方式,有挺多区别。需要注意的是,bind绑定service的时候,直到最后一个bind到service的程序调用unbind,否则service一直会运行。而对于startservice这种启动方式来说,一旦启动,需要自己stopService或者调用service内部的stopSelf,否则该service是不会关闭的。
还需要注意的是service的声明周期,这个附张图就全明白了。
这里写图片描述
需要注意的是,onCreate方法只在你启动service的时候调用一次,之后再启动service的时候就直接走到onStartCommand()或者onBind()里了。

好了,废话不多说了,上个demo吧:

public class MainActivity extends AppCompatActivity implements View.OnClickListener{    private boolean hasBound;    private Button intent_Service;    private Button start_Service;    private Button bind_Service;    private Button messenger_Service;    //下面的handler和Messenger使用来进行跨进程通信的    private Handler handler=new Handler()    {        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            if(msg.what==322)            {                Toast.makeText(getApplicationContext(),"receive message from server",Toast.LENGTH_SHORT).show();            }        }    };    private Messenger clientMessenger=new Messenger(handler);    private Messenger serverMessenger;    @Override    protected void onCreate(Bundle savedInstanceState) {        super.onCreate(savedInstanceState);        setContentView(R.layout.activity_main);        initView();    }    private void initView()    {        intent_Service= (Button) findViewById(R.id.intent_service);        intent_Service.setOnClickListener(this);        start_Service= (Button) findViewById(R.id.start_service);        start_Service.setOnClickListener(this);        bind_Service=(Button)findViewById(R.id.bind_service);        bind_Service.setOnClickListener(this);        messenger_Service=(Button)findViewById(R.id.messenger_service);        messenger_Service.setOnClickListener(this);    }    @Override    public void onClick(View v) {        switch(v.getId())        {            case R.id.intent_service:            //启动IntentService                Intent intentService=new Intent(this,IntentTestService.class);                startService(intentService);                break;            case R.id.start_service:            //start调用普通Sservice                Intent startService=new Intent(this,NormalService.class);                startService(startService);                break;            case R.id.bind_service:            //bind调用service                Intent bindService=new Intent(this,NormalService.class);                if(bindService.resolveActivity(getPackageManager())!=null)                bindService(bindService,connection,BIND_AUTO_CREATE);                break;//利用Messenger进行跨进程通信            case R.id.messenger_service:                if(!hasBound) {                    Intent intent = new Intent("com.skateboard.serverservice.service.BIND");                    intent.setPackage("com.skateboard.serverservice");                    bindService(intent, messengerConnection, Context.BIND_AUTO_CREATE);                }                else                {                    sendMessageToServier();                }                break;        }    }    private ServiceConnection messengerConnection=new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            hasBound=true;            serverMessenger=new Messenger(service);            Message message=new Message();            message.what=233;            message.replyTo=clientMessenger;            try {                serverMessenger.send(message);            } catch (RemoteException e) {                e.printStackTrace();            }        }        @Override        public void onServiceDisconnected(ComponentName name) {          hasBound=false;        }    };    private ServiceConnection connection=new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            NormalService.NormalBinder binder= (NormalService.NormalBinder) service;            binder.bindMethod();        }        @Override        public void onServiceDisconnected(ComponentName name) {        }    };    private void sendMessageToServier()    {        Message message=new Message();        message.what=233;        message.replyTo=clientMessenger;        try {            serverMessenger.send(message);        } catch (RemoteException e) {            e.printStackTrace();        }    }    @Override    protected void onDestroy() {        super.onDestroy();    }}

IntentTestService继承子IntentService,它的功能很简单,就是打印一行话 “intent service start”。比较特别的就是就如如上所说的,这个service是运行在非主线程的。

public class IntentTestService extends IntentService {    public IntentTestService()    {       super("IntentTestService");    }    /**     * Creates an IntentService.  Invoked by your subclass's constructor.     *     * @param name Used to name the worker thread, important only for debugging.     */    public IntentTestService(String name) {        super(name);    }    @Override    protected void onHandleIntent(Intent intent) {        System.out.println("intent service start");    }}

NormalService可以接受startService()的方式启动同时也可以接受bindService的方式启动,这里主要讲讲bindService的启动方式,当我们bind到一个service的时候,回调用的onBind方法,这时会返回一个IBinder类,这个类个人觉得很想代理模式,通过它来调用service中的方法,在我们bindservice的时候,需要传入一个参数,ServiceConnection,在这个对象里面有两个回调方法,一个是ublic void onServiceConnected(ComponentName name, IBinder service)一个是public void onServiceDisconnected(ComponentName name),在onServiceConnected中的参数service就是我们在onBind方法中返回的IBinder,通过对它的转型,我们就可以调用相应的service中的方法了。所以这里我写了一个内部类NormalBinder,用它来打印“”bind method”并在onBind方法中返回他,这样我在MainActivity中就可以得到这个NormalBinder,并调用它内部的方法。

public class NormalService extends Service {    public NormalService() {    }    @Override    public int onStartCommand(Intent intent, int flags, int startId) {        System.out.println("service start");        stopSelf();        return super.onStartCommand(intent, flags, startId);    }    @Override    public IBinder onBind(Intent intent) {        // TODO: Return the communication channel to the service.        NormalBinder normalBinder=new NormalBinder();        return normalBinder;    }    @Override    public void onDestroy() {        super.onDestroy();        System.out.println("stop service");    }    public class NormalBinder extends Binder    {        public void bindMethod()        {            System.out.println("bind method");        }    }}

对于这个流程,我本想画个示意图,但是太懒了,我决定还是文字吧。
跨进程通讯的方式有两种,一种是AIDL,一种就是利用Messenger了,这两种方式的区别就在鱼AIDL是多线程的,而Messenger是单线程的,也就是说利用Messenger的跨进程通信在消息队列中每次只有一个请求。需要注意的是如果你需要服务器回传数据给客户端,你需要在handler的public void handleMessage(Message msg)方法中得到客户端的Messenger,这个messenger就是Messenger clientMessenger=msg.replyTo;这是在客户端在向服务端发送Message的时候传递给message的参数。

public class ServerService extends Service {    private Handler handler=new Handler()    {        @Override        public void handleMessage(Message msg) {            super.handleMessage(msg);            if(msg.what==233)            {                Messenger clientMessenger=msg.replyTo;                Message message=new Message();                message.what=322;                try {                    clientMessenger.send(message);                } catch (RemoteException e) {                    e.printStackTrace();                }            }        }    };    private Messenger messenger=new Messenger(handler);    public ServerService()    {    }    @Override    public void onCreate() {        super.onCreate();        System.out.println("service create");    }    @Override    public IBinder onBind(Intent intent) {        System.out.println("bind service");       return messenger.getBinder();    }}

接着MainAcitivyt发起bindService的请求,(这里要注意的是,5.0以后,开启service的Intent必需是显示的Intent,所以你的Intent里必须要包含另一个程序的包名的信息。)在ServiceConnection中的onServiceConnected的方法里,通过返回的IBinder来得到相应的Messenger

 private ServiceConnection messengerConnection=new ServiceConnection() {        @Override        public void onServiceConnected(ComponentName name, IBinder service) {            hasBound=true;            serverMessenger=new Messenger(service);            Message message=new Message();            message.what=233;            message.replyTo=clientMessenger;            try {                serverMessenger.send(message);            } catch (RemoteException e) {                e.printStackTrace();            }        }        @Override        public void onServiceDisconnected(ComponentName name) {          hasBound=false;        }    };
0 0
原创粉丝点击