• 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);    // 后面非原语类型需要一个方向指示符。

          }

     

    路漫漫其修远兮 吾将上下而求索
  • 相关阅读:
    System.Diagnostics.Process.Start()
    Asp.Net 构架(HttpModule 介绍) Part.3
    Asp.Net 构架(Http Handler 介绍) Part.2
    Asp.Net构架(Http请求处理流程)
    Ruby 2.0 发布首个预览版
    Java基本数据类型及类型转换
    J2EE 1.4 APIs and Technologies
    java final 关键字
    Android获取通讯录
    Activity的四种加载模式(转载)
  • 原文地址:https://www.cnblogs.com/hudabing/p/3319674.html
Copyright © 2020-2023  润新知