Android四大组件之Service

Android四大组件之Service

       Android支持服务的概念,服务是在后台运行的组件,没有用户界面,Android服务可用有与活动独立的生命周期。Android支持两种类型的服务:

本地服务:

      本地服务只能由承载该服务的应用程序访问,无法供在设备上运行的其他应用程序访问。客户端调用Context.startService()启动该服务。

远程服务:

      远程服务除了可从承载服务的应用程序访问,还可以从其他应用程序访问。远程服务使用AIDL向客户端定义。服务支持onBind()方法,客户端通过Context.bindService()进行调用。

 

1)本地服务

1.1、startService  

      本地服务可由Context.startService()启动,启动后这些服务将持续运行,直到客户端调用Context.stopService()或服务自己调用stopSelf()。

      注意:如果调用Context.startService()时还未创建服务,系统将实例化服务并调用服务的onStartCommand()方法。如果在调用Context.startService()时服务已经启动,那么不会再创建一个实例,而是重新调用正在运行的服务的onStartCommand()方法。

      Demo:我们在MainActivity中新建两个两个Button,一个用于启动服务,另外一个用于停止服务。建立一个MyService类继承于Service,当收到服务的时候在通知栏弹出通知,一直到我们的服务退出才清除通知,同时收到启动服务的消息时我们建立一个线程sleep 10秒。当我们退出MainActivity的时候停止服务,同时清除通知栏的通知。

MainActivity.xml:就两个Button用于启动和停止服务。

  1. <SPAN style="FONT-SIZE: 14px"><RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.     xmlns:tools="http://schemas.android.com/tools"  
  3.     android:layout_width="match_parent"  
  4.     android:layout_height="match_parent"  
  5.     android:paddingBottom="@dimen/activity_vertical_margin"  
  6.     android:paddingLeft="@dimen/activity_horizontal_margin"  
  7.     android:paddingRight="@dimen/activity_horizontal_margin"  
  8.     android:paddingTop="@dimen/activity_vertical_margin"  
  9.     tools:context=".MainActivity" >  
  10.   
  11.     <Button  
  12.         android:id="@+id/btnStart"  
  13.         android:layout_width="wrap_content"  
  14.         android:layout_height="wrap_content"  
  15.         android:text="startService" >  
  16.     </Button>  
  17.       
  18.     <Button  
  19.         android:id="@+id/btnStop"  
  20.         android:layout_width="wrap_content"  
  21.         android:layout_height="wrap_content"  
  22.         android:text="stopService"   
  23.         android:layout_below="@id/btnStart">  
  24.     </Button>  
  25.   
  26. </RelativeLayout></SPAN>  
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    tools:context=".MainActivity" >

    <Button
        android:id="@+id/btnStart"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="startService" >
    </Button>
    
    <Button
        android:id="@+id/btnStop"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="stopService" 
        android:layout_below="@id/btnStart">
    </Button>

</RelativeLayout>

然后是MainActivity,用于响应Button的单击事件:

  1. <SPAN style="FONT-SIZE: 14px">public class MainActivity extends Activity implements OnClickListener{  
  2.   
  3.     private static final String TAG = "MainActivity";  
  4.     private int counter = 1;  
  5.     private Button btnStart, btnStop;  
  6.     @Override  
  7.     protected void onCreate(Bundle savedInstanceState) {  
  8.         super.onCreate(savedInstanceState);  
  9.         setContentView(R.layout.activity_main);  
  10.         btnStart = (Button)this.findViewById(R.id.btnStart);  
  11.         btnStop = (Button)this.findViewById(R.id.btnStop);  
  12.         btnStart.setOnClickListener(this);  
  13.         btnStop.setOnClickListener(this);  
  14.     }  
  15.   
  16.     @Override  
  17.     public void onClick(View v) {  
  18.         // TODO Auto-generated method stub  
  19.         Log.v(TAG, "id:"+v.getId() + "btn:"+R.id.btnStart);  
  20.         switch (v.getId()) {  
  21.         case R.id.btnStart:  
  22.             Log.v(TAG, "Starting Service...counter=" + counter);  
  23.             Intent intent = new Intent(MainActivity.this, MyService.class);  
  24.             intent.putExtra("counter", counter);  
  25.             startService(intent);  
  26.             break;  
  27.   
  28.         case R.id.btnStop:  
  29.             Log.v(TAG, "Stopping Service...");  
  30.             if( stopService(new Intent(MainActivity.this, MyService.class)) ) {  
  31.                 Log.v(TAG, "stopService successful");  
  32.             } else {  
  33.                 Log.v(TAG, "stopService failed");  
  34.             }  
  35.             break;  
  36.               
  37.         default:  
  38.             break;  
  39.         }  
  40.     }  
  41.       
  42.     @Override  
  43.     protected void onDestroy() {  
  44.         // TODO Auto-generated method stub  
  45.         stopService(new Intent(MainActivity.this, MyService.class));  
  46.         super.onDestroy();  
  47.     }  
  48. }</SPAN>  
public class MainActivity extends Activity implements OnClickListener{

	private static final String TAG = "MainActivity";
	private int counter = 1;
	private Button btnStart, btnStop;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		btnStart = (Button)this.findViewById(R.id.btnStart);
		btnStop = (Button)this.findViewById(R.id.btnStop);
		btnStart.setOnClickListener(this);
		btnStop.setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		Log.v(TAG, "id:"+v.getId() + "btn:"+R.id.btnStart);
		switch (v.getId()) {
		case R.id.btnStart:
			Log.v(TAG, "Starting Service...counter=" + counter);
			Intent intent = new Intent(MainActivity.this, MyService.class);
			intent.putExtra("counter", counter);
			startService(intent);
			break;

		case R.id.btnStop:
			Log.v(TAG, "Stopping Service...");
			if( stopService(new Intent(MainActivity.this, MyService.class)) ) {
				Log.v(TAG, "stopService successful");
			} else {
				Log.v(TAG, "stopService failed");
			}
			break;
			
		default:
			break;
		}
	}
	
	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		stopService(new Intent(MainActivity.this, MyService.class));
		super.onDestroy();
	}
}


最后是我们的MyService,当收到服务的时候,在通知栏弹出通知,并启动一个sleep 10秒的线程。

  1. <SPAN style="FONT-SIZE: 14px">public class MyService extends Service {  
  2.   
  3.     private static final String TAG = "MyService";  
  4.     private NotificationManager notificationMgr;  
  5.     private ThreadGroup threadGroup = new ThreadGroup("ServiceWorkder");   
  6.       
  7.     @Override  
  8.     public void onCreate() {  
  9.         // TODO Auto-generated method stub  
  10.         super.onCreate();  
  11.         Log.v(TAG, "in onCreate");  
  12.         notificationMgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);  
  13.         Notification notification = new Notification(R.drawable.ic_launcher, "Service is running", System.currentTimeMillis());  
  14.         notification.flags = Notification.FLAG_NO_CLEAR;  
  15.         PendingIntent intent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0);  
  16.         notification.setLatestEventInfo(this, TAG, "Service is running", intent);  
  17.         notificationMgr.notify(0, notification);  
  18.     }  
  19.       
  20.     @Override  
  21.     public int onStartCommand(Intent intent, int flags, int startId) {  
  22.         // TODO Auto-generated method stub  
  23.         super.onStartCommand(intent, flags, startId);  
  24.           
  25.         int counter = intent.getExtras().getInt("counter");  
  26.         Log.v(TAG, "in onStartCommand, counter = "+counter+",startId = "+startId);  
  27.         new Thread(threadGroup, new ServiceWorker(counter)).start();  
  28.         return START_STICKY;  
  29.     }  
  30.   
  31.     class ServiceWorker implements Runnable {  
  32.         private int counter = -1;  
  33.           
  34.         public ServiceWorker(int counter) {  
  35.             this.counter = counter;  
  36.         }  
  37.           
  38.         public void run() {  
  39.             final String TAG = "ServiceWorker" + Thread.currentThread().getId();  
  40.             try {  
  41.                 Log.v(TAG, "Sleeping for 10 seconds.counter="+counter);  
  42.                 Thread.sleep(10000);  
  43.                 Log.v(TAG, "...waking up");  
  44.             } catch (Exception e) {  
  45.                 // TODO: handle exception  
  46.                 Log.v(TAG, "...sleep interrupt");  
  47.             }  
  48.         }  
  49.     }  
  50.       
  51.     @Override  
  52.     public void onDestroy() {  
  53.         // TODO Auto-generated method stub  
  54.         Log.v(TAG, "in onDestroy. Interrupt threads and canceling notifications");  
  55.         threadGroup.interrupt();  
  56.         notificationMgr.cancelAll();  
  57.         super.onDestroy();  
  58.     }  
  59.       
  60.     @Override  
  61.     public IBinder onBind(Intent intent) {  
  62.         // TODO Auto-generated method stub  
  63.         return null;  
  64.     }  
  65.   
  66. }</SPAN>  
public class MyService extends Service {

	private static final String TAG = "MyService";
	private NotificationManager notificationMgr;
	private ThreadGroup threadGroup = new ThreadGroup("ServiceWorkder"); 
	
	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.onCreate();
		Log.v(TAG, "in onCreate");
		notificationMgr = (NotificationManager)getSystemService(NOTIFICATION_SERVICE);
		Notification notification = new Notification(R.drawable.ic_launcher, "Service is running", System.currentTimeMillis());
		notification.flags = Notification.FLAG_NO_CLEAR;
		PendingIntent intent = PendingIntent.getActivity(this, 0, new Intent(this, MainActivity.class), 0);
		notification.setLatestEventInfo(this, TAG, "Service is running", intent);
		notificationMgr.notify(0, notification);
	}
	
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		// TODO Auto-generated method stub
		super.onStartCommand(intent, flags, startId);
		
		int counter = intent.getExtras().getInt("counter");
		Log.v(TAG, "in onStartCommand, counter = "+counter+",startId = "+startId);
		new Thread(threadGroup, new ServiceWorker(counter)).start();
		return START_STICKY;
	}

	class ServiceWorker implements Runnable {
		private int counter = -1;
		
		public ServiceWorker(int counter) {
			this.counter = counter;
		}
		
		public void run() {
			final String TAG = "ServiceWorker" + Thread.currentThread().getId();
			try {
				Log.v(TAG, "Sleeping for 10 seconds.counter="+counter);
				Thread.sleep(10000);
				Log.v(TAG, "...waking up");
			} catch (Exception e) {
				// TODO: handle exception
				Log.v(TAG, "...sleep interrupt");
			}
		}
	}
	
	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		Log.v(TAG, "in onDestroy. Interrupt threads and canceling notifications");
		threadGroup.interrupt();
		notificationMgr.cancelAll();
		super.onDestroy();
	}
	
	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return null;
	}

}


最后不要忘了在AndroidManifest.xml中声明我们的Service:

  1. <SPAN style="FONT-SIZE: 14px">        <service   
  2.             android:name=".MyService">  
  3.         </service></SPAN>  
        <service 
            android:name=".MyService">
        </service>

 

最后通知栏运行效果如下:

 

1.2、bindService

        本地服务也可由Context.bindService()启动,这样调用者和服务绑在一起,调用者一旦退出,服务也就终止了。客户端建立一个与Service连接,使用此连接与Service通信,通过Context.bindService()绑定服务,使用Context.unbindService()关闭服务。多个客户端可以绑定同一个服务,如果Service未启动,bindService()可以启动服务。

       注意:上面的startService()和bindService()是完全独立的两种模式,你可以绑定一个已经通过startService()启动的服务。例如:一个后台播放音乐的服务可以通过startService()启动播放,然后activity可以通过调用bindService()方法建立于Service的联系,执行切换歌曲等操作。这种情况下:stopService()不会停止服务,直到最后一个unbindService()调用。

      当创建一个能够提供绑定功能的服务时,我们必须提供一个IBinder对象,客户端能够使用这个对象与服务通信,Android中有三种方式:

(1)扩展Binder类

          一般用于服务和Activity属于同一个进程的情况。类似上面的startService()我们在MainActivity中建立两个Button,一个用于bindService,另外一个unbindService()。在获得Service的IBinder接口之后就可以调用Service的内部方法了。

  1. <SPAN style="FONT-SIZE: 14px">public class MainActivity extends Activity implements OnClickListener{  
  2.   
  3.     private static final String TAG = "MainActivity";  
  4.     private boolean isBindFlag = false;  
  5.     private Button btnBind, btnUnbind;  
  6.     @Override  
  7.     protected void onCreate(Bundle savedInstanceState) {  
  8.         super.onCreate(savedInstanceState);  
  9.         setContentView(R.layout.activity_main);  
  10.         btnBind = (Button)this.findViewById(R.id.btnBind);  
  11.         btnUnbind = (Button)this.findViewById(R.id.btnUnbind);  
  12.         btnBind.setOnClickListener(this);  
  13.         btnUnbind.setOnClickListener(this);  
  14.     }  
  15.   
  16.     @Override  
  17.     public void onClick(View v) {  
  18.         // TODO Auto-generated method stub  
  19.         switch (v.getId()) {  
  20.           
  21.         case R.id.btnBind:  
  22.             Intent intent2 = new Intent(MainActivity.this, MyBindService.class);  
  23.             bindService(intent2, serviceConnection, Context.BIND_AUTO_CREATE);  
  24.             break;  
  25.               
  26.         case R.id.btnUnbind:  
  27.             unbindService(serviceConnection);  
  28.             break;  
  29.         default:  
  30.             break;  
  31.         }  
  32.     }  
  33.     private ServiceConnection serviceConnection = new ServiceConnection() {  
  34.           
  35.         @Override  
  36.         public void onServiceDisconnected(ComponentName name) {  
  37.             // TODO Auto-generated method stub  
  38.             isBindFlag = false;  
  39.         }  
  40.           
  41.         @Override  
  42.         public void onServiceConnected(ComponentName name, IBinder service) {  
  43.             // TODO Auto-generated method stub  
  44.             MyBindService.MyBinder binder = (MyBinder)service;  
  45.             MyBindService bndService = binder.getService();  
  46.             bndService.myMethod();  
  47.             isBindFlag = true;  
  48.         }  
  49.     };  
  50.       
  51.     @Override  
  52.     protected void onDestroy() {  
  53.         // TODO Auto-generated method stub  
  54.         if(isBindFlag == true) {  
  55.             unbindService(serviceConnection);  
  56.         }  
  57.         super.onDestroy();  
  58.     }  
  59. }</SPAN>  
public class MainActivity extends Activity implements OnClickListener{

	private static final String TAG = "MainActivity";
	private boolean isBindFlag = false;
	private Button btnBind, btnUnbind;
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		btnBind = (Button)this.findViewById(R.id.btnBind);
		btnUnbind = (Button)this.findViewById(R.id.btnUnbind);
		btnBind.setOnClickListener(this);
		btnUnbind.setOnClickListener(this);
	}

	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		switch (v.getId()) {
		
		case R.id.btnBind:
			Intent intent2 = new Intent(MainActivity.this, MyBindService.class);
			bindService(intent2, serviceConnection, Context.BIND_AUTO_CREATE);
			break;
			
		case R.id.btnUnbind:
			unbindService(serviceConnection);
			break;
		default:
			break;
		}
	}
	private ServiceConnection serviceConnection = new ServiceConnection() {
		
		@Override
		public void onServiceDisconnected(ComponentName name) {
			// TODO Auto-generated method stub
			isBindFlag = false;
		}
		
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			// TODO Auto-generated method stub
			MyBindService.MyBinder binder = (MyBinder)service;
			MyBindService bndService = binder.getService();
			bndService.myMethod();
			isBindFlag = true;
		}
	};
	
	@Override
	protected void onDestroy() {
		// TODO Auto-generated method stub
		if(isBindFlag == true) {
			unbindService(serviceConnection);
		}
		super.onDestroy();
	}
}


        这里当绑定到MyBindService之后,就可以通过bndService实例调用其方法myMethod()了。下面MyBindService比较简单就是继承于Service,并实现其onBind()接口,返回一个MyBinder实例,客户端拿到这个MyBinder之后可以通过它获取到MyBindService实例,然后调用其提供的myMethod()方法了。

 

  1. <SPAN style="FONT-SIZE: 14px">public class MyBindService extends Service {  
  2.   
  3.     private static final String TAG = "MyBindService";  
  4.       
  5.     public void myMethod() {  
  6.         Log.i(TAG, "myBindService->myMethod()");  
  7.     }  
  8.       
  9.     @Override  
  10.     public IBinder onBind(Intent intent) {  
  11.         // TODO Auto-generated method stub  
  12.         return myBinder;  
  13.     }  
  14.       
  15.     public class MyBinder extends Binder {  
  16.           
  17.         public MyBindService getService() {  
  18.             return MyBindService.this;  
  19.         }  
  20.     }  
  21.   
  22.     private MyBinder myBinder = new MyBinder();  
  23. }</SPAN>  
public class MyBindService extends Service {

	private static final String TAG = "MyBindService";
	
	public void myMethod() {
		Log.i(TAG, "myBindService->myMethod()");
	}
	
	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return myBinder;
	}
	
	public class MyBinder extends Binder {
		
		public MyBindService getService() {
			return MyBindService.this;
		}
	}

	private MyBinder myBinder = new MyBinder();
}

 

     同理最后我们也需要在AndroidManifest.xml中声明我们的服务。

 

(2)使用Messenger

 

 

(3)Remote Service 也就是我们下面要说的AIDL服务了。

 

2)AIDL服务     

 

2.1)构建远程服务  

      上面介绍的各种服务只能由承载它的应用程序使用,如果想构建可由其他进程通过RPC使用的服务,需要使用IDL来定义向客户端公开的接口,在Android中这个IDL就称为AIDL。构建远程服务的一般步骤为:

 

1、编写一个AIDL文件用来向客户端定义接口。AIDL文件使用Java语法扩展名为.aidl,其内部使用的包名和Android项目使用的包名相同。

       首先在项目的src目录下新建一个IStudentInfo.aidl文件,在AIDL文件中定义服务接口。提供了double getScore(String name)接口,根据给定的String类型的学生姓名,返回一个double类型的分数。

      

  1. package com.myAndroid.aidlService;  
  2.   
  3. interface IStudentInfoService {  
  4.     double getScore(String name);  
  5. }  
package com.myAndroid.aidlService;

interface IStudentInfoService {
	double getScore(String name);
}

      

 

2、将AIDL文件添加到Eclipse项目的src目录下,Android Eclipse插件将调用AIDL编译器从AIDL文件生成Java接口。

 

       生成的java接口文件位于gen/com.myAndroid.aidlService下,名为IStudengInfoService.java:

  1. /* 
  2.  * This file is auto-generated.  DO NOT MODIFY. 
  3.  * Original file: C:\Documents and Settings\Administrator\workspace\Android使用AIDL创建Service\src\com\myAndroid\aidlService\IStudentInfoService.aidl 
  4.  */  
  5. package com.myAndroid.aidlService;  
  6. public interface IStudentInfoService extends android.os.IInterface  
  7. {  
  8. /** Local-side IPC implementation stub class. */  
  9. public static abstract class Stub extends android.os.Binder implements com.myAndroid.aidlService.IStudentInfoService  
  10. {  
  11. private static final java.lang.String DESCRIPTOR = "com.myAndroid.aidlService.IStudentInfoService";  
  12. /** Construct the stub at attach it to the interface. */  
  13. public Stub()  
  14. {  
  15. this.attachInterface(this, DESCRIPTOR);  
  16. }  
  17. /** 
  18.  * Cast an IBinder object into an com.myAndroid.aidlService.IStudentInfoService interface, 
  19.  * generating a proxy if needed. 
  20.  */  
  21. public static com.myAndroid.aidlService.IStudentInfoService asInterface(android.os.IBinder obj)  
  22. {  
  23. if ((obj==null)) {  
  24. return null;  
  25. }  
  26. android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);  
  27. if (((iin!=null)&&(iin instanceof com.myAndroid.aidlService.IStudentInfoService))) {  
  28. return ((com.myAndroid.aidlService.IStudentInfoService)iin);  
  29. }  
  30. return new com.myAndroid.aidlService.IStudentInfoService.Stub.Proxy(obj);  
  31. }  
  32. @Override public android.os.IBinder asBinder()  
  33. {  
  34. return this;  
  35. }  
  36. @Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException  
  37. {  
  38. switch (code)  
  39. {  
  40. case INTERFACE_TRANSACTION:  
  41. {  
  42. reply.writeString(DESCRIPTOR);  
  43. return true;  
  44. }  
  45. case TRANSACTION_getScore:  
  46. {  
  47. data.enforceInterface(DESCRIPTOR);  
  48. java.lang.String _arg0;  
  49. _arg0 = data.readString();  
  50. double _result = this.getScore(_arg0);  
  51. reply.writeNoException();  
  52. reply.writeDouble(_result);  
  53. return true;  
  54. }  
  55. }  
  56. return super.onTransact(code, data, reply, flags);  
  57. }  
  58. private static class Proxy implements com.myAndroid.aidlService.IStudentInfoService  
  59. {  
  60. private android.os.IBinder mRemote;  
  61. Proxy(android.os.IBinder remote)  
  62. {  
  63. mRemote = remote;  
  64. }  
  65. @Override public android.os.IBinder asBinder()  
  66. {  
  67. return mRemote;  
  68. }  
  69. public java.lang.String getInterfaceDescriptor()  
  70. {  
  71. return DESCRIPTOR;  
  72. }  
  73. @Override public double getScore(java.lang.String name) throws android.os.RemoteException  
  74. {  
  75. android.os.Parcel _data = android.os.Parcel.obtain();  
  76. android.os.Parcel _reply = android.os.Parcel.obtain();  
  77. double _result;  
  78. try {  
  79. _data.writeInterfaceToken(DESCRIPTOR);  
  80. _data.writeString(name);  
  81. mRemote.transact(Stub.TRANSACTION_getScore, _data, _reply, 0);  
  82. _reply.readException();  
  83. _result = _reply.readDouble();  
  84. }  
  85. finally {  
  86. _reply.recycle();  
  87. _data.recycle();  
  88. }  
  89. return _result;  
  90. }  
  91. }  
  92. static final int TRANSACTION_getScore = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);  
  93. }  
  94. public double getScore(java.lang.String name) throws android.os.RemoteException;  
  95. }  
/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: C:\Documents and Settings\Administrator\workspace\Android使用AIDL创建Service\src\com\myAndroid\aidlService\IStudentInfoService.aidl
 */
package com.myAndroid.aidlService;
public interface IStudentInfoService extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.myAndroid.aidlService.IStudentInfoService
{
private static final java.lang.String DESCRIPTOR = "com.myAndroid.aidlService.IStudentInfoService";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an com.myAndroid.aidlService.IStudentInfoService interface,
 * generating a proxy if needed.
 */
public static com.myAndroid.aidlService.IStudentInfoService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.myAndroid.aidlService.IStudentInfoService))) {
return ((com.myAndroid.aidlService.IStudentInfoService)iin);
}
return new com.myAndroid.aidlService.IStudentInfoService.Stub.Proxy(obj);
}
@Override public android.os.IBinder asBinder()
{
return this;
}
@Override public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws android.os.RemoteException
{
switch (code)
{
case INTERFACE_TRANSACTION:
{
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getScore:
{
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 = data.readString();
double _result = this.getScore(_arg0);
reply.writeNoException();
reply.writeDouble(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.myAndroid.aidlService.IStudentInfoService
{
private android.os.IBinder mRemote;
Proxy(android.os.IBinder remote)
{
mRemote = remote;
}
@Override public android.os.IBinder asBinder()
{
return mRemote;
}
public java.lang.String getInterfaceDescriptor()
{
return DESCRIPTOR;
}
@Override public double getScore(java.lang.String name) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
double _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(name);
mRemote.transact(Stub.TRANSACTION_getScore, _data, _reply, 0);
_reply.readException();
_result = _reply.readDouble();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_getScore = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public double getScore(java.lang.String name) throws android.os.RemoteException;
}


       对于所生成的类,注意几点:在IStudentInfoService中有一个名为IStudentInfoService的接口,实现了IInterface接口。

       内部有一个名为Stub的static final 抽象类扩展了android.os.Binder并实现了IStudentInfoService接口。

       内部还有一个名为Proxy的static类,实现了IStudentInfoService接口,它是Stub类的代理。      

3、实现一个服务并从onBind()方法返回所生成的接口。

 

      要实现服务的接口,需要编写一个类来扩展android.app.Service并实现IStudentInfoService接口,这个类需要提供onBind()方法将服务向客户端公开。

  1. package com.myAndroid.aidlService;  
  2.   
  3. import android.app.Service;  
  4. import android.content.Intent;  
  5. import android.os.IBinder;  
  6. import android.os.RemoteException;  
  7. import android.util.Log;  
  8.   
  9. public class StudentInfoService extends Service {  
  10.   
  11.     private static final String TAG = "StudentInfoService";  
  12.       
  13.     public class StudentInfoServiceImpl extends IStudentInfoService.Stub {  
  14.   
  15.         @Override  
  16.         public double getScore(String name) throws RemoteException {  
  17.             // TODO Auto-generated method stub   
  18.             Log.v(TAG, "getScore() called for "+ name);  
  19.             return 85.0;  
  20.         }  
  21.     }  
  22.       
  23.     @Override  
  24.     public IBinder onBind(Intent arg0) {  
  25.         // TODO Auto-generated method stub   
  26.         Log.v(TAG, "onBind called");  
  27.         return new StudentInfoServiceImpl();  
  28.     }  
  29. }  
package com.myAndroid.aidlService;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

public class StudentInfoService extends Service {

	private static final String TAG = "StudentInfoService";
	
	public class StudentInfoServiceImpl extends IStudentInfoService.Stub {

		@Override
		public double getScore(String name) throws RemoteException {
			// TODO Auto-generated method stub
			Log.v(TAG, "getScore() called for "+ name);
			return 85.0;
		}
	}
	
	@Override
	public IBinder onBind(Intent arg0) {
		// TODO Auto-generated method stub
		Log.v(TAG, "onBind called");
		return new StudentInfoServiceImpl();
	}
}


        从AIDL文件生成的Stub类是抽象类,且实现了IStudentInfoService接口。在我们的服务实现中内部类StudentInfoServiceIml扩展了Stub类,实现了getScore()方法,充当着远程服务具体实现,当客户端bind到服务时,返回一个此类的实例。

 

4、最后将服务配置添加到AndroidManifest.xml文件中

       这次我们需要用一个Intent过滤器来公开服务。

  1. <service android:name="StudentInfoService">  
  2.           <intent-filter >  
  3.               <action android:name="com.myAndroid.aidlService.IStudentInfoService"/>  
  4.           </intent-filter>  
  5.       </service>  
  <service android:name="StudentInfoService">
            <intent-filter >
                <action android:name="com.myAndroid.aidlService.IStudentInfoService"/>
            </intent-filter>
        </service>


2.2)调用远程服务  

       当客户端与服务通信时,它们之间需要一个协议或契约,在Android中这个协议就是AIDL文件。所以客户端调用服务的第一步就是获取服务的AIDL文件并将其复制到客户端项目中,同理AIDL编译器会创建一个接口定义公开文件,这个文件与服务器中的文件一样。

      我们创建一个新的Android项目名为 StudentInfoClient,包名为com.myAndroid.studentInfoClient。然后在这个项目下新建一个Java包名为

com.myAndroid.aidlService,并将IStudentInfoService.aidl文件拷贝到当前包下面。

     最后我们在MainActivity中通过bindService()获取服务的引用,然后调用其getScore()方法,即可跟服务端通信。下面给出客户端源码:

         

  1. package com.myAndroid.studentInfoClient;  
  2.   
  3. import com.myAndroid.aidlService.IStudengInfoService;  
  4.   
  5. import android.os.Bundle;  
  6. import android.os.IBinder;  
  7. import android.app.Activity;  
  8. import android.content.ComponentName;  
  9. import android.content.Context;  
  10. import android.content.Intent;  
  11. import android.content.ServiceConnection;  
  12. import android.support.v4.widget.SimpleCursorAdapter.ViewBinder;  
  13. import android.view.Menu;  
  14. import android.view.View;  
  15. import android.view.View.OnClickListener;  
  16. import android.widget.Button;  
  17. import android.widget.Toast;  
  18. import android.widget.ToggleButton;  
  19.   
  20. public class MainActivity extends Activity implements View.OnClickListener {  
  21.   
  22.     private ToggleButton toggleButton;  
  23.     private Button callButton;  
  24.     private IStudengInfoService myService = null;  
  25.       
  26.     @Override  
  27.     protected void onCreate(Bundle savedInstanceState) {  
  28.         super.onCreate(savedInstanceState);  
  29.         setContentView(R.layout.activity_main);  
  30.         toggleButton = (ToggleButton)this.findViewById(R.id.bindBtn);  
  31.         callButton = (Button)this.findViewById(R.id.callBtn);  
  32.         toggleButton.setOnClickListener(this);  
  33.         callButton.setOnClickListener(this);  
  34.     }  
  35.       
  36.     @Override  
  37.     public void onClick(View v) {  
  38.         // TODO Auto-generated method stub  
  39.         switch (v.getId()) {  
  40.         case R.id.bindBtn:  
  41.             if(((ToggleButton)v).isChecked()) {  
  42.                 bindService(new Intent(IStudengInfoService.class.getName()), conn, Context.BIND_AUTO_CREATE);  
  43.             } else {  
  44.                 unbindService(conn);  
  45.                 callButton.setEnabled(false);  
  46.             }  
  47.             break;  
  48.   
  49.         case R.id.callBtn:  
  50.             callService();  
  51.             break;  
  52.         default:  
  53.             break;  
  54.         }  
  55.     }  
  56.       
  57.     private void callService() {  
  58.         try {  
  59.             double val = myService.getScore("Lucy");  
  60.             Toast.makeText(MainActivity.this, "Value from service is "+ val, Toast.LENGTH_LONG).show();  
  61.         } catch (Exception e) {  
  62.             // TODO: handle exception  
  63.         }  
  64.     }  
  65.   
  66.     private ServiceConnection conn = new ServiceConnection() {  
  67.           
  68.         @Override  
  69.         public void onServiceDisconnected(ComponentName name) {  
  70.             // TODO Auto-generated method stub  
  71.             myService = null;  
  72.             toggleButton.setChecked(false);  
  73.             callButton.setEnabled(false);  
  74.         }  
  75.           
  76.         @Override  
  77.         public void onServiceConnected(ComponentName name, IBinder service) {  
  78.             // TODO Auto-generated method stub  
  79.             myService = IStudengInfoService.Stub.asInterface(service);  
  80.             toggleButton.setChecked(true);  
  81.             callButton.setEnabled(true);  
  82.         }  
  83.     };  
  84.       
  85.     protected void onDestroy() {  
  86.         if(callButton.isEnabled()) {  
  87.             unbindService(conn);  
  88.         }  
  89.         super.onDestroy();  
  90.     }  
  91. }  
package com.myAndroid.studentInfoClient;

import com.myAndroid.aidlService.IStudengInfoService;

import android.os.Bundle;
import android.os.IBinder;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.support.v4.widget.SimpleCursorAdapter.ViewBinder;
import android.view.Menu;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.Toast;
import android.widget.ToggleButton;

public class MainActivity extends Activity implements View.OnClickListener {

	private ToggleButton toggleButton;
	private Button callButton;
	private IStudengInfoService myService = null;
	
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		toggleButton = (ToggleButton)this.findViewById(R.id.bindBtn);
		callButton = (Button)this.findViewById(R.id.callBtn);
		toggleButton.setOnClickListener(this);
		callButton.setOnClickListener(this);
	}
	
	@Override
	public void onClick(View v) {
		// TODO Auto-generated method stub
		switch (v.getId()) {
		case R.id.bindBtn:
			if(((ToggleButton)v).isChecked()) {
				bindService(new Intent(IStudengInfoService.class.getName()), conn, Context.BIND_AUTO_CREATE);
			} else {
				unbindService(conn);
				callButton.setEnabled(false);
			}
			break;

		case R.id.callBtn:
			callService();
			break;
		default:
			break;
		}
	}
	
	private void callService() {
		try {
			double val = myService.getScore("Lucy");
			Toast.makeText(MainActivity.this, "Value from service is "+ val, Toast.LENGTH_LONG).show();
		} catch (Exception e) {
			// TODO: handle exception
		}
	}

	private ServiceConnection conn = new ServiceConnection() {
		
		@Override
		public void onServiceDisconnected(ComponentName name) {
			// TODO Auto-generated method stub
			myService = null;
			toggleButton.setChecked(false);
			callButton.setEnabled(false);
		}
		
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			// TODO Auto-generated method stub
			myService = IStudengInfoService.Stub.asInterface(service);
			toggleButton.setChecked(true);
			callButton.setEnabled(true);
		}
	};
	
	protected void onDestroy() {
		if(callButton.isEnabled()) {
			unbindService(conn);
		}
		super.onDestroy();
	}
}

         代码中对于AIDL服务我们需要提供ServiceConnection接口的实现,此接口定义两个方法:一个供系统建立服务连接时调用,另一个在销毁服务连接时调用。当建立服务时回调onServiceConnected()方法,我们根据参数service调用IStudengInfoService.Stub.asInterface()获得服务端的代理,然后调用其相应方法getScore()。

        注意:bindService()是异步调用,因为进程或服务可能没有运行,但是我们不能在主线程上等待服务启动。当从服务解除绑定时我们不会调用onServiceDisConnected(),只有在服务崩溃时才会调用它。如果调用了它,我们可能需要重写调用bindService()。

2.3)向服务传递复杂类型

注意:AIDL对非原语的支持:

 1、AIDL支持String和CharSequence。

 2、AIDL支持传递其他AIDL接口,但你引用的每个AIDL接口都需要一个import语句。

 3、AIDL支持传递实现android.os.Parcelable接口的复杂类型。需要在AIDL文件中包含针对这些类型的Import语句。

 4、AIDL支持java.util.List和java.util.Map,但是具有一些限制,集合中的项允许数据类型包括Java原语、String、CharSequence和android.os.Parcelable。无需为List和Map提供import语句,但是需要为Parcelable提供。

 5、除字符串外。非原语类型需要一个方向指示符。方向指示符包括in、out和inout。in表示由客户端设置,out表示值由服务设置,inout表示客户端和服务都设置了该值。

 Parcelable接口告诉Android运行时在封送marshalling和解unmarshalling过程中如何序列化和反序列化对象。

  1. public class Person implements Parcelable {  
  2.   
  3.     private int age;  
  4.     private String name;  
  5.           
  6.     public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() {  
  7.               
  8.         public Person createFromParcel(Parcel in) {  
  9.             return new Person(in);  
  10.         }  
  11.           
  12.         public Person[] newArray(int size) {  
  13.             return new Person[size];  
  14.         }  
  15.     };  
  16.           
  17.     public Person() {  
  18.     }  
  19.       
  20.     private Person(Parcel in) {  
  21.         readFromParcel(in);  
  22.     }  
  23.       
  24.     @Override  
  25.     public int describeContents() {  
  26.         // TODO Auto-generated method stub  
  27.         return 0;  
  28.     }  
  29.   
  30.     @Override  
  31.     public void writeToParcel(Parcel dest, int flags) {  
  32.         // TODO Auto-generated method stub  
  33.         dest.writeInt(age);  
  34.         dest.writeString(name);  
  35.     }  
  36.       
  37.     public void readFromParcel(Parcel in) {  
  38.         age = in.readInt();  
  39.         name = in.readString();  
  40.     }  
  41.   
  42.     public int getAge() {  
  43.         return age;  
  44.     }  
  45.   
  46.     public void setAge(int age) {  
  47.         this.age = age;  
  48.     }  
  49.   
  50.     public String getName() {  
  51.         return name;  
  52.     }  
  53.   
  54.     public void setName(String name) {  
  55.         this.name = name;  
  56.     }  
  57. }  
public class Person implements Parcelable {

	private int age;
	private String name;
		
	public static final Parcelable.Creator<Person> CREATOR = new Parcelable.Creator<Person>() {
			
		public Person createFromParcel(Parcel in) {
			return new Person(in);
		}
		
		public Person[] newArray(int size) {
			return new Person[size];
		}
	};
		
	public Person() {
	}
	
	private Person(Parcel in) {
		readFromParcel(in);
	}
	
	@Override
	public int describeContents() {
		// TODO Auto-generated method stub
		return 0;
	}

	@Override
	public void writeToParcel(Parcel dest, int flags) {
		// TODO Auto-generated method stub
		dest.writeInt(age);
		dest.writeString(name);
	}
	
	public void readFromParcel(Parcel in) {
		age = in.readInt();
		name = in.readString();
	}

	public int getAge() {
		return age;
	}

	public void setAge(int age) {
		this.age = age;
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}


        Parcelable接口定义在封送/解封送过程中混合和分解对象的契约,Parcelable接口的底层是Parcel容器对象,Parcel类是一种最快的序列号和反序列化机制,专为Android中的进程间通信而设计。

       要实现Parcelable接口,需要实现writeToParecl()和readFromParcel()方法。写入对象到包裹和从包裹中读取对象,注意:写入属性的顺序和读取属性的顺序必须相同。

       向Person类添加一个名为CREATOR的static final属性,该属性需要实现android.os.Parcelable.Creator<T>接口。

       为Parcelable提供一个构造函数,知道如何从Parcel创建对象。

      在.aidl文件中我们需要导入该类:import com.myAndroid.aidlService.Person。

      interface IStudentInfoServie{

                 String getScore(in String name, in Person requester);    // 后面非原语类型需要一个方向指示符。

      }

 

路漫漫其修远兮 吾将上下而求索
原文地址:https://www.cnblogs.com/hudabing/p/3319674.html