Android Service中方法使用详细介绍
service作为四大组件值得我们的更多的关注
在android中,activity主要负责前台页面的展示,service主要负责需要长期运行的任务。例如,一个从service播放音乐的音乐播放器,应被设置为前台运行,因为用户会明确地注意它的运行.在状态栏中的通知可能会显示当前的歌曲并且允许用户启动一个activity来与音乐播放器交互。
service的两种实现形式
1.非绑定
通过调用应用程序组件(例如activity)的startservice()方法来启动一个服务.一旦启动,服务就会在后台一直运行,即使应用程序组件此时被关闭.通常,已经启动的服务会处理一些单一功能,并且也不需要返回结果给调用者.例如,在网络上下载或上传文件.当服务的工作处理结束,才会自己关闭服务.
2.绑定(bind)
通过调用应用程序组件的bindservice()方法来绑定一个服务.已绑定的服务会提供一个客户端-服务端交互接口.该接口主要用来与应用程序交互,发送请求,获取结果,甚至通过ipc来访问进程.只要一个程序组件绑定服务就会运行绑定服务,多个应用程序组件可以同时时间绑定一个服务.当所有的应用程序组件都解除绑定,该绑定服务器就会被销毁.
实现service的方法介绍
onstartcommand()
系统在其它组件比如activity通过调用startservice()请求service启动时调用这个方法.一旦这个方法执行,service就启动并且在后台长期运行.如果你实现了它,你需要负责在service完成任务时停止它,通过调用stopself()或stopservice().(如果你只想提供绑定,你不需实现此方法).
onbind()
当组件调用bindservice()想要绑定到service时(比如想要执行进程间通讯)系统调用此方法.在你的实现中,你必须提供一个返回一个ibinder来以使客户端能够使用它与service通讯,你必须总是实现这个方法,但是如果你不允许绑定,那么你应返回null.
oncreate()
系统在service第一次创建时执行此方法,来执行只运行一次的初始化工作(在调用它方法如onstartcommand()或onbind()之前).如果service已经运行,这个方法不会被调用.
ondestroy()
系统在service不再被使用并要销毁时调用此方法.你的service应在此方法中释放资源,比如线程,已注册的侦听器,接收器等等.这是service收到的最后一个调用.
如果一个组件通过调用startservice()启动一个service(最终导致onstartcommand()被调用),之后service会保持运行,直到它通过stopself()停止自己或另外的组件调用stopservice()停止它.
service实现代码
1.非绑定
新建一个myservice继承自service,并重写父类的oncreate()、onstartcommand()和ondestroy()方法
public class myintentservice extends intentservice { public myintentservice() { super("myintentservice"); } @override protected void onhandleintent(intent intent) { // intentservice会使用单独的线程来执行该方法的代码 // 该方法内执行耗时任务,比如下载文件,此处只是让线程等待20秒 long endtime = system.currenttimemillis() + 20 * 1000; system.out.println("onstart"); while (system.currenttimemillis() < endtime) { synchronized (this) { try { wait(endtime - system.currenttimemillis()); } catch (interruptedexception e) { e.printstacktrace(); } } } system.out.println("----耗时任务执行完成---"); } }
我们在布局文件中加入了两个按钮,一个用于启动service,一个用于停止service。
然后打开或新建mainactivity作为程序的主activity,在里面加入启动service和停止service的逻辑,代码如下所示:
public class mainactivity extends activity implements onclicklistener { private button startservice; private button stopservice; @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); startservice = (button) findviewbyid(r.id.start_service); stopservice = (button) findviewbyid(r.id.stop_service); startservice.setonclicklistener(this); stopservice.setonclicklistener(this); } @override public void onclick(view v) { switch (v.getid()) { case r.id.start_service: intent startintent = new intent(this, myservice.class); startservice(startintent); break; case r.id.stop_service: intent stopintent = new intent(this, myservice.class); stopservice(stopintent); break; default: break; } }
项目中的每一个service都必须在androidmanifest.xml中注册才行,所以还需要编辑androidmanifest.xml文件,代码如下所示:
<application android:allowbackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/apptheme" > …… <service android:name="com.example.servicetest.myservice" > </service> </application>
周期分析
oncreate()方法只会在service第一次被创建的时候调用,如果当前service已经被创建过了,不管怎样调用startservice()方法,oncreate()方法都不会再执行。因此你可以再多点击几次start service按钮试一次,每次都只会有onstartcommand()方法中的打印日志。
2.绑定的service
public class localservice extends service { // binder given to clients private final ibinder mbinder = new localbinder(); // random number generator private final random mgenerator = new random(); public class localbinder extends binder { localservice getservice() { // 返回本service的实例到客户端,于是客户端可以调用本service的公开方法 return localservice.this; } } @override public ibinder onbind(intent intent) { return mbinder; } /**客户端所要调用的方法*/ public int getrandomnumber() { return mgenerator.nextint(100); } }
下面是一个绑定到localservice并且在按钮按下时调用getrandomnumber()的actvity的例子:
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(); // 绑定到类localservice的实例 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; } } /** 当按钮按下时调用(在layout文件中定义的button并用android:onclick 属性指定响应到本方法) */ public void onbuttonclick(view v) { if (mbound) { // 调用localservice的一个方法 // 然而,如果这个调用中有挂起操作,那么这个请求应发 // 生在另一个线程来避免拉低activity的性能. int num = mservice.getrandomnumber(); toast.maketext(this, "number: " + num, toast.length_short).show(); } } /** 定义service绑定的回调,传给bindservice() 的*/ 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; } }; }
service的周期函数
1、当采用context.startservice()方法启动服务,与之有关的生命周期方法
oncreate()–> onstart()–> ondestroy()
oncreate()该方法在服务被创建时调用,该方法只会被调用一次,无论调用多少次startservice()或bindservice()方法,服务也只被创建一次。
onstart() 只有采用context.startservice()方法启动服务时才会回调该方法。该方法在服务开始运行时被调用。多次调用startservice()方法尽管不会多次创建服务,但onstart() 方法会被多次调用。
ondestroy()该方法在服务被终止时调用。
2、 当采用context.bindservice()方法启动服务,与之有关的生命周期方法
oncreate()–> onbind() –> onunbind() –> ondestroy()
onbind()只有采用context.bindservice()方法启动服务时才会回调该方法。该方法在调用者与服务绑定时被调用,当调用者与服务已经绑定,多次调用context.bindservice()方法并不会导致该方法被多次调用。
onunbind()只有采用context.bindservice()方法启动服务时才会回调该方法。该方法在调用者与服务解除绑定时被调用。
如果先采用startservice()方法启动服务,然后调用bindservice()方法绑定到服务,再调用unbindservice()方法解除绑定,最后调用bindservice()方法再次绑定到服务,触发的生命周期方法如下:
oncreate()–>onstart()–>onbind()–>onunbind()[重载后的方法需返回true–>onrebind()
那么如果我们既点击了start service按钮,又点击了bind service按钮会怎么样呢?
这个时候你会发现,不管你是单独点击stop service按钮还是unbind service按钮,service都不会被销毁,必要将两个按钮都点击一下,service才会被销毁。也就是说,点击stop service按钮只会让service停止,点击unbind service按钮只会让service和activity解除关联,一个service必须要在既没有和任何activity关联又处理停止状态的时候才会被销毁。
service和thread的区别
主要就是因为service的后台概念。thread我们大家都知道,是用于开启一个子线程,在这里去执行一些耗时操作就不会阻塞主线程的运行。而service我们最初理解的时候,总会觉得它是用来处理一些后台任务的,一些比较耗时的操作也可以放在这里运行,这就会让人产生混淆了。但是,如果我告诉你service其实是运行在主线程里的,所以是没有任何关系的。
service又有何用呢?
其实大家不要把后台和子线程联系在一起就行了,这是两个完全不同的概念。
android的后台就是指,它的运行是完全不依赖ui的。即使activity被销毁,或者程序被关闭,只要进程还在,service就可以继续运行。
比如说一些应用程序,始终需要与服务器之间始终保持着心跳连接,就可以使用service来实现。你可能又会问,前面不是刚刚验证过service是运行在主线程里的么?在这里一直执行着心跳连接,难道就不会阻塞主线程的运行吗?当然会,但是我们可以在service中再创建一个子线程,然后在这里去处理耗时逻辑就没问题了。
使用service创建线程和activity直接创建线程的区别
activity很难对thread进行控制,当activity被销毁之后,就没有任何其它的办法可以再重新获取到之前创建的子线程的实例。而且在一个activity中创建的子线程,另一个activity无法对其进行操作。但是service就不同了,所有的activity都可以与service进行关联,然后可以很方便地操作其中的方法,即使activity被销毁了,之后只要重新与service建立关联,就又能够获取到原有的service中binder的实例。因此,使用service来处理后台任务,activity就可以放心地finish,完全不需要担心无法对后台任务进行控制的情况。
intentservice介绍
intentservice是service的子类,比普通的service增加了额外的功能。
先看service本身存在两个问题:
service不会专门启动一条单独的进程,service与它所在应用位于同一个进程中;
service也不是专门一条新线程,因此不应该在service中直接处理耗时的任务;
二、intentservice特征
会创建独立的worker线程来处理所有的intent请求;
会创建独立的worker线程来处理onhandleintent()方法实现的代码,无需处理多线程问题;
所有请求处理完成后,intentservice会自动停止,无需调用stopself()方法停止service;
为service的onbind()提供默认实现,返回null;
为service的onstartcommand提供默认实现,将请求intent添加到队列中;
实现
public class myintentservice extends intentservice { public myintentservice() { super("myintentservice"); } @override protected void onhandleintent(intent intent) { // intentservice会使用单独的线程来执行该方法的代码 // 该方法内执行耗时任务,比如下载文件,此处只是让线程等待20秒 long endtime = system.currenttimemillis() + 20 * 1000; system.out.println("onstart"); while (system.currenttimemillis() < endtime) { synchronized (this) { try { wait(endtime - system.currenttimemillis()); } catch (interruptedexception e) { e.printstacktrace(); } } } system.out.println("----耗时任务执行完成---"); } }
activity代码
public void startintentservice(view source) { // 创建需要启动的intentservice的intent intent intent = new intent(this, myintentservice.class); startservice(intent); }
以上所述是小编给大家介绍的android service中方法使用详细介绍,希望对大家有所帮助