`
ch_kexin
  • 浏览: 906560 次
  • 性别: Icon_minigender_2
  • 来自: 青岛
社区版块
存档分类
最新评论

基础总结篇之四Service完全解析

 
阅读更多

富貴必從勤苦得,男兒須讀五車書。唐.杜甫《柏學士茅屋》

作为程序员的我们,须知富贵是要通过勤苦努力才能得到的,要想在行业内有所建树,就必须刻苦学习和钻研。

今天我们来讲一下Android中Service的相关内容。

Service在Android中和Activity是属于同一级别上的组件,我们可以将他们认为是两个好哥们,Activity仪表不凡,迷倒万千少女,经常做一些公众人物角色,而Service一副彪悍的长相,但却身强力壮,常常在后台做一些搬运工的力气活,虽然有些累,但大家都不能失去他。

下面我们就围绕Service对其进行全面讲解:

1.Service生命周期

Service生命周期可以从两种启动Service的模式开始讲起,分别是context.startService()和context.bindService()

(1).startService的启动模式下的生命周期:当我们首次使用startService启动一个服务时,系统会实例化一个Service实例,依次调用其onCreate和onStartCommand方法,然后进入运行状态,此后,如果再使用startService启动服务时,不再创建新的服务对象,系统会自动找到刚才创建的Service实例,调用其onStart方法;如果我们想要停掉一个服务,可使用stopService方法,此时onDestroy方法会被调用,需要注意的是,不管前面使用了多个次startService,只需一次stopService,即可停掉服务。

(2).bindService启动模式下的生命周期:在这种模式下,当调用者首次使用bindService绑定一个服务时,系统会实例化一个Service实例,并一次调用其onCreate方法和onBind方法,然后调用者就可以和服务进行交互了,此后,如果再次使用bindService绑定服务,系统不会创建新的Service实例,也不会再调用onBind方法;如果我们需要解除与这个服务的绑定,可使用unbindService方法,此时onUnbind方法和onDestroy方法会被调用。

两种模式有以下几点不同之处:startService模式下调用者与服务无必然联系,即使调用者结束了自己的生命周期,只要没有使用stopService方法停止这个服务,服务仍会运行;通常情况下,bindService模式下服务是与调用者生死与共的,在绑定结束之后,一旦调用者被销毁,服务也就立即终止,就像江湖上的一句话:不求同生,但愿同死。

值得一提的是,以前我们在使用startService启动服务时都是习惯重写onStart方法,在Android2.0时系统引进了onStartCommand方法取代onStart方法,为了兼容以前的程序,在onStartCommand方法中其实调用了onStart方法,不过我们最好是重写onStartCommand方法。

以上两种模式的流程如下图所示:

下面我们就结合实例来演示一下这两种模式的生命周期过程。我们新建一个名为service的项目,然后创建一个MyService的服务类,代码如下:

 

[java] view plain copy
 
  1. package com.scott.service;  
  2.   
  3. import android.app.Service;  
  4. import android.content.Intent;  
  5. import android.os.IBinder;  
  6. import android.util.Log;  
  7.   
  8. public class MyService extends Service {  
  9.   
  10.     private static final String TAG = "MyService";  
  11.       
  12.     @Override  
  13.     public void onCreate() {  
  14.         super.onCreate();  
  15.         Log.i(TAG, "onCreate called.");  
  16.     }  
  17.       
  18.     @Override  
  19.     public int onStartCommand(Intent intent, int flags, int startId) {  
  20.         Log.i(TAG, "onStartCommand called.");  
  21.         return super.onStartCommand(intent, flags, startId);  
  22.     }  
  23.       
  24.     @Override  
  25.     public void onStart(Intent intent, int startId) {  
  26.         super.onStart(intent, startId);  
  27.         Log.i(TAG, "onStart called.");  
  28.     }  
  29.       
  30.     @Override  
  31.     public IBinder onBind(Intent intent) {  
  32.         Log.i(TAG, "onBind called.");  
  33.         return null;  
  34.     }  
  35.       
  36.     @Override  
  37.     public boolean onUnbind(Intent intent) {  
  38.         Log.i(TAG, "onUnbind called.");  
  39.         return super.onUnbind(intent);  
  40.     }  
  41.       
  42.     @Override  
  43.     public void onDestroy() {  
  44.         super.onDestroy();  
  45.         Log.i(TAG, "onDestroy called.");  
  46.     }  
  47. }  

然后再AndroidManifest.xml中配置服务信息,不然这个服务就不会生效,配置如下:

 

 

[html] view plain copy
 
  1. <service android:name=".MyService">  
  2.             <intent-filter>  
  3.                  <action android:name="android.intent.action.MyService" />  
  4.                  <category android:name="android.intent.category.DEFAULT" />  
  5.             </intent-filter>  
  6.         </service>  

如果服务只是在本应用中使用,大可以去掉<intent-filter>属性。

 

服务搭建完成之后,我们就来关注一下调用者MainActivity,它很简单,只有两个按钮,一个是启动服务,另一个是停止服务,我们来看一下他们的点击事件:

 

[java] view plain copy
 
  1. /** 
  2.  * 启动服务 
  3.  * @param view 
  4.  */  
  5. public void start(View view) {  
  6.     Intent intent = new Intent(this, MyService.class);  
  7.     startService(intent);  
  8. }  
  9.   
  10. /** 
  11.  * 停止服务 
  12.  * @param view 
  13.  */  
  14. public void stop(View view) {  
  15.     Intent intent = new Intent(this, MyService.class);  
  16.     stopService(intent);  
  17. }  

接下来我们就先点击一次启动按钮,看看都发生了些什么。日志打印结果如下:

 

当然我们觉得还不过瘾,再点击一次,我们会发现结果略有不同:

我们看到第二次点击时onCreate方法就不再被调用了,而是直接调用了onStartCommand方法(onStartCommand中又调用了onStart方法)。我们选择“Settings->Application s->Running services”就会发现我们刚刚启动的服务:

然后我们点击停止按钮,试图停止服务,我们发现如下现象:

我们会发现onDestroy方法被调用了,此时服务就停止运行了。我们再次查看“Running services”,就会发现MyService这个服务已全无踪迹。

在这个过程中,onBind方法和onUnbind方法始终没被调用,我们下面就让这两位show一下自己。

我们修改一下MainActivity的代码,使其可以可以以bindService的方式启动一个服务,代码如下:

 

[java] view plain copy
 
  1. private ServiceConnection conn = new ServiceConnection() {  
  2.       
  3.     @Override  
  4.     public void onServiceConnected(ComponentName name, IBinder service) {  
  5.         //connected  
  6.         Log.i(TAG, "onServiceConnected called.");  
  7.     }  
  8.   
  9.     /** 
  10.      *  Called when a connection to the Service has been lost. 
  11.      *  This typically happens when the process hosting the service has crashed or been killed. 
  12.      *  This does not remove the ServiceConnection itself. 
  13.      *  this binding to the service will remain active, 
  14.      *  and you will receive a call to onServiceConnected when the Service is next running. 
  15.      */  
  16.     @Override  
  17.     public void onServiceDisconnected(ComponentName name) {  
  18.     }  
  19. };  
  20.   
  21. /** 
  22.  * 绑定服务 
  23.  * @param view 
  24.  */  
  25. public void bind(View view) {  
  26.     Intent intent = new Intent(this, MyService.class);  
  27.     bindService(intent, conn, Context.BIND_AUTO_CREATE);  
  28. }  
  29.   
  30. /** 
  31.  * 解除绑定 
  32.  * @param view 
  33.  */  
  34. public void unbind(View view) {  
  35.     unbindService(conn);  
  36. }  

在使用bindService绑定服务时,我们需要一个ServiceConnection代表与服务的连接,它只有两个方法,onServiceConnected和onServiceDisconnected,前者是在操作者在连接一个服务成功时被调用,而后者是在服务崩溃或被杀死导致的连接中断时被调用,而如果我们自己解除绑定时则不会被调用,所以我们这里只研究onServiceConnected这个方法。

 

看样子是可以去绑定一个服务了,其实还不行,因为我们前面服务中的onBind方法返回值为null,这样是不行的,要想实现绑定操作,必须返回一个实现了IBinder接口类型的实例,该接口描述了与远程对象进行交互的抽象协议,有了它我们才能与服务进行交互。我们于是有了这样的代码:

 

[java] view plain copy
 
  1. @Override  
  2. public IBinder onBind(Intent intent) {  
  3.     Log.i(TAG, "onBind called.");  
  4.     return new Binder() {};  
  5. }  

我们返回了一个Binder的实例,而这个Binder恰恰是实现了IBinder接口,所以这样就可以实现绑定服务的操作了,一起来演示一下。

 

先点击一下绑定按钮,我们会发现在MainActivity中打印日志如下:

似的,onServiceConnected方法被调用了,看来绑定连接已经成功了,看看MyService如何:

onCreate方法和onBind方法被调用了,此时服务已进入运行阶段,如果再次点击绑定按钮,onCreate和onBinder并不会再次被调用,这个过程中它们仅被调用一次。

然后点击解除绑定按钮,我们会发现MyService打印如下:

可以看到onUnbind方法和onDestroy方法被调用了,此时MyService已被销毁,整个生命周期结束。

另一方面,当我们退出MainActivity时,服务也会随之而结束,从这一点上看,MyService可以说是誓死追随着MainActivity。

需要注意的是,在连接中断状态再去做解除绑定操作会引起一个异常,在MainActivity销毁之前没有进行解除绑定也会导致后台出现异常信息,此时我们就要想办法确保不会出现此类情况,可以这样做:

 

[java] view plain copy
 
  1. private boolean binded;  
  2.   
  3. @Override  
  4. public void onServiceConnected(ComponentName name, IBinder service) {  
  5.     binded = true;  
  6. }  
  7.   
  8. /** 
  9.  * 解除绑定 
  10.  * @param view 
  11.  */  
  12. public void unbind(View view) {  
  13.     unbindService();  
  14. }  
  15.   
  16. @Override  
  17. protected void onDestroy() {  
  18.     super.onDestroy();  
  19.     unbindService();  
  20. }  
  21.   
  22. /** 
  23.  * 解除服务绑定 
  24.  */  
  25. private void unbindService() {  
  26.     if (binded) {  
  27.         unbindService(conn);  
  28.         binded = false;  
  29.     }  
  30. }  

以上就是bindService的生命周期,正如我们上面讲的一样,使用bindService启动服务后调用者和服务绑定到了一起,当调用者被销毁,服务也立即结终止。

通常情况下是这样的,不过也有特殊情况。当startService和bindService在同一场合下使用时,就会出现稍微不同的现象。

如果我们先以startService方式启动服务,然后再用bindService绑定到这个服务,之后使用unbindService解除绑定,此时服务并不会因此而终止,而是继续运行,直到我们使用stopService来停止这个服务。下面我们再修改一下代码以验证这个过程。MyService保持不变,我们只需修改一下MainActivity。MainActivity最新代码如下:

 

[java] view plain copy
 
  1. package com.scott.service;  
  2.   
  3. import android.app.Activity;  
  4. import android.content.ComponentName;  
  5. import android.content.Context;  
  6. import android.content.Intent;  
  7. import android.content.ServiceConnection;  
  8. import android.os.Bundle;  
  9. import android.os.IBinder;  
  10. import android.util.Log;  
  11. import android.view.View;  
  12.   
  13. public class MainActivity extends Activity {  
  14.       
  15.     private static final String TAG = "MainActivity";  
  16.       
  17.     @Override  
  18.     public void onCreate(Bundle savedInstanceState) {  
  19.         super.onCreate(savedInstanceState);  
  20.         setContentView(R.layout.main);  
  21.     }  
  22.       
  23.     private ServiceConnection conn = new ServiceConnection() {  
  24.           
  25.         @Override  
  26.         public void onServiceConnected(ComponentName name, IBinder service) {  
  27.             Log.i(TAG, "onServiceConnected called.");  
  28.         }  
  29.           
  30.         @Override  
  31.         public void onServiceDisconnected(ComponentName name) {  
  32.         }  
  33.     };  
  34.       
  35.     /** 
  36.      * 启动服务 
  37.      * @param view 
  38.      */  
  39.     public void start(View view) {  
  40.         Intent intent = new Intent(this, MyService.class);  
  41.         startService(intent);  
  42.     }  
  43.       
  44.     /** 
  45.      * 绑定服务 
  46.      * @param view 
  47.      */  
  48.     public void bind(View view) {  
  49.         Intent intent = new Intent(this, MyService.class);  
  50.         bindService(intent, conn, Context.BIND_AUTO_CREATE);  
  51.     }  
  52.       
  53.     /** 
  54.      * 解除绑定 
  55.      * @param view 
  56.      */  
  57.     public void unbind(View view) {  
  58.         unbindService(conn);  
  59.     }  
  60.       
  61.     /** 
  62.      * 停止服务 
  63.      * @param view 
  64.      */  
  65.     public void stop(View view) {  
  66.         Intent intent = new Intent(this, MyService.class);  
  67.         stopService(intent);  
  68.     }  
  69. }  

在MainActivity中包含了四个按钮事件,分别是startService、bindService、unbindService和stopService,我们逐一地按下,看看都发生了什么。

 

首先按下启动服务的按钮,MyService打印如下:

恩,意料之中。然后我们再按下绑定服务的按钮,MyService打印如下:

此时,只有onBind被调用,之后两者就绑定成功。我们再按下解除绑定的按钮,MyService打印如下:

此时,onUnbind方法方法被调用,注意,此时MyService并没有因解除绑定而终止,而是继续运行。也许我们心里会问,如果多次按下绑定服务的按钮或重复以上两个步骤,结果如何呢?答案是onBind和onUnbind都不会再被调用了。看不到onBind被调用,是不是没有绑定成功啊,我们来看一下MainActivity打印信息:

重复按下绑定按钮,几次都绑定成功了。最后我们按下停止服务的按钮,MyService打印如下:

此时,onDestroy被调用了,此时MyService停止了运行,整个生命周期结束。

以上就是关于MyService生命周期的讲解,下面我们来介绍一下如何与服务进行通信。与服务之间的通信可以分为两种,进程内的通信和进程间的通信,前者调用者和服务在同一应用进程内,而后者是分布在不同应用进程中的。

2.进程内与服务通信

进程内与服务通信实际上就是通过bindService的方式与服务绑定,获取到通信中介Binder实例,然后通过调用这个实例的方法,完成对服务的各种操作。我们上面也介绍了不少关于bindService的内容,下面我们就针对实际需求对代码做改动。首先是MyService,代码如下:

 

[java] view plain copy
 
  1. package com.scott.service;  
  2.   
  3. import android.app.Service;  
  4. import android.content.Intent;  
  5. import android.os.Binder;  
  6. import android.os.IBinder;  
  7. import android.util.Log;  
  8.   
  9. public class MyService extends Service {  
  10.   
  11.     private static final String TAG = "MyService";  
  12.       
  13.     @Override  
  14.     public IBinder onBind(Intent intent) {  
  15.         Log.i(TAG, "onBind called.");  
  16.         return new MyBinder();  
  17.     }  
  18.       
  19.     /** 
  20.      * 绑定对象 
  21.      * @author user 
  22.      * 
  23.      */  
  24.     public class MyBinder extends Binder {  
  25.           
  26.         /** 
  27.          * 问候 
  28.          * @param name 
  29.          */  
  30.         public void greet(String name) {  
  31.             Log.i(TAG, "hello, " + name);  
  32.         }  
  33.     }  
  34. }  

我们创建了一个MyBinder的内部类,定义了一个greet方法,在onBind方法中就将这个MyBinder的实例返回,只要调用者获取到这个实例,就可以像拿着游戏手柄一样对服务进行操作。我们来看一下调用者的代码吧,MainActivity代码如下:

 

 

[java] view plain copy
 
  1. package com.scott.service;  
  2.   
  3. import android.app.Activity;  
  4. import android.content.ComponentName;  
  5. import android.content.Context;  
  6. import android.content.Intent;  
  7. import android.content.ServiceConnection;  
  8. import android.os.Bundle;  
  9. import android.os.IBinder;  
  10. import android.view.View;  
  11.   
  12. public class MainActivity extends Activity {  
  13.       
  14.     /** 
  15.      * 绑定对象实例 
  16.      */  
  17.     private MyService.MyBinder binder;  
  18.       
  19.     @Override  
  20.     public void onCreate(Bundle savedInstanceState) {  
  21.         super.onCreate(savedInstanceState);  
  22.         setContentView(R.layout.main);  
  23.     }  
  24.       
  25.     private ServiceConnection conn = new ServiceConnection() {  
  26.           
  27.         @Override  
  28.         public void onServiceConnected(ComponentName name, IBinder service) {  
  29.             binder = (MyService.MyBinder) service;  //获取其实例  
  30.             binder.greet("scott");                  //调用其方法  
  31.         }  
  32.           
  33.         @Override  
  34.         public void onServiceDisconnected(ComponentName name) {  
  35.         }  
  36.     };  
  37.       
  38.     /** 
  39.      * 绑定服务 
  40.      * @param view 
  41.      */  
  42.     public void bind(View view) {  
  43.         Intent intent = new Intent(this, MyService.class);  
  44.         bindService(intent, conn, Context.BIND_AUTO_CREATE);  
  45.     }  
  46.       
  47.     /** 
  48.      * 解除绑定 
  49.      * @param view 
  50.      */  
  51.     public void unbind(View view) {  
  52.         unbindService(conn);  
  53.     }  
  54. }  

在上面的代码中,我们是在绑定服务成功时将IBinder类型的service参数强转为MyService.MyBinder类型,获取绑定中介实例,然后调用其greet方法。

 

操作一下,看看效果如何。先点击绑定服务的按钮,MyService打印如下:

需要注意的是,与服务绑定是一个异步的过程,也就是说,在这一刻我们绑定服务,下一刻我们去操作binder对象,也许它还为null,这就容易引起空指针异常,正确的做法是把这些操作放到绑定成功之后,确保万无一失。

以上就是进程内通信的内容。

分享到:
评论

相关推荐

    Android中Service完全解析(上)

    在Android应用开发中,Service是四大组件之一,它在后台执行长时间运行的...通过阅读"Android中Service完全解析(上)"这篇博客和对应的"MyService"源码,可以深入了解Service的运作机制,为实际项目开发打下坚实基础。

    Android Service深入解析Demo

    这篇博客"Android Service深入解析Demo"通过实例深入讲解了Service的相关知识,下面将详细阐述Service的核心概念、生命周期、启动与绑定方式以及如何在实践中应用。 1. **Service核心概念** Service是Android系统...

    iOS开发网络篇之Web Service和XML数据解析

    在iPhone和后台系统的通信中,使用Web Service获取服务器数据上最常见的一种形式。 而在Web Service通信中,数据交换格式通常上使用XML数据,XML数据也是软件开发中普遍存在的一种格式, 因此XML解析也就成为项目...

    Android Service完全解析,关于服务你所需知道的一切(上).html

    Android Service完全解析,关于服务你所需知道的一切(上).html

    Android Service全面解析

    本篇文章将全面解析Android Service的相关知识点,包括Service的生命周期、启动与绑定方式、交互机制以及注意事项。 首先,Service的生命周期主要由四个方法构成:onCreate(), onStartCommand(), onBind(), 和...

    web service 解析工具

    自己写的一个web service解析工具 输入url能解析出web service的方法和参数信息

    EMC存储使用Unisphere Service Manager解析存储原厂日志手册.docx

    安装完成后,通过USM工具解析存储收集的原厂日志,步骤包括:启动USM,选择View System Configuration,加载从存储设备下载的_data.zip日志文件,选择日志格式进行解析,查看解析结果,包括存储信息、磁盘信息、LUN...

    ServiceNow 基础手册

    ServiceNow平台的基础手册涵盖了该平台的基本使用方法,包括如何导航、管理记录以及搜索等操作。以下是对手册内容的详细解读。 首先,ServiceNow用户界面是与应用程序和信息交互的主要方式。ServiceNow的用户界面...

    Web Service详细解析及使用方法

    总结来说,Web Service是现代分布式系统中的重要组成部分,XFIRE、AXIS和CXF等框架为开发者提供了便利,使得构建和消费Web Service变得更加容易。理解这些工具的特点和使用方法,对于提升开发效率和系统互操作性至关...

    SAP web Service 基础教程

    SAP Web Service 基础教程 SAP Web Service 是一种基于 SOAP 协议和 WSDL 语言的 Web 服务实现方案,在 SAP 系统中,开发和消费 SOAP 方式的 Web Service 十分方便。本教程将详细介绍 SAP Web Service 的基础知识...

    Google Web Service Java解析

    总结,通过Java实现Google Web Service请求,主要涉及到URL构建、网络请求和数据解析三个关键步骤。利用Google提供的Java客户端库可以简化这个过程,提高开发效率。不过,实际开发时还需要关注错误处理、权限验证、...

    android基础知识05:四大组件之service 02:远程调用实例程序

    在"android基础知识05:四大组件之service 02:远程调用实例程序"中,我们探讨的是如何在不同的应用之间通过AIDL(Android Interface Definition Language)进行远程服务调用。AIDL是Android提供的一种机制,用于在...

    android service总结文档

    一篇对于android service的详细总结

    android基础知识总结

    #### 四、Service组件解析 Service是Android四大组件之一,用于执行长时间运行的操作,如音乐播放、后台数据同步等,不提供用户界面。Service有两种启动方式:startService()和bindService()。前者用于执行一次性的...

    一切用户服务service基础实例

    本篇将深入探讨"一切用户服务service基础实例",包括Service的生命周期及其相关的实践示例。 一、Service基础知识 Service主要用于执行那些不需要用户交互但需要在后台持续运行的任务,如播放音乐、定时任务或者...

    Android开发四大组件之Service应用总结Demo

    service的启动,停止,绑定,取消绑定,以及IntentService的生命周期走向测试和IntentService与访问者信息通信过程,不清楚之处请参阅我的博客《Android开发四大组件之Service总结》

    《实战Delphi6/Kylix2/SOAP/Web Service程序设计篇》(

    在《实战Delphi6/Kylix2/SOAP/Web Service程序设计篇》这本书中,作者李维精心编撰了一套系统而全面的教程,针对的是Delphi6和Kylix2这两个经典的Visual Basic derivative (VBD) 编程环境,尤其是针对SOAP(Simple ...

    service全面解析

    在Android系统中,Service是四大组件之一,它主要用于在后台执行长时间运行的操作,而不提供用户界面。Service组件在很多场景下被广泛使用,比如音乐播放、定时任务、网络通信等。下面将对Service进行全面解析。 **...

    Android中Service的生命周期解析.pdf

    本篇文章将深入解析Android Service的生命周期。 1. Service的定义 Service是继承自ContextWrapper类的,其父类ContextWrapper又继承自Context类。Service是Android应用中的一个特殊类,用于执行那些需要在后台持续...

    systemd service Ordering cycle found无法启动对应systemd service问题解析脚本

    systemd service Ordering cycle found无法启动对应systemd service问题解析脚本: /usr/bin/python3 dot_find_cycles.py systemd_analyze_dot_file --only-shortest systemd service bootup sorted analyze

Global site tag (gtag.js) - Google Analytics