【安卓笔记】全面解析Service组件

来源:互联网 发布:调节屏幕亮度软件 编辑:程序博客网 时间:2024/06/05 06:50

service,android四大组件之一,是一个长期运行在应用后台的android组件,它没有与用户交互的界面。

service的特点是:
1.长期运行在后台;
2.其他组件可以通过绑定操作与service进行交互;
3.默认运行在UI线程上;
4.无用户界面。
下面总结了service常见的知识点,帮助大家理解和复习service。

-------------------------------------------------------------

目录:

service分类简介

一. 如何创建一个service?  

二.如何启动/关闭service? 

三.如何绑定/解绑service?   

四.如何创建前台service?     

五.service的生命周期?   

六.如何让service与activity进行交互?     

七.使用AIDL绑定远程服务 

八.service与thread的区别?

------------------------------------------------------------

service分类简介:                                                                                                       

     
service按照类型分为前台服务后台服务
前台服务有个很明显的标志就是在任务栏有个通知(notification),就像天天动听后台播放音乐那样。而后台服务在通知栏上是没有任何显示的,只有我们去应用程序管理器中才能看到它,默认情况下我们创建的都是后台服务,比如日期同步,邮件同步等操作。之所以有前台服务,除了给用户友好的提示之外还有一个用处,那就是提高服务的优先级别,让系统不敢随便的kill掉它。众所周知,android系统是将进程分为五个级别(前台进程,可见进程,服务进程,后台进程,空进程)的,级别低的进程会在系统内存告急的时候优先被kill,而前台进程(foreground process)优先级最高,所以基本不可能被干掉。前台服务保证了服务的持久性。

service其实又可分为本地服务远程服务
本地服务中服务是依附在主线程上的(main thread),节省了资源,但是缺点是当主进程被kill掉的时候服务也会挂掉。而远程服务会单独创建一个进程,当主进程销毁之后service仍然能够运行。但是这种方式需要用到AIDL(android interface description language),比较麻烦,而且还很耗资源。其实总体而言,远程服务还是比较少见的,所以能用本地服务就用本地服务吧!

---------------------------------------------------------------------------

一. 如何创建一个service?                                                                                             


在介绍如何创建service之前,希望大家明确一点,那就是用户体验问题,因为service是运行在UI线程上的,我们一定不可以在这里处理耗时操作,如果有耗时操作,务必开子线程或者使用AsyncTask。附上文档说明:

1.编写一个类继承android.app.Service抽象类
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. import android.app.Service;  
  2. import android.content.Intent;  
  3. import android.os.IBinder;  
  4. public class ServiceExample extends Service  
  5. {  
  6.     @Override  
  7.     public IBinder onBind(Intent intent)  
  8.     {  
  9.         return null;  
  10.     }  
  11.       
  12. }  
其中,onBind是抽象方法,我们必须实现。另外这个类还有一些生命周期方法如:onCreate,onDestroy,onStartCommand等。与onBind绑定方法对应的还有onUbind(解绑)方法。
下面逐一介绍各个方法:
onCreate:一看就知道是初始化的方法,当系统启动服务或者绑定服务时会调用此方法。注意,这个方法只会被调用一次,适合做初始化工作。
onStartCommand:每次在activity中调用startService时,都会调用这个方法,但是绑定服务(bindService)时并不会调用这个方法。
    参数:
        Intent intent:即调用startService方法中传递进来的intent。
        int flags:启动服务的请求所携带的附加数据。
        int startID:一个唯一的整型数代表了当前的开启请求。
onDestroy:没什么好说的,这个方法用于销毁sevice。通常在这个方法中关闭资源,比如关闭线程,取消注册广播接收者等等。当在activity中调用stopService或者unBindService时都会调用这个方法。
onBind:当绑定服务(bindService)时会调用此方法。这个方法比较有意思,可以看到它的返回值是IBinder接口,这个接口是用来和与之绑定的组件进行通信的。一旦绑定了服务,这个IBinder便会返回给绑定组件,在该组件中我们就能通过调用IBinder中的方法间接与service进行通信了!当然这涉及了另一个类:ServiceConnection,这是一个服务连接器,关于这个类,我们在下一部分再介绍。
onUnBind:顾名思义,当组件与service取消绑定时,会调用这个方法。
注:跟activity不一样,service生命周期方法中不需调用父类方法。
   2.在清单文件AndroidManifest.xml中配置service
    在application节点下创建一个service节点:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <service android:name="com.example.xxx"></service>  
还有一些常见选项:

android:name:服务类名

android:label:服务的标签,如果此项不设置,那么默认显示的服务名则为类名

android:icon:服务的图标

android:permission:申明此服务的权限,这意味着只有提供了该权限的应用才能控制或连接此服务

android:process:表示该服务是否运行在另外一个进程,如果设置了此项,那么将会在包名后面加上这段字符串表示另一进程的名字(即远程服务)

android:enabled:如果此项设置为 true,那么 Service 将会默认被系统启动,不设置默认此项为 false

android:exported:表示该服务是否能够被其他应用程序所控制或连接,不设置默认此项为 false

具体的使用案例我放在了后面,请继续向下看。


二.如何启动/关闭service?                                                                                             


 其实在上面已经多次提到启动服务了,其实启动/关闭service非常简单,两个api搞定: 
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. startService(Intent intent)//启动服务  
  2. stopService(Intent intent)//关闭服务  
ntent用于指定我们要开启的服务,可以用显示意图也可以用隐式意图。显式意图很简单,直接指明开启的服务的类名即可,像这样:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. Intent intent1 = new Intent(this,MyService.class);  
如果使用隐式意图,首先我们需要在配置service时增加一个意图过滤器:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <service android:name="com.example.service.PayService">     
  2.         <intent-filter>  
  3.                <action android:name="com.example.pay"/>  
  4.            </intent-filter>              
  5. </service>  
然后我们开启服务的时候,也指定action:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. Intent intent = new Intent("com.example.pay");  
关闭服务同理,此处不再敖述。

三.如何绑定/解绑service?                                                                                               


这个比启动/关闭service稍微复杂点,关键是理解流程,api都是很简单的。下面先从api开始介绍:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public boolean bindService(Intent service, ServiceConnection conn, int flags)//绑定  
  2. public void unbindService(ServiceConnection conn)//解绑  
bindService方法接收三个参数:
Intent service:指定要绑定的服务,跟startService的参数相同,不再介绍。
int flags:绑定选项,这个参数指定绑定的一些选项,常用的有BIND_AUTO_CREATE(这个参数很吊,当调用bindService时,如果没有开启服务,将会自动开启服务),BIND_DEBUG_UNBIND等
ServiceConnection conn:服务连接器.这个对象用于和service进行通信,之前我们在创建service时有个必须实现的方法叫onBind,这个方法返回的IBinder对象将会被此连接器获取,进而此连接器通过调用IBinder的方法与service交互。
这是一个接口类型,我们可以看看接口声明:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public interface ServiceConnection {  
  2.     public void onServiceConnected(ComponentName name, IBinder service);  
  3.     public void onServiceDisconnected(ComponentName name);  
  4. }  
此接口有两个方法,从名字就可以看出来,一个是在与服务建立连接的时候调用,另一个是与服务失去连接的时候调用。其中onServiceConnected方法的第二个参数就是之前onBind返回的IBinder的引用!所以onBind方法如果返回null此处就获取不到IBinder引用了。我们将在后面介绍activity与service进行交互,具体使用示例请继续往下看。
unbindService方法接收的参数也是这个连接器,需要注意的是两个连接器必须是同一个,故我们通常将连接器设为全局的变量。另外还有一个需要注意的点,服务只能被解除绑定一次,如果第二次解除绑定,将会抛出异常。但是为了确保service解绑,通常会在activity的onDestroy中解绑service,为了不抛异常,我们有两种解决方案。一是定义一个标志位,表示当前是否已经解除绑定,这样只要判断标志位即可。另外一种方案是将unbindService方法try起来:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. try  
  2.    {  
  3.      if(conn != null)  
  4.          unbindService(conn);  
  5.     } catch (Exception e)  
  6.      {  
  7.       }  

  

四.如何创建前台service?                                              


在文章一开始我们介绍srvice分类的时候就已经说了前台service,故这里不再介绍前台service,咱们直接创建一个前台service。创建前台service需要调用一个api叫startForeground(),但是这个方法是在2.0之后才有的,在之前的版本,我们使用setForeground()方法。文档里面有如何兼容旧版本的demo程序,用到了反射。在这里为了方便起见,直接使用新版api了:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public final void startForeground(int id, Notification notification)  
  2. public final void stopForeground(boolean removeNotification)  
  首先新建一个android工程,然后创建一个类继承service:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package com.example.foregroundservicedemo.service;  
  2. import android.app.Notification;  
  3. import android.app.PendingIntent;  
  4. import android.app.Service;  
  5. import android.content.Intent;  
  6. import android.os.IBinder;  
  7. import com.example.foregroundservicedemo.MainActivity;  
  8. import com.example.foregroundservicedemo.R;  
  9. public class MyService extends Service  
  10. {  
  11.     @Override  
  12.     public IBinder onBind(Intent intent)  
  13.     {  
  14.         return null;  
  15.     }  
  16.       
  17.     @Override  
  18.     public void onCreate()  
  19.     {  
  20.         Notification notification = new Notification(R.drawable.notification,  "您有一条新通知", System.currentTimeMillis());   
  21.         Intent notificationIntent = new Intent(this, MainActivity.class);    
  22.         PendingIntent pendingIntent = PendingIntent.getActivity(this0,notificationIntent, 0);    
  23.         notification.setLatestEventInfo(this"通知的标题""通知的内容",pendingIntent);     
  24.         
  25.         startForeground(1, notification); //开启前台服务   
  26.     }  
  27.     @Override  
  28.     public void onDestroy()  
  29.     {  
  30.         stopForeground(true);//停止前台服务,并销毁通知  
  31.     }  
  32. }  
可以看到,我们在onCreate方法中创建了一个通知,然后调用startForefround方法使当前service以前台方式运行,在onDestroy方法中停止前台服务,并销毁通知。
然后别忘了在清单文件中配置:
[html] view plaincopy在CODE上查看代码片派生到我的代码片
  1. <service android:name="com.example.foregroundservicedemo.service.MyService"></service>  
最后,我们编写一个activity,添加两个按钮分别用于启动/停止服务,代码很简单,下面只贴出onclick方法:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. public void onClick(View v)  
  2.     {  
  3.         switch (v.getId())  
  4.         {  
  5.         case R.id.but_start:  
  6.             Intent intent = new Intent(this,MyService.class);  
  7.             this.startService(intent);  
  8.             break;  
  9.         case R.id.but_stop:  
  10.             Intent intent2 = new Intent(this,MyService.class);  
  11.             this.stopService(intent2);  
  12.             break;  
  13.         }  
  14. }  
好了,大功告成,下面测试下:
主界面:

开启服务:

五.service的生命周期?                                               


上面介绍了好几种方式开启服务,下面总结下:
1.使用startService方式开启;
2.使用bindService方式开启;
其实还有第三种:
3.既startService又bindService。
那这三种方式开启服务的生命周期如何呢?我们先看下图:
从这个图可以看到前两种启动方式的生命周期,总结如下:

(1). 被启动的服务的生命周期:如果一个Service被某个Activity 调用 Context.startService 方法启动,那么不管是否有Activity使用bindService绑定或unbindService解除绑定到该Service,该Service都在后台运行。如果一个Service被startService 方法多次启动,那么onCreate方法只会调用一次,onStart将会被调用多次(对应调用startService的次数),并且系统只会创建Service的一个实例(因此你应该知道只需要一次stopService调用)。该Service将会一直在后台运行,而不管对应程序的Activity是否在运行,直到被调用stopService,或自身的stopSelf方法。当然如果系统资源不足,android系统也可能结束服务。

(2). 被绑定的服务的生命周期:如果一个Service被某个Activity 调用 Context.bindService 方法绑定启动,不管调用 bindService 调用几次,onCreate方法都只会调用一次,同时onStart方法始终不会被调用。当连接建立之后,Service将会一直运行,除非调用Context.unbindService 断开连接或者之前调用bindService 的 Context 不存在了(如Activity被finish的时候),系统将会自动停止Service,对应onDestroy将被调用。

 至于第三种比较特殊了,我们也来总结下它的生命周期:
        3). 被启动又被绑定的服务的生命周期如果一个Service又被启动又被绑定,则该Service将会           一直在后台运行。并且不管如何调用,onCreate始终只会调用一次,对应startService调用多少次,  Service的onStart便会调用多少次。只调用unbindService将不会停止Service,只调用stopService也不会停止service,只有同时调两个方法才能销毁service。

光这么总结大家可能觉得比较生硬,其实我们可以采用打LOG的方式研究其生命周期,新建一个service如下,清单文件这里就不贴了:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package com.example.servicedemo2.myservice;  
  2.   
  3. import com.example.servicedemo2.binder.IService;  
  4.   
  5. import android.app.Service;  
  6. import android.content.Intent;  
  7. import android.content.ServiceConnection;  
  8. import android.os.Binder;  
  9. import android.os.IBinder;  
  10. import android.util.Log;  
  11. import android.widget.Toast;  
  12.   
  13. public class MyService extends Service  
  14. {  
  15.     private static final String TAG = "MyService";  
  16.   
  17.     @Override  
  18.     public void onCreate()  
  19.     {  
  20.         Log.i(TAG,"服务被创建");  
  21.     }  
  22.   
  23.     @Override  
  24.     public IBinder onBind(Intent intent)  
  25.     {  
  26.         Log.i(TAG,"服务被绑定");  
  27.         return new MyBinder();  
  28.     }  
  29.     @Override  
  30.     public int onStartCommand(Intent intent, int flags, int startId)  
  31.     {  
  32.         Log.i(TAG,"onstartCommand方法调用,startId = "+startId);  
  33.         return super.onStartCommand(intent, flags, startId);  
  34.     }  
  35.     @Override  
  36.     public void onDestroy()  
  37.     {  
  38.         Log.i(TAG,"服务被销毁");  
  39.     }  
  40.     private class MyBinder extends Binder implements IService  
  41.     {  
  42.         @Override  
  43.         public void func()  
  44.         {  
  45.             myServiceFunc();//通过一个binder将服务中的方法暴露给外界  
  46.         }  
  47.     }  
  48.     /** 
  49.      * 服务中的私有的方法 
  50.      */  
  51.     private void myServiceFunc()  
  52.     {  
  53.         Toast.makeText(getApplicationContext(),"成功调用了服务中的方法..."0).show();  
  54.     }  
  55.   
  56.     @Override  
  57.     public boolean onUnbind(Intent intent)  
  58.     {  
  59.         Log.i(TAG,"服务被解除绑定...");  
  60.         return super.onUnbind(intent);  
  61.     }  
  62. }  
测试的activity,布局也不贴了。
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package com.example.servicedemo2;  
  2.   
  3. import com.example.servicedemo2.binder.IService;  
  4. import com.example.servicedemo2.myservice.MyService;  
  5.   
  6. import android.app.Activity;  
  7. import android.app.Service;  
  8. import android.content.ComponentName;  
  9. import android.content.Intent;  
  10. import android.content.ServiceConnection;  
  11. import android.os.Bundle;  
  12. import android.os.IBinder;  
  13. import android.util.Log;  
  14. import android.view.View;  
  15. import android.view.View.OnClickListener;  
  16. import android.widget.Button;  
  17. import android.widget.Toast;  
  18.   
  19. /** 
  20.  * @author Rowand jj 
  21.  * 
  22.  */  
  23. public class MainActivity extends Activity implements OnClickListener  
  24. {  
  25.     protected static final String TAG = "MainActivity";  
  26.     private Button but_start,but_stop,but_bind,but_unbind,but_func;  
  27.     private IService s = null;  
  28.     private ServiceConnection conn = null;  
  29.     @Override  
  30.     protected void onCreate(Bundle savedInstanceState)  
  31.     {  
  32.         super.onCreate(savedInstanceState);  
  33.         setContentView(R.layout.activity_main);  
  34.         but_start = (Button) findViewById(R.id.but_start);  
  35.         but_stop = (Button) findViewById(R.id.but_stop);  
  36.         but_bind = (Button) findViewById(R.id.but_bind);  
  37.         but_unbind = (Button) findViewById(R.id.but_unbind);  
  38.         but_func = (Button) findViewById(R.id.but_func);  
  39.           
  40.         but_start.setOnClickListener(this);  
  41.         but_stop.setOnClickListener(this);  
  42.         but_bind.setOnClickListener(this);  
  43.         but_unbind.setOnClickListener(this);  
  44.         but_func.setOnClickListener(this);  
  45.     }  
  46.     @Override  
  47.     public void onClick(View v)  
  48.     {  
  49.         switch (v.getId())  
  50.         {  
  51.         case R.id.but_start:  
  52.             Intent intent1 = new Intent(this,MyService.class);  
  53.             this.startService(intent1);  
  54.             break;  
  55.         case R.id.but_stop:  
  56.             Intent intent2 = new Intent(this,MyService.class);  
  57.             this.stopService(intent2);  
  58.             break;  
  59.         case R.id.but_bind:  
  60.             Intent intent3 = new Intent(this,MyService.class);  
  61.             conn = new ServiceConnection()  
  62.             {  
  63.                 @Override  
  64.                 public void onServiceDisconnected(ComponentName name)  
  65.                 {  
  66.                     Log.i(TAG,"onServiceDisconnected运行了...");  
  67.                 }  
  68.                   
  69.                 @Override  
  70.                 public void onServiceConnected(ComponentName name, IBinder service)  
  71.                 {  
  72.                     Log.i(TAG,"成功连接上了服务,现在可以调用服务中的方法了");  
  73.                     s = (IService) service;//因为我们知道在Myservice中的IBinder对象继承了Binder并实现了IService接口  
  74.                 }  
  75.             };  
  76.             this.bindService(intent3, conn, Service.BIND_AUTO_CREATE);  
  77.             break;  
  78.         case R.id.but_unbind:  
  79.             if(conn != null)  
  80.                 this.unbindService(conn);  
  81.             break;  
  82.         case R.id.but_func:  
  83.             if(s != null)  
  84.             {  
  85.                 s.func();//调用IBinder的方法间接与service通信  
  86.             }  
  87.             else  
  88.             {  
  89.                 Toast.makeText(this,"还没有绑定服务...",0).show();  
  90.             }  
  91.             break;  
  92.         }  
  93.     }  
  94.     @Override  
  95.     protected void onDestroy()//activity销毁时,为避免报错,自动解除绑定service,之所以try起来,是因为service只能被解除绑定一次  
  96.     {  
  97.         super.onDestroy();  
  98.         try  
  99.         {  
  100.             if(conn != null)  
  101.                 unbindService(conn);  
  102.         } catch (Exception e)  
  103.         {  
  104.         }  
  105.     }  
  106.   
  107. }  
IService接口:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package com.example.servicedemo2.binder;  
  2. public interface IService  
  3. {  
  4.     public void func();  
  5. }  
运行效果:

有了这个程序,观察生命周期就方便了,只要观察logcat就行了,这里我就不截图了,读者如果有兴趣可以下载示例代码(最下方),自己运行下,以加深对service的理解。
这里我们读者可能看到我创建了一个IService接口,并让自定义的MyBinder对象实现了IService方法,之所以这样做,是为了提高封装性,读者注意看,我将MyBinder定义成了Service中的私有类
,这样里面的方法就不会全部暴露,我们将想暴露给外界的方法抽象到IService接口中,这样外界只能访问到我们想暴露的方法了。

六.如何让service与activity进行交互?                                 


通常service与activity交互的方式有两种:
1.使用bindservice方式交互。
    这种交互方式在上面那个例子中已经体现出来了,绑定服务后,通过service返回的IBinder对象即可调用service中的方法。
2.使用broadcastReceiver交互(注意性能问题,广播接收者调用时间有限制)
    不熟悉广播接收者的请看这篇文章
    我们也是通过一个实例代码说明。原理很简单,在service内部创建广播接收者,接收一个固定的动作(action),然后在activity中发送广播即可。
    首先来看service(广播接收者采用动态注册的方式声明):
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package com.example.service;  
  2.   
  3. import android.app.Service;  
  4. import android.content.BroadcastReceiver;  
  5. import android.content.Context;  
  6. import android.content.Intent;  
  7. import android.content.IntentFilter;  
  8. import android.os.IBinder;  
  9. import android.widget.Toast;  
  10.   
  11. public class MyService extends Service  
  12. {  
  13.     private MyReceiver receiver = null;  
  14.     @Override  
  15.     public IBinder onBind(Intent intent)  
  16.     {  
  17.         return null;  
  18.     }  
  19.     @Override  
  20.     public void onCreate()  
  21.     {  
  22.         IntentFilter filter = new IntentFilter();  
  23.         filter.addAction("com.example.broadcast");//监听的动作  
  24.         receiver = new MyReceiver();  
  25.         this.registerReceiver(receiver, filter);//注册广播接收者  
  26.     }  
  27.     /** 
  28.      * 服务中的方法 
  29.      */  
  30.     private void serviceMethod()  
  31.     {  
  32.         Toast.makeText(getApplicationContext(),"我是服务中的方法...",0).show();  
  33.     }  
  34.     @Override  
  35.     public void onDestroy()  
  36.     {  
  37.         if(receiver!=null)  
  38.             this.unregisterReceiver(receiver);//解除注册  
  39.     }  
  40.   
  41.     public class MyReceiver extends BroadcastReceiver  
  42.     {  
  43.         @Override  
  44.         public void onReceive(Context context, Intent intent)  
  45.         {  
  46.             serviceMethod();  
  47.         }  
  48.     }  
  49. }  
测试的activity:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package com.example.myservicedemo3;  
  2.   
  3. import android.app.Activity;  
  4. import android.content.Intent;  
  5. import android.os.Bundle;  
  6. import android.view.View;  
  7. import android.view.View.OnClickListener;  
  8. import android.widget.Button;  
  9.   
  10. import com.example.service.MyService;  
  11.   
  12. public class MainActivity extends Activity  
  13. {      
  14.     private Button but_send = null;  
  15.     @Override  
  16.     protected void onCreate(Bundle savedInstanceState)  
  17.     {  
  18.         super.onCreate(savedInstanceState);  
  19.         setContentView(R.layout.activity_main);  
  20.       
  21. //        开启service服务  
  22.         Intent intent = new Intent(this,MyService.class);  
  23.         this.startService(intent);  
  24.           
  25.         but_send = (Button) findViewById(R.id.but_send);  
  26.         but_send.setOnClickListener(new OnClickListener()  
  27.         {  
  28.             @Override  
  29.             public void onClick(View v)  
  30.             {  
  31.                 Intent broadcast = new Intent();  
  32.                 broadcast.setAction("com.example.broadcast");//和service中的receiver接收的action一致  
  33.                 MainActivity.this.sendBroadcast(broadcast);//发广播  
  34.             }  
  35.         });  
  36.           
  37.     }  
  38. }  
布局与清单文件略。
运行时,只有点击button,service中的广播接收者便会受到广播,进而调用service的方法。

七.使用AIDL绑定远程服务                                              


   这不是本文重点,下面简单以一个例子说明,如果读者想进一步了解,可以查看官方文档。
所谓aidl,就是一个接口定义语言,用于服务间的跨进程通信。比如你的应用需要调用支付宝的支付服务,这就需要使用到aidl了。下面的例子正是基于此场景:
第一步:新建一个android工程,作为”支付服务“。
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package com.example.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 PayService extends Service  
  9. {  
  10.     private static final String TAG = "PayService";  
  11.     @Override  
  12.     public IBinder onBind(Intent intent)  
  13.     {  
  14.         Log.i(TAG,"绑定了支付服务...");  
  15.         return new MyBinder();  
  16.     }  
  17.       
  18.       
  19.     @Override  
  20.     public boolean onUnbind(Intent intent)  
  21.     {  
  22.         Log.i(TAG,"解除绑定支付服务...");  
  23.         return false;  
  24.     }  
  25.     private class MyBinder extends IService.Stub  
  26.     {  
  27.         @Override  
  28.         public void callServiceFunc()  
  29.         {  
  30.             pay();  
  31.         }  
  32.     }  
  33.       
  34.     /** 
  35.      * 服务内部的支付方法 
  36.      */  
  37.     private void pay()  
  38.     {  
  39.         Log.i(TAG,"调用了支付的方法...");  
  40.     }  
  41. }  
读者肯定注意到这里的MyBinder继承了IService.Stub,这个类是什么呢?
读者还记得上面的IService接口么,那个接口是将Binder中想暴露给外界的方法抽象出来而形成的。IService接口不仅在服务中调用,还要在Activity中调用,一个应用程序内部接口是公用的,但是不同的应用程序之间如果想公用一个接口,必须有某种机制才行。这就引出aidl了,下面我们建立一个.aidl格式的”接口“:
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package com.example.service;  
  2. interface IService  
  3. {  
  4.     void callServiceFunc();  
  5. }  
可以看到,这个aidl接口跟接口貌似没什么区别,除了后缀不一样之外。读者走到这一步请在看下R文件,看看有没有变化,如果aidl没错误的话,R文件中会自动生成这样一个文件:IService.java
,我们的IService.Stub就来自这里。这里的Stub类已经自动继承了Binder类!我们在其他应用如果想使用该接口,只需将aidl文件与对应包名拷贝到工程下即可,另外在ServiceConnection方法中可以通过:Stub.asInterface方法将Binder对象转化为IService对象。
工程截图如下:
第二步:在建一个android工程,作为第三方应用。
[java] view plaincopy在CODE上查看代码片派生到我的代码片
  1. package com.example.thirdapplication;  
  2.   
  3. import android.app.Activity;  
  4. import android.app.Service;  
  5. import android.content.ComponentName;  
  6. import android.content.Intent;  
  7. import android.content.ServiceConnection;  
  8. import android.os.Bundle;  
  9. import android.os.IBinder;  
  10. import android.os.RemoteException;  
  11. import android.view.View;  
  12. import android.view.View.OnClickListener;  
  13. import android.widget.Button;  
  14. import android.widget.Toast;  
  15.   
  16. import com.example.service.IService;  
  17. import com.example.service.IService.Stub;  
  18.   
  19. /** 
  20.  * @author Rowand jj 
  21.  * 
  22.  *这是第三方的应用,用来远程调用支付服务。 
  23.  *使用aidl调用远程服务。 
  24.  *    aidl:Android Interface Definition Language 
  25.  */  
  26. public class MainActivity extends Activity implements OnClickListener  
  27. {  
  28.     private Button but_bind = null;  
  29.     private Button but_pay = null;  
  30.       
  31.     private IService myService = null;  
  32.     private ServiceConnection conn = null;  
  33.       
  34.     @Override  
  35.     protected void onCreate(Bundle savedInstanceState)  
  36.     {  
  37.         super.onCreate(savedInstanceState);  
  38.         setContentView(R.layout.activity_main);  
  39.         but_bind = (Button) findViewById(R.id.but_bind);  
  40.         but_pay = (Button) findViewById(R.id.but_pay);  
  41.           
  42.         but_bind.setOnClickListener(this);  
  43.         but_pay.setOnClickListener(this);  
  44.     }  
  45.   
  46.     @Override  
  47.     public void onClick(View v)  
  48.     {  
  49.         switch (v.getId())  
  50.         {  
  51.         case R.id.but_bind:  
  52.             Intent intent = new Intent("com.example.pay");  
  53.             conn = new ServiceConnection()  
  54.             {  
  55.                 @Override  
  56.                 public void onServiceDisconnected(ComponentName name)  
  57.                 {  
  58.                 }  
  59.                 @Override  
  60.                 public void onServiceConnected(ComponentName name, IBinder service)  
  61.                 {  
  62.                     myService = Stub.asInterface(service);  
  63.                 }  
  64.             };  
  65.             this.bindService(intent, conn, Service.BIND_AUTO_CREATE);  
  66.             Toast.makeText(this,"绑定成功..."0).show();  
  67.             break;  
  68.         case R.id.but_pay:  
  69.             try  
  70.             {  
  71.                 if(myService!=null)  
  72.                     myService.callServiceFunc();  
  73.             } catch (RemoteException e)  
  74.             {  
  75.                 e.printStackTrace();  
  76.             }  
  77.             break;  
  78.         }  
  79.     }  
  80.       
  81.     @Override  
  82.     protected void onDestroy()  
  83.     {  
  84.         super.onDestroy();  
  85.         if(conn != null)  
  86.             this.unbindService(conn);  
  87.     }  
  88.   
  89. }  
工程截图如下:
运行截图:



八.service与thread的区别?                                           


service与thread是两个完全不同的概念。他们的使用场景也不一样
thread通常用于处理耗时操作,而service则是长期运行于后台的组件。它们的生命周期是不一样的。
1.thread的生命周期是不定的,当创建thread的组件比如activity被销毁后,thread如果没有执行完毕,该thread仍然会继续执行,这样该activity就不再只有thread的引用了,这导致该线程变得不可控。。
2.service是长期运行于后台的组件。它的生命周期很长,只有当在代码中调用unbindservice、stopservice、stopself或者在手机进程列表中kill掉该进程,service才会被销毁。当然,系统内存非常低的情况下,也会干掉service。
你可以把 Service 想象成一种消息服务,而你可以在任何有 Context 的地方调用 Context.startService、Context.stopService、Context.bindService,Context.unbindService,来控制它,你也可以在 Service 里注册 BroadcastReceiver,在其他地方通过发送 broadcast 来控制它,当然这些都是 Thread 做不到的。


---------------------------------------------------------------------------------------------------------------------------------------------------

示例代码打包下载
------------------------------------------------------------------------------------------------------------------------------------------------------
ps.写一篇博客不容易,希望尊重作者的劳动成果,转载请声明出处:http://blog.csdn.net/chdjj/article/details/19333171
0 0