Android Activity与Service通信(不同进程之间)详解
在android中,activity主要负责前台页面的展示,service主要负责需要长期运行的任务,所以在我们实际开发中,就会常常遇到activity与service之间的通信,我们一般在activity中启动后台service,通过intent来启动,intent中我们可以传递数据给service,而当我们service执行某些操作之后想要更新ui线程,我们应该怎么做呢?接下来我就介绍三种方式来实现service与activity之间的通信问题
activity与service通信的方式有三种:
继承binder类
这个方式只有当你的acitivity和service处于同一个application和进程时,才可以用,比如你后台有一个播放背景音乐的service,这时就可以用这种方式来进行通信。
用例子来说明其使用方法:
1. 来看service的写法:
public class localservice extends service { // 实例化自定义的binder类 private final ibinder mbinder = new localbinder(); // 随机数的生成器 private final random mgenerator = new random(); /** * 自定义的binder类,这个是一个内部类,所以可以知道其外围类的对象,通过这个类,让activity知道其service的对象 */ public class localbinder extends binder { localservice getservice() { // 返回activity所关联的service对象,这样在activity里,就可调用service里的一些公用方法和公用属性 return localservice.this; } } @override public ibinder onbind(intent intent) { return mbinder; } /** public方法,activity可以进行调用 */ public int getrandomnumber() { return mgenerator.nextint(100); } }
在service里定义一个内部类,binder的子类,通过这个类,把service的对象传给activity,这样activity就可以调用service里的公用方法和公用属性了,但这种方式,一定要在同一个进程和同一个application里。
2. 再看相应activity的代码:
public class bindingactivity extends activity { localservice mservice; boolean mbound = false; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); } @override protected void onstart() { super.onstart(); // 绑定service,绑定后就会调用mconnetion里的onserviceconnected方法 intent intent = new intent(this, localservice.class); bindservice(intent, mconnection, context.bind_auto_create); } @override protected void onstop() { super.onstop(); // 解绑service,这样可以节约内存 if (mbound) { unbindservice(mconnection); mbound = false; } } /** 用户点击button,就读取service里的随机数 */ public void onbuttonclick(view v) { if (mbound) { // 用service的对象,去读取随机数 int num = mservice.getrandomnumber(); toast.maketext(this, "number: " + num, toast.length_short).show(); } } /** 定交serviceconnection,用于绑定service的*/ private serviceconnection mconnection = new serviceconnection() { @override public void onserviceconnected(componentname classname, ibinder service) { // 已经绑定了localservice,强转ibinder对象,调用方法得到localservice对象 localbinder binder = (localbinder) service; mservice = binder.getservice(); mbound = true; } @override public void onservicedisconnected(componentname arg0) { mbound = false; } }; }
这里就是通过ibinder来得到localservice对象,再去调用其public方法。
使用messenger
上面的方法只能在同一个进程里才能用,如果要与另外一个进程的service进行通信,则可以用messenger。
其实实现ipc的方式,还有aidl,但推荐使用messenger,有两点好处:
1. 使用messenger方式比使用aidl的方式,实现起来要简单很多
2. 使用messenger时,所有从activity传过来的消息都会排在一个队列里,不会同时请求service,所以是线程安全的。如果
你的程序就是要多线程去访问service,就可以用aidl,不然最好使用messenger的方式。
不过,其实messenger底层用的就是aidl实现的,看一下实现方式,先看service的代码:
public class messengerservice extends service { /** 用于handler里的消息类型 */ static final int msg_say_hello = 1; /** * 在service处理activity传过来消息的handler */ class incominghandler extends handler { @override public void handlemessage(message msg) { switch (msg.what) { case msg_say_hello: toast.maketext(getapplicationcontext(), "hello!", toast.length_short).show(); break; default: super.handlemessage(msg); } } } /** * 这个messenger可以关联到service里的handler,activity用这个对象发送message给service,service通过handler进行处理。 */ final messenger mmessenger = new messenger(new incominghandler()); /** * 当activity绑定service的时候,通过这个方法返回一个ibinder,activity用这个ibinder创建出的messenger,就可以与service的handler进行通信了 */ @override public ibinder onbind(intent intent) { toast.maketext(getapplicationcontext(), "binding", toast.length_short).show(); return mmessenger.getbinder(); } }
再看一下activity的代码:
public class activitymessenger extends activity { /** 向service发送message的messenger对象 */ messenger mservice = null; /** 判断有没有绑定service */ boolean mbound; private serviceconnection mconnection = new serviceconnection() { public void onserviceconnected(componentname classname, ibinder service) { // activity已经绑定了service // 通过参数service来创建messenger对象,这个对象可以向service发送message,与service进行通信 mservice = new messenger(service); mbound = true; } public void onservicedisconnected(componentname classname) { mservice = null; mbound = false; } }; public void sayhello(view v) { if (!mbound) return; // 向service发送一个message message msg = message.obtain(null, messengerservice.msg_say_hello, 0, 0); try { mservice.send(msg); } catch (remoteexception e) { e.printstacktrace(); } } @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.main); } @override protected void onstart() { super.onstart(); // 绑定service bindservice(new intent(this, messengerservice.class), mconnection, context.bind_auto_create); } @override protected void onstop() { super.onstop(); // 解绑 if (mbound) { unbindservice(mconnection); mbound = false; } } }
注意:以上写的代码只能实现从activity向service发送消息,如果想从service向activity发送消息,只要把代码反过来写就可以了。
使用aidl
aidl,android interface definition language。建立aidl服务要比建立普通的服务复杂一些,具体步骤如下:
(1)在eclipse android工程的java包目录中建立一个扩展名为aidl的文件。该文件的语法类似于java代码,但会稍有不同。详细介绍见实例的内容。
(2)如果aidl文件的内容是正确的,adt会自动生成一个java接口文件(*.java)。
(3)建立一个服务类(service的子类)。
(4)实现由aidl文件生成的java接口。
(5)在androidmanifest.xml文件中配置aidl服务,尤其要注意的是,<action>标签中android:name的属性值就是客户端要引用该服务的id,也就是intent类的参数值。
感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!
下一篇: 4种java复制文件的方式
推荐阅读
-
Android Activity与Service通信(不同进程之间)详解
-
Android Activity 与Service进行数据交互详解
-
Android Activity与Service通信(不同进程之间)详解
-
Android Fragment与Activity之间的相互通信实例代码
-
Android Fragment与Activity之间的相互通信实例代码
-
Service与Activity之间的通信(同一进程)
-
Android实现Activity、Service与Broadcaster三大组件之间互相调用的方法详解
-
Service与Activity之间的通信(同一进程)
-
Android实现Activity、Service与Broadcaster三大组件之间互相调用的方法详解
-
Android Activity与Fragment之间的跳转实例详解