多个activy 如何公用一个socket 连接实例
全部答案(共1个回答)
设备的搜索和链接做在一个service里面,Activity只做UI,这样就可以将底层实现功能和UI分离开来.至于多个UI和service交互,就有很多种方法了,可以用AIDL方式,也可以用broardcast来进行交互.
SocketRocket: http://t.cn/zOZHf9X 实现RFC6455
char sendbuf[30] = "0X000X000X000X010X020X000X00";
int numsnd = send(clien...
出现这类问题是由于网络连接失败而引起的,可能是远程的主机没有响应,或者网络环境太差,也就是说很大可能是远端的服务器坏了,或者网络太忙,不知道你上传的服务器...
一个应用程序可以有多个Activity,每个Activity是同级别的,那么在启动程序时,最先启动哪个Activity呢? 有些程序可能需要显示在程序列表里,有...
在system.ini文件中,在[BOOT]下面有个“shell=文件名”。正确的文件名应该是“explorer.exe”,如果不是“explo...
大家还关注
确定举报此问题
举报原因(必选):
广告或垃圾信息
激进时政或意识形态话题
不雅词句或人身攻击
侵犯他人隐私
其它违法和不良信息
报告,这不是个问题
报告原因(必选):
这不是个问题
这个问题分类似乎错了
这个不是我熟悉的地区1274人阅读
在不同的activity中怎么公用一个socket,每次在不同的activity中发消息,都要new一个新的socket出来,很麻烦。。还有就是,实际应用中,如果一段时间不发消息,socket会被android系统自动断掉,怎么才能保持socket的长连接呢?
·&&&&&&&答:可以使用Service来操作socket。多个activity统一跟service通讯进行操作。service保持对socket的操作就可以避免被干掉了
有三种方式可以解决问题
1:单例模式,即我的应用程序总共就只有一个这个类的实例
2:静态&&你写一个类FatherConnect,这个类中有一个静态变量socket,一个静态方法对他进行初始化,然后在你需要的地方都应用这个类中的socket&&这样可以保证所有的socket都是本socket,并且只有一个。
3:第三种方式是这样的,利用每个android应用程序都具有关联额应用程序对象这一事实。默认情况下,如果未定义自定义应用程序对象,android将使用android.app.Application,如果指定了的话,那么一个应用程序始终只有一个应用程序对象,所有组件都可以访问它
推荐第三种&因为这是符合android编程习惯的
service在android中既不是单独的进程,也不是线程,
Service是Android的四大组件之一,被用来执行长时间的后台任务,同样,线程也可以实现在后台执行任务,它们的区别在哪呢?何时使用Service何时使用Thread呢?今天我也来说说我的理解和总结。
首先,需要了解Service的几个特点。
(1) 默认情况下,Service其实是运行在主线程中的,如果需要执行复杂耗时的操作,必须在Service中再创建一个Thread来执行任务。
(2) Service的优先级高于后台挂起的Activity,当然,也高于Activity所创建的Thread,因此,系统可能在内存不足的时候优先杀死后台的Activity或者Thread,而不会轻易杀死Service组件,即使被迫杀死Service,也会在资源可用时重启被杀死的Service
其实,Service和Thread根本就不是一个级别的东西,Service是系统的四大组件之一,Thread只是一个用来执行后台任务的工具类,它可以在Activity中被创建,也可以在Service中被创建。因此,我们其实不应该讨论该使用Service还是Thread,而是应该讨论在什么地方创建Thread。
典型的应用中,它可以在以下三个位置被创建,不同的位置,其生命周期不一样,所以,我们应该根据该Thread的目标生命周期来决定是在Service中创建Thread还是在Activity中创建它。
(1) 在Activity中被创建
这种情况下,一般在onCreate时创建,在onDestroy()中销毁,否则,Activity销毁后,Thread是会依然在后台运行着。
这种情况下,Thread的生命周期即为整个Activity的生命周期。所以,在Activity中创建的Thread只适合完成一些依赖Activity本身有关的任务,比如定时更新一下Activity的控件状态等。
核心特点:该Thread的就是为这个Activity服务的,完成这个特定的Activity交代的任务,主动通知该Activity一些消息和事件,Activity销毁后,该Thread也没有存活的意义了。
(2)在Application中被创建
这种情况下,一般自定义Application类,重载onCreate方法,并在其中创建Thread,当然,也会在onTerminate()方法中销毁Thread,否则,如果Thread没有退出的话,即使整个Application退出了,线程依然会在后台运行着。
这种情况下,Thread的生命周期即为整个Application的生命周期。所以,在Application中创建的Thread,可以执行一些整个应用级别的任务,比如定时检查一下网络连接状态等等。
核心特点:该Thread的终极目标是为这个APP的各个Activity服务的,包括完成某个Activity交代的任务,主动通知某个Activity一些消息和事件等,APP退出之后该Thread也没有存活的意义了。
以上这两种情况下,Thread的生命周期都不应该超出整个应用程序的生命周期,也就是,整个APP退出之后,Thread都应该完全退出,这样才不会出现内存泄漏或者僵尸线程。那么,如果你希望整个APP都退出之后依然能运行该Thread,那么就应该把Thread放到Service中去创建和启动了。
(3)在Service中被创建
这是保证最长生命周期的Thread的唯一方式,只要整个Service不退出,Thread就可以一直在后台执行,一般在Service的onCreate()中创建,在onDestroy()中销毁。
所以,在Service中创建的Thread,适合长期执行一些独立于APP的后台任务,比较常见的就是:在Service中保持与服务器端的长连接。
核心特点:该Thread可以为APP提供一些“服务”或者“状态查询”,但该Thread并不需要主动通知APP任何事件,甚至不需要知道APP是谁。
总之,我们不是要考虑该用Thread或者该用Service,而是应该为Thread选择合适的生命周期,这就是我对Service和Thread的思考和理解,
如果你的线程造成内存溢出,你的任务中有引用外部资源,并且你的资源没有被正常释放,造成你的任务永远不能结束。在有很多线程的场景用线程池更合适,让线程池自己去管理,你只管往里面增加任务就好了。
参考知识库
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
访问:1535次
排名:千里之外当前位置: →
→ 一个帖子学会Android开发四大组件
一个帖子学会Android开发四大组件
& 作者及来源: 丿黑色丶幽默丨灬 - 博客园 &
&收藏到→_→:
摘要: 一个帖子学会Android开发四大组件
"一个帖子学会Android开发四大组件"::
注:本文来自“友盟杯”,仅在此阅读,学习
这个文章主要是讲android开发的四大组件,本文主要分为
一、activity详解
二、service详解
三、broadcast receiver详解
四、content provider详解
外加一个重要组件 intent的详解。
一、activity详解
activty的的也就是它所在进程的。
一个activity的启动顺序:
oncreate()——&onstart()——&onresume()
当另一个activity启动时:
第一个activity
onpause()——&第二个activity&
&&oncreate()——&onstart()——&onresume()&
——&第一个activity&
当返回到第一个activity时:
第二个activity
onpause()&——&&第一个activity on art()——&onstart()——&onresume()&
——&第二个activity& &onstop()——&ondestroy()
一个activity的销毁顺序:
(情况一)onpause()——&&process
(情况二)onpause()——&onstop()——&&process
(情况三)onpause()——&onstop()——&ondestroy()
每一个活动( activity )都处于某一个状态,对于开发者来说,是无法控制其处于某一个状态的,这些均由系统来完成。
但是当一个活动的状态发生改变的时候,开发者可以通过调用 onxx() 的方法获取到相关的通知信息。
在实现 activity 类的时候,通过覆盖( override )这些方法即可在你需要处理的时候来调用。
& && &&&&一、 oncreate&:当活动第一次启动的时候,触发该方法,可以在此时完成活动的初始化工作。&
oncreate 方法有一个参数,该参数可以为空( null ),也可以是之前调用 onsaveinstancestate ()方法保存的状态信息。
& && &&&二、&&onstart&:该方法的触发表示所属活动将被展现给用户。
& && &&&三、&&onresume&:当一个活动和用户发生交互的时候,触发该方法。
& && &&四、&&onpause&:当一个正在前台运行的活动因为其他的活动需要前台运行而转入后台运行的时候,触发该方法。这时候需要将活动的状态持久化,比如正在编辑的 记录等。
& && &&&五、&&onstop&:当一个活动不再需要展示给用户的时候,触发该方法。如果内存紧张,系统会直接结束这个活动,而不会触发 onstop 方法。 所以保存状态信息是应该在onpause时做,而不是onstop时做。活动如果没有在前台运行,都将被停止或者linux管理进程为了给新的活动预留足够的存储空间而随时结束这些活动。因此对于开发者来说,在设计的时候,必须时刻牢记这一原则。在一些情况下,onpause方法或许是活动触发的最后的方法,因此开发者需要在这个时候保存需要保存的信息。
& && &&&六、on art&:当处于停止状态的活动需要再次展现给用户的时候,触发该方法。
& && &&&七、 ondestroy&:当活动销毁的时候,触发该方法。和 onstop 方法一样,如果内存紧张,系统会直接结束这个活动而不会触发该方法。
·& && &&&onsaveinstancestate :系统调用该方法,允许活动保存之前的状态,比如说在一串字符串中的光标所处的位置等。&
通常情况下,开发者不需要重写覆盖该方法,在默认的实现中,已经提供了自动保存活动所涉及到的用户界面组件的所有状态信息。
activity栈
上面提到开发者是无法控制activity的状态的,那activity的状态又是按照何种逻辑来运作的呢?这就要知道 activity 栈。
每个activity的状态是由它在activity栈(是一个后进先出lifo,包含所有正在运行activity的队列)中的位置决定的。
当一个新的activity启动时,当前的活动的activity将会移到activity栈的顶部。
如果用户使用后退按钮返回的话,或者前台的activity结束,活动的activity就会被移出栈消亡,而在栈上的上一个活动的activity将会移上来并变为活动状态。如下图所示:& 一个的优先级是受最高优先级的activity影响的。当决定某个是否要终结去释放资源,android使用栈来决定基于activity的的优先级。
activity状态
一般认为activity有以下四种状态:
活动的:当一个activity在栈顶,它是可视的、有焦点、可此文来自: 马开东博客
转载请注明出处 网址:
接受用户输入的。android试图尽最大可能保持它活动状态,杀死其它activity来确保当前活动activity有足够的资源可使用。当另外一个activity被激活,这个将会被暂停。
暂停:在很多情况下,你的activity可视但是它没有焦点,换句话说它被暂停了。有可能原因是一个透明或者非全屏的activity被激活。
当被暂停,一个activity仍会当成活动状态,只不过是不可以接受用户输入。在极特殊的情况下,android将会杀死一个暂停的activity来为活动的activity提供充足的资源。当一个activity变为完全隐藏,它将会变成停止。
停止:当一个activity不是可视的,它“停止”了。这个activity将仍然在内存中保存它所有的状态和会员信息。尽管如此,当其它地方需要内存时,它将是最有可能被释放资源的。当一个activity停止后,一个很重要的步骤是要保存数据和当前ui状态。一旦一个activity退出或关闭了,它将变为待用状态。
待用: 在一个activity被杀死后和被装在前,它是待用状态的。待用acitivity被移除activity栈,并且需要在显示和可用之前重新启动它。
activity的四种加载模式
在android的多activity开发中,activity之间的跳转可能需要有多种方式,有时是普通的生成一个新实例,有时希望跳转到原来某个activity实例,而不是生成大量的重复的activity。加载模式便是决定以哪种方式启动一个跳转到原来某个activity实例。
在android里,有4种activity的启动模式,分别为:
·standard: 标准模式,一调用startactivity()方法就会产生一个新的实例。
·singletop: 如果已经有一个实例位于activity栈的顶部时,就不产生新的实例,而只是调用activity中的newinstance()方法。如果不位于栈顶,会产生一个新的实例。
·singletask: 会在一个新的task中产生这个实例,以后每次调用此文来自: 马开东博客
转载请注明出处 网址:
都会使用这个,不会去产生新的实例了。
·singleinstance: 这个跟singletask基本上是一样,只有一个区别:在这个模式下的activity实例所处的task中,只能有这个activity实例,不能有其他的实例。
这些启动模式可以在功能清单文件androidmanifest.xml中进行设置,中的launchmode属性。
相关的代码中也有一些标志可以使用,比如我们想只启用一个实例,则可以使用 intent.flag_activity_reorder_to_front 标志,这个标志表示:如果这个activity已经启动了,就不产生新的activity,而只是把这个activity实例加到栈顶来就可以了。
intent intent = new intent(reorderfour.this, reordertwo.class);
intent.addflags(intent.flag_activity_reorder_to_front);
startactivity(intent);
activity的加载模式受启动activity的intent对象中设置的flag和manifest文件中activity的元素的特性值交互控制。
下面是影响加载模式的一些特性
核心的intent flag有:
flag_activity_new_task
flag_activity_clear_top
flag_activity_reset_task_if_needed
flag_activity_single_top
核心的特性有:
taskaffinity
launchmode
allowtaskreparenting
cleartaskonlaunch
alwaysretaintaskstate
finishontasklaunch
四种加载模式的区别
所属task的区别
一般情况下,“standard”和”singletop”的activity的目标task,和收到的intent的发送者在同一个task内,就相当于谁调用它,它就跟谁在同一个task中。
除非intent包括参数flag_activity_new_task。如果提供了flag_activity_new_task参数,会启动到别的task里。
“singletask”和”singleinstance” 总是把要启动的activity作为一个task的根元素,他们不会被启动到一个其他task里。
是否允许多个实例
“standard”和”singletop”可以被实例化多次,并且是可以存在于不同的task中;这种实例化时一个task可以包括一个activity的多个实例;
“singletask”和”singleinstance”则限制只生成一个实例,并且是task的根元素。
singletop 要求如果创建intent的时候栈顶已经有要创建的activity的实例,则将intent发送给该实例,而不创建新的实例。
是否允许其它activity存在于本task内
“singleinstance”独占一个task,其它activity不能存在那个task里;
如果它启动了一个新的activity,不管新的activity的launch mode 如何,新的activity都将会到别的task里运行(如同加了flag_activity_new_task参数)。
而另外三种模式,则可以和其它activity共存。
是否每次都生成新实例
“standard”对于每一个启动intent都会生成一个activity的新实例;
“singletop”的activity如果在task的栈顶的话,则不生成新的该activity的实例,直接使用栈顶的实例,否则,生成该activity的实例。
比如:
现在task栈元素为a-b-c-d(d在栈顶),这时候给d发一个启动intent,如果d是 “standard”的,则生成d的一个新实例,栈变为a-b-c-d-d。
如果d是singletop的话,则不会生产d的新实例,栈状态仍为a-b-c-d
如果这时候给b发intent的话,不管b的launchmode是”standard” 还是 “singletop” ,都会生成b的新实例,栈状态变为a-b-c-d-b。
“singleinstance”是其所在栈的唯一activity,它会每次都被重用。
“singletask” 如果在栈顶,则接受intent,否则,该intent会被丢弃,但是该task仍会回到前台。 当已经存在的activity实例处理新的intent时候,会调用onnewintent()方法,如果收到intent生成一个activity实例,那么用户可以通过back键回到上一个状态;如果是已经存在的一个activity来处理这个intent的话,用户不能通过按back键返回到这之前的状态。
-----------------------------------
二、service详解
service可以在和多场合的应用中使用,比如播放的时候用户启动了其他activity这个时候程序要在后台继续播放,比如检测sd卡上文件的变化,再或者在后台记录你 位置的改变等等,总之服务嘛,总是藏在后头的。
service是在一段不定的时间运行在后台,不和用户交互应用组件。每个service必须在manifest中 通过&service&来声明。可以通过contect.startservice和contect.bindserverice来启动。
service和其他的应用组件一样,运行在进程的主线程中。这就是说如果service需要很多耗时或者阻塞的操作,需要在其子线程中实现。
service的两种模式(startservice()/bindservice()不是完全分离的):
本地服务 local service 用于内部。
它可以启动并运行,直至有人停止了它或它自己停止。在这种方式下,它以调用context.startservice()启动,而以调用context.stopservice()结束。它可以调用service.stopself() 或 service.stopselfresult()来自己停止。不论调用了多少次startservice()方法,你只需要调用一次stopservice()来停止服务。
用于实现自己的一些耗时任务,比如查询升级信息,并不占用比如activity所属线程,而是单开线程后台执行,这样 比较好。
远程服务 remote service 用于android系统内部的之间。
它可以通过自己定义并暴露出来的接口进行程序操作。客户端建立一个到服务对象的连接,并通过那个连接来调用服务。连接以调用context.bindservice()方法建立,以调用 context.unbindservice()关闭。多个客户端可以绑定至同一个服务。如果服务此时还没有加载,bindservice()会先加载它。
可被其他复用,比如天气预报服务,其他不需要再写这样的服务,调用已有的即可。
使用context.startservice() 启动service是会会经历:
context.startservice() -&oncreate()- &onstart()-&service running
context.stopservice() | -&ondestroy() -&service stop
如果service还没有运行,则android先调用oncreate()然后调用onstart();如果service已经运行,则只调用onstart(),所以一个service的onstart方法可能会重复调用多次。
stopservice的时候直接ondestroy,如果是调用者自己直接退出而没有调用stopservice的话,service会一直在后台运行。该service的调用者再启动起来后可以通过stopservice关闭service。
所以调用startservice的为:oncreate --& onstart(可多次调用) --& ondestroy
使用使用context.bindservice()启动service会经历:
context.bindservice()-&oncreate()-&onbind()-&service running
onunbind() -& ondestroy() -&service stop
onbind将返回给客户端一个ibind接口实例,ibind允许客户端回调服务的方法,比如得到service运行的状态或其他操作。这个时候把调用者(context,例如activity)会和service绑定在一起,context退出了,srevice就会调用onunbind-&ondestroy相应退出。
所以调用bindservice的为:oncreate --& onbind(只一次,不可多次绑定) --& onunbind --& ondestory。
在service每一次的开启关闭过程中,只有onstart可被多次调用(通过多次startservice调用),其他oncreate,onbind,onunbind,ondestory在一个中只能被调用一次。
而启动service,根据onstartcommand的返回值不同,有两个附加的模式:
1. start_sticky 用于显示启动和停止service。
2. start_not_sticky或start_redeliver_intent用于有命令需要处理时才运行的模式。
服务不能自己运行,需要通过调用context.startservice()或context.bindservice()方法启动服务。这两个方法都可以启动service,但是它们的使用场合有所不同。
1. 使用startservice()方法启用服务,调用者与服务之间没有此文来自: 马开东博客
转载请注明出处 网址:
关连,即使调用者退出了,服务仍然运行。
如果打算采用context.startservice()方法启动服务,在服务未被创建时,系统会先调用服务的oncreate()方法,接着调用onstart()方法。
如果调用startservice()方法前服务已经被创建,多次调用startservice()方法并不会导致多次创建服务,但会导致多次调用onstart()方法。
采用startservice()方法启动的服务,只能调用context.stopservice()方法结束服务,服务结束时会调用ondestroy()方法。
2. 使用bindservice()方法启用服务,调用者与服务绑定在了一起,调用者一旦退出,服务也就终止,大有“不求同时生,必须同时死”的特点。
onbind()只有采用context.bindservice()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,多次调用context.bindservice()方法并不会导致该方法被多次调用。
采用context.bindservice()方法启动服务时只能调用onunbind()方法解除调用者与服务解除,服务结束时会调用ondestroy()方法。
看看官方给出的比较流程示意图:
官方文档告诉我们,一个service可以同时start并且bind,在这样的情况,系统会一直保持service的运行状态如果service已经start了或者bind_auto_create标志被设置。如果没有一个条件满足,那么系统将会调用ondestory方法来终止service.所有的清理工作(终止线程,反注册接收器)都在ondestory中完成。
拥有service的进程具有较高的优先级
官方文档告诉我们,android系统会尽量保持拥有service的进程运行,只要在该service已经被启动(start)或者客户端连接(bindservice)到它。当内存不足时,需要保持,拥有service的进程具有较高的优先级。
1. 如果service正在调用oncreate,onstartcommand或者ondestory方法,那么用于当前service的进程则变为前台进程以避免被killed。
2. 如果当前service已经被启动(start),拥有它的进程则比那些用户可见的进程优先级低一些,但是比那些不可见的进程更重要,这就意味着service一般不会被killed.
3. 如果客户端已经连接到service (bindservice),那么拥有service的进程则拥有最高的优先级,可以认为service是可见的。
4. 如果service可以使用startforeground(int, notification)方法来将service设置为前台状态,那么系统就认为是对用户可见的,并不会在内存不足时killed。
如果有其他的应用组件作为service,activity等运行在相同的进程中,那么将会增加该进程的重要性。
本地service
1.不需和activity交互的本地服务
public class localservice extends service {
private static final string tag = &localservice&;
public ibinder onbind(intent intent) {
log.i(tag, &onbind&);
public void oncreate() {
log.i(tag, &oncreate&);
super.oncreate();
public void ondestroy() {
log.i(tag, &ondestroy&);
super.ondestroy();
public void onstart(intent intent, int startid) {
log.i(tag, &onstart&);
super.onstart(intent, startid);
activity:
public class serviceactivity extends activity {
protected void oncreate(bundle savedinstancestate) {
super.oncreate(savedinstancestate);
setcontentview(r.layout.servicedemo);
((button) findviewbyid(r.id.startlocalservice)).setonclicklistener(
new view.onclicklistener(){
public void onclick(view view) {
// todo auto-generated method stub
startservice(new intent(&com.demo.service_demo&));
((button) findviewbyid(r.id.stoplocalservice)).setonclicklistener(
new view.onclicklistener(){
public void onclick(view view) {
// todo auto-generated method stub
stopservice(new intent(&com.demo.service_demo&));
在androidmanifest.xml添加:
&service android:name=&.localservice&&
&intent-filter&
&action android:name=&com.demo.service_demo& /&
&category android:name=&android.intent.category.default& /&
&/intent-filter&
&/service&
否则启动服务时会提示new intent找不到&com.demo.service_demo&。
对于这类不需和activity交互的本地服务,是使用startservice/stopservice的最好例子。
运行时可以发现第一次startservice时,会调用oncreate和onstart,在没有stopservice前,无论点击多少次startservice,都只会调用onstart。而stopservice时调用ondestroy。再次点击stopservice,会发现不会进入service的的,即不会再调用oncreate,onstart和ondestroy。
而onbind在startservice/stopservice中没有调用。
2.本地服务和activity交互
对于这种case,官方的sample(apidemo\app.localservice)是最好的例子:
* this is an example of implementing an application service that runs locally
* in the same process as the application. the {@link localservicecontroller}
* and {@link localservicebinding} classes show how to interact with the
* service.
* &p¬ice the use of the {@link notificationmanager} when inte ing things
* happen in the service. this is generally how background services should
* interact with the user, rather than doing something more disruptive such as
* calling startactivity().
public class localservice extends service {
private not
* class for clients to access. because we know this service always
* runs in the same process as its clients, we don't need to deal with
public class localbinder extends binder {
localservice getservice() {
return localservice.
public void oncreate() {
mnm = (notificationmanager)getsystemservice(notification_service);
// display a notification about us starting. we put an icon in the status bar.
shownotification();
public int onstartcommand(intent intent, int flags, int startid) {
log.i(&localservice&, &received start id & + startid + &: & + intent);
// we want this service to continue running until it is explicitly
// stopped, so return sticky.
return start_
public void ondestroy() {
// cancel the persistent notification.
mnm.cancel(r.string.local_service_started);
// tell the user we stopped.
toast.maketext(this, r.string.local_service_stopped, toast.length_short).show();
public ibinder onbind(intent intent) {
// this is the object that receives interactions from clients. see
// remoteservice for a more complete example.
private final ibinder mbinder = new localbinder();
* show a notification while this service is running.
private void shownotification() {
// in this sample, we'll use the same text for the ticker and the expanded notification
charsequence text = gettext(r.string.local_service_started);
// set the icon, scrolling text and timestamp
notification notification = new notification(r.drawable.stat_sample, text,
system.currenttimemillis());
// the pendingintent to launch our activity if the user selects this notification
pendingintent contentintent = pendingintent.getactivity(this, 0,
new intent(this, localservicecontroller.class), 0);
// set the info for the views that show in the notification panel.
notification.setlatesteventinfo(this, gettext(r.string.local_service_label),
text, contentintent);
// send the notification.
// we use a layout id because it is a unique number. we use it later to cancel.
mnm.notify(r.string.local_service_started, notification);
这里可以发现onbind需要返回一个ibinder对象。也就是说和上一例子localservice不同的是,
1. 添加了一个public内部类继承binder,并添加getservice方法来返回当前的service对象;
2. 新建一个ibinder对象--new那个binder内部类;
3. onbind方法返还那个ibinder对象。
activity:
* &p&example of binding and unbinding to the {@link localservice}.
* this demonstrates the implementation of a service which the client will
* bind to, receiving an object through which it can communicate with the service.&/p&
public class localservicebinding extends activity {
private locals
protected void oncreate(bundle savedinstancestate) {
super.oncreate(savedinstancestate);
setcontentview(r.layout.local_service_binding);
// watch for button clicks.
button button = (button)findviewbyid(r.id.bind);
button.setonclicklistener(mbindlistener);
button = (button)findviewbyid(r.id.unbind);
button.setonclicklistener(munbindlistener);
private serviceconnection mconnection = new serviceconnection() {
public void onserviceconnected(componentname classname, ibinder service) {
// this is called when the connection with the service has been
// established, giving us the service object we can use to
// interact with the service. because we have bound to a explicit
// service that we know is running in our own process, we can
// cast its ibinder to a concrete class and directly access it.
mboundservice = ((localservice.localbinder)service).getservice();&
// tell the user about this for our demo.
toast.maketext(localservicebinding.this, r.string.local_service_connected,
toast.length_short).show();
public void onservicedisconnected(componentname classname) {&
// this is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
// because it is running in our same process, we should never
// see this happen.
mboundservice =
toast.maketext(localservicebinding.this, r.string.local_service_disconnected,
toast.length_short).show();
private onclicklistener mbindlistener = new onclicklistener() {
public void onclick(view v) {
// establish a connection with the service. we use an explicit
// class name because we want a specific service implementation that
// we know will be running in our own process (and thus won't be
// supporting component replacement by other applications).
bindservice(new intent(localservicebinding.this,&
localservice.class), mconnection, context.bind_auto_create);
misbound =
private onclicklistener munbindlistener = new onclicklistener() {
public void onclick(view v) {
if (misbound) {
// detach our existing connection.
unbindservice(mconnection);
misbound =
明显看出这里面添加了一个名为serviceconnection类,并实现了onserviceconnected(从ibinder获取service对象)和onservicedisconnected(set service to null)。
而bindservice和unbindservice方法都是操作这个serviceconnection对象的。
androidmanifest.xml里添加:
&service android:name=&.app.localservice& /&
这里没什么特别的,因为service没有需要什么特别的action,所以只是声明service而已,而activity和普通的没差别。
运行时,发现调用次序是这样的:
bindservice:
1.localservice : oncreate
2.localservice : onbind
3.activity: onserviceconnected
unbindservice: 只是调用ondestroy
可见,onstart是不会被调用的,而onservicedisconnected没有调用的原因在上面代码的注释有说明。
------------------------
三、broadcast receiver详解
broadcastreceiver 用于异步接收广播intent。主要有两大类,用于接收广播的:
·正常广播 normal broadcasts(用 context.sendbroadcast()发送)是完全异步的。它们都运行在一个未定义的顺序,通常是在同一时间。这样会更有效,但意味着receiver不能包含所要使用的结果或中止的api。
·有序广播 ordered broadcasts(用 context.sendorderedbroadcast()发送)每次被发送到一个receiver。所谓有序,就是每个receiver执行后可以传播到下一个receiver,也可以完全中止传播--不传播给其他receiver。 而receiver运行的顺序可以通过matched
intent-filter 里面的android:priority来控制,当priority优先级相同的时候,receiver以任意的顺序运行。
要注意的是,即使是normal broadcasts,系统在某些情况下可能会恢复到一次传播给一个receiver。 特别是receiver可能需要创建一个进程,为了避免系统超载,只能一次运行一个receiver。
broadcast receiver 并没有提供可视化的界面来显示广播信息。可以使用notification和notification manager来实现可视化的信息的界面,显示广播信息的内容,图标及震动信息。
一个broadcastreceiver 对象只有在被调用onreceive(context, intent)的才有效的,当从该函数返回后,该对象就无效的了,结束。
因此从这个特征可以看出,在所调用的onreceive(context, intent)函数里,不能有过于耗时的操作,不能使用线程来执行。对于耗时的操作,请start service来完成。因为当得到其他异步操作所返回的结果时,broadcastreceiver 可能已经无效了。
发送广播
事件的广播比较简单,构建intent对象,可调用sendbroadcast(intent)方法将广播发出。另外还有sendorderedbroadcast(),sendstickybroadcast()等方法,请查阅api doc。
1.new intent with action name
intent intent = new intent(string action);
或者 只是new intent, 然后
intent.setaction(string action);
2.set data等准备好了后,in activity,
sendbroadcast(intent); // 发送广播
接收广播
通过定义一个继承broadcastreceiver类来实现,继承该类后覆盖其onreceiver方法,并在该方法中响应事件。
public class smsreceiver extends broadcastreceiver {&
& && &&&@override&
& && &&&public void onreceive(context context, intent intent) {&
& && && && && & // get data from sms intent&
& && && && && & bundle bundle = intent.getextras();&
& && && && && & if (bundle != null){&
& && && && && && && && &// get message by &pdus&&
& && && && && && && && &object[] objarray = (object[]) bundle.get(&pdus&);&
& && && && && && && && &// rebuild sms&
& && && && && && && && &smsmessage[] messages = new smsmessage[objarray.length];&
& && && && && && && && &for (int i=0; i & objarray. i++){&
& && && && && && && && && && &&&messages[i] = smsmessage.createfrompdu((byte[])objarray[i]);&
& && && && && && && && && && &&&stringbuilder str = new stringbuilder(&from: &);&
& && && && && && && && && && &&&str.append(messages[i].getdisplayoriginatingaddress());&
& && && && && && && && && && &&&str.append(&\nmessage:\n&);&
& && && && && && && && && && &&&str.append(messages[i].getdisplaymessagebody());&
& && && && && && && && && && &&&toast.maketext(context, str.tostring(), toast.length_long)&
& && && && && && && && && && && && && && && && &.show();&
& && && && && && && && &}&
& && && && && & }&
& && &&&}&
注册receiver
注册有两种方式:
1. 静态方式,在androidmanifest.xml的application里面定义receiver并设置要接收的action。
&receiver android:name=&.smsreceiver&&
&intent-filter&
&action android:name=&android.provider.telephony.sms_received& /&
&/intent-filter&
&/receiver&
2.&动态方式,
在activity里面调用函数来注册,和静态的内容差不多。一个形参是receiver,另一个是intentfilter,其中里面是要接收的action。
public class hellodemo extends activity {& &&
& && &&&private broadc& &&
& && &&&@override&
& && &&&protected void onstart() {&
& && && && && & super.onstart();&
& && && && && & receiver = new callreceiver();&
& && && && && & re terreceiver(receiver, new intentfilter(&android.intent.action.phone_state&));&
& && &&&}&
& && &&&@override&
& && &&&protected void onstop() {&
& && && && && & unre terreceiver(receiver);&
& && && && && & super.onstop();&
& && &&&}&
一个receiver可以接收多个action的,即可以有多个intent-filter,需要在onreceive里面对intent.getaction(action name)进行判断。
个人推荐使用静态注册方式,由系统来管理receiver,而且程序里的所有receiver,可以在xml里面一目了然。而动态注册方式,隐藏在代码中,比较难发现。
而且动态注册,需要特别注意的是,在退出程序前要记得调用context.unre terreceiver()方法。一般在activity的onstart()里面进行注册, onstop()里面进行注销。官方提醒,如果在activity.onresume()里面注册了,就必须在activity.onpause()注销。
permission权限
要接收某些action,需要在androidmanifest.xml里面添加相应的permission。例如接收sms:
&uses-permission android:name=&android.permission.receive_sms& /&
下面给出动态注册的接收来电的广播处理的callreceiver的代码:
一种方式是直接读取intent.getstringextra(&incoming_number&)来获取来电号码:
public class callreceiver extends broadcastreceiver {&
& && &&&@override&
& && &&&public void onreceive(context context, intent intent) {&
& && && && && & telephonymanager telemanager = (telephonymanager) context.getsystemservice(context.telephony_service);&
& && && && && &&&
& && && && && & switch(telemanager.getcallstate()){&
& && && && && & case telephonymanager.call_state_ringing: //响铃&
& && && && && && && && &toast.maketext(context, &ringing: & + intent.getstringextra(&incoming_number&), toast.length_long).show();&
& && && && && && && && &&
& && && && && & case telephonymanager.call_state_offhook: //接听&
& && && && && && && && &toast.maketext(context, &offhook: & + intent.getstringextra(&incoming_number&), toast.length_long).show();&
& && && && && && && && &&
& && && && && & case telephonymanager.call_state_idle: //挂断&
& && && && && && && && &toast.maketext(m_context, &idle: & + incomingnumber, toast.length_long).show();&
& && && && && && && && &&
& && && && && & }&
& && &&&}&
在运行时,发现除了响铃时可以获取来电号码,接听和挂断都不能成功获取的,显示为null。
另一种方式是通过phonestatelistener的oncallstatechanged来监听状态的变化:
public class callreceiver extends broadcastreceiver {&
& && &&&private context m_&
& && &&&@override&
& && &&&public void onreceive(context context, intent intent) {&
& && && && && & m_context =&
& && && && && & telephonymanager telemanager = (telephonymanager) context.getsystemservice(context.telephony_service);&
& && && && && & telemanager.listen(new phonestatelistener(){&
& && && && && && && && &@override&
& && && && && && && && &public void oncallstatechanged(int state, string incomingnumber) {&
& && && && && && && && && && &&&switch(state){&
& && && && && && && && && && &&&case telephonymanager.call_state_ringing: //响铃&
& && && && && && && && && && && && && & toast.maketext(m_context, &ringing: & + incomingnumber, toast.length_long)&
& && && && && && && && && && && && && && && && && && && && && & .show();&
& && && && && && && && && && && && && &&
& && && && && && && && && && &&&case telephonymanager.call_state_offhook: //接听&
& && && && && && && && && && && && && & toast.maketext(m_context, &offhook: & + incomingnumber, toast.length_long)&
& && && && && && && && && && && && && & .show();&
& && && && && && && && && && && && && &&
& && && && && && && && && && &&&case telephonymanager.call_state_idle: //挂断&
& && && && && && && && && && && && && & toast.maketext(m_context, &idle: & + incomingnumber, toast.length_long)&
& && && && && && && && && && && && && & .show();&
& && && && && && && && && && && && && &&
& && && && && && && && && && &&&}&
& && && && && && && && &}}, phonestatelistener.listen_call_state);&&
& && &&&}&
运行时也发现incomingnumber在接听和挂断时获取为blank。
因为这里监听的是通话的状态变化,所以这个receiver会被调用3次。
监听通话状态需要加上权限:
&uses-permission android:name=&android.permission.read_phone_state&/&
===========
小结:
1. 对于sendbroadcast的intent对象,需要设置其action name;
2. 推荐使用显式指明receiver,在配置文件androidmanifest.xml指明;
3. 一个receiver可以接收多个
4. 每次接收广播都会重新生成一个接收广播的对象,再次调用onreceive;
5. 在broadcast 中尽量不要处理太多逻辑问题,建议复杂的逻辑交给activity 或者 service 去处理。
--------------------------------------------
四、content provider详解
contentprovider(内容提供者)是android中的四大组件之一。主要用于对外共享数据,也就是通过contentprovider把应用中的数据共享给其他应用访问,其他应用可以通过contentprovider对指定应用中的数据进行操作。contentprovider分为系统的和自定义的,系统的也就是例如联系人,图片等数据。
android中对数据操作包含有:
file, sqlite3, preferences, contectresolver与contentprovider前三种数据操作方式都只是针对本应用内数据,程序不能通过这三种方法去操作别的应用内的数据。
android中提供contectresolver与contentprovider来操作别的的数据。
使用方式:
一个应用实现contentprovider来提供内容给别的应用来操作,
一个应用通过contentresolver来操作别的应用数据,当然在自己的应用中也可以。
以下这段是google doc中对contentprovider的大致概述:
内容提供者将一些特定的数据供给其它使用。内容提供者继承于contentprovider 基类,为其它取用和存储它管理的数据实现了一套标准方法。然而,并不直接调用这些方法,而是使用一个 contentresolver 对象,调用它的方法作为替代。contentresolver可以与任意内容提供者进行会话,与其合作来对所有相关交互通讯进行管理。
1.contentprovider
android提供了一些主要数据类型的contentprovider,比如音频、视频、图片和私人通讯录等。可在android.provider包下面找到一些android提供的contentprovider。通过获得这些contentprovider可以查询它们包含的数据,当然前提是已获得适当的读取权限。
主要方法:
public
boolean oncreate() 在创建contentprovider时调用
public cursor query(uri, string[], string, string[], string) 用于查询指定uri的contentprovider,返回一个cursor
public uri insert(uri, contentvalues) 用于添加数据到指定uri的contentprovider中
public int update(uri, contentvalues, string, string[]) 用于更新指定uri的contentprovider中的数据
public int delete(uri, string, string[]) 用于从指定uri的contentprovider中删除数据
public string gettype(uri) 用于返回指定的uri中的数据的mime类型
*如果操作的数据属于集合类型,那么mime类型字符串应该以vnd.android.cursor.dir/开头。
例如:要得到所有person记录的uri为content://contacts/person,那么返回的mime类型字符串为&vnd.android.cursor.dir/person&。
*如果要操作的数据属于非集合类型数据,那么mime类型字符串应该以vnd.android.cursor.item/开头。
例如:要得到id为10的person记录的uri为content://contacts/person/10,那么返回的mime类型字符串应为&vnd.android.cursor.item/person&。
2.contentresolver
当外部应用需要对contentprovider中的数据进行添加、删除、修改和查询操作时,可以使用contentresolver类来完成,要获取contentresolver对象,可以使用context提供的getcontentresolver()方法。
contentresolver cr = getcontentresolver();
contentresolver提供的方法和contentprovider提供的方法对应的有以下几个方法。
public uri insert(uri uri, contentvalues values) 用于添加数据到指定uri的contentprovider中。
public int delete(uri uri, string selection, string[] selectionargs) 用于从指定uri的contentprovider中删除数据。
public int update(uri uri, contentvalues values, string selection, string[] selectionargs) 用于更新指定uri的contentprovider中的数据。
public cursor query(uri uri, string[] projection, string selection, string[] selectionargs, string sortorder) 用于查询指定uri的contentprovider。
uri指定了将要操作的contentprovider,其实可以把一个uri看作是一个网址,我们把uri分为三部分。
第一部分是&content://&。可以看作是网址中的&http://&。
第二部分是主机名或authority,用于唯一标识这个contentprovider,外部应用需要根据这个标识来找到它。可以看作是网址中的主机名,比如&blog.马开东&。
第三部分是路径名,用来表示将要操作的数据。可以看作网址中细分的内容路径。