Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android服務(Service)全解析(四)--AIDL

Android服務(Service)全解析(四)--AIDL

編輯:關於Android編程

package cn.com.remoteServiceClient;
import com.cn.aidl.IRemoteQuery;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
//客戶端步驟:
//1 自定義ServiceConnection類實現ServiceConnection接口
//即RemoteQueryServiceConnection implements ServiceConnection
//重寫其方法public void onServiceConnected(ComponentName name, IBinder service)
//主要目的就是接受服務端傳過來的Binder對象,即方法的參數IBinder service.
//但是因為存在AIDL協議的轉換,所以IBinder service是一個代理對象,我們要強轉,將其轉換為接口類型對象.代碼如下:
//	public void onServiceConnected(ComponentName name, IBinder service) {
//		remoteQueryBinder=IRemoteQuery.Stub.asInterface(service);//強轉!!		
//	}
//
//2 利用隱式意圖激活遠程服務
//
//3 利用remoteQueryBinder調用服務裡面的方法
//
//
//
//AIDL的客戶端的總結:
// (1) 采用的是隱式意圖去激活服務service,因為服務和客戶端不在同一個應用!
//    彼此看不見,所以是"隱"的,那麼就要采用隱式意圖去激活,所以在文件清單裡
//    聲明服務組件的時候,還要給其配置意圖過濾器!
// (2) 在onServiceConnected()方法裡接收服務端返回來的Binder對象時一定要注意!!!
//     這裡和本地服務的情況不一樣!!!因為存在AIDL協議的轉換,所以IBinder service是一個代理對象
//     我們要強轉將其轉換為接口類型對象remoteQueryBinder
//     即remoteQueryBinder=IRemoteQuery.Stub.asInterface(service);實現轉換
// (3) 核心總結:
//     現在把兩個例子都寫完了,再往回看,那麼可以發現其實本地服務和遠程服務
//     都在圍繞一個核心:得到一個Binder對象--->這個Binder對象有一個顯著的
//     特點:可以實現與服務的綁定,且可以完成一些業務
//     
//     在本地服務裡面的實現是:Binder對象的類繼承自Binder且實現了業務的接口
//     那麼在接收此Binder對象的時候,當然可以用此接口來接收(父類引用指向子類對象嘛)
//     
//     在遠程服務裡面實現是:我們要寫一個aidl文件.
//     然後由AIDL自動生成了一個很大的接口,在此接口中最核心是Stub類!它繼承自Binder而且
//     實現了我們定義的業務接口!所以返回來的Binder代理對象(注意是代理對象!)
//     既有"綁定"到服務的能力,也有完成業務方法的能力
//     
//     所以在本地和遠程中我們都可以用業務接口來接受返回來的Binder對象或Binder代理對象    
public class MainActivity extends Activity {
    TextView numberTextView;
    TextView resultTextView;
    Button button;
    RemoteQueryServiceConnection conn=new RemoteQueryServiceConnection();
    IRemoteQuery remoteQueryBinder;
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);   
        numberTextView=(TextView) findViewById(R.id.number);
        resultTextView=(TextView) findViewById(R.id.result);
        button=(Button) findViewById(R.id.button);
        button.setOnClickListener(new ButtonOnClickListener());
        Intent service=new Intent();
        service.setAction("com.cn.remoteService.RemoteQueryService");
        bindService(service, conn, this.BIND_AUTO_CREATE);//綁定服務
    }
    
    private class ButtonOnClickListener implements OnClickListener{
		public void onClick(View v) {			
			String number=numberTextView.getText().toString();
			String result;
			try {
				result = remoteQueryBinder.queryByNum(Integer.valueOf(number));
				resultTextView.setText(result);
			} catch (Exception e) {
				e.printStackTrace();
			}
			
		}   	
    }
    //接收綁定的服務和解除服務
    private final class RemoteQueryServiceConnection implements ServiceConnection{
		public void onServiceConnected(ComponentName name, IBinder service) {
			remoteQueryBinder=IRemoteQuery.Stub.asInterface(service);			
		}
		public void onServiceDisconnected(ComponentName name) {
			remoteQueryBinder=null;
		}   	
    }

	protected void onDestroy() {
		unbindService(conn);
		super.onDestroy();	
	}
    
    
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >
   <TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="@string/number"
    />
    <EditText
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:id="@+id/number"
    />
    <Button
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:text="@string/button"
    android:id="@+id/button"
    />
    <TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:id="@+id/result"
    />
</LinearLayout>
package com.cn.remoteService;
import com.cn.aidl.IRemoteQuery;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
//服務端步驟:
//1 生成aidl文件
//建立一個接口,裡面可以有各種方法.
//將此接口稍作修改,讓"接口名"和"方法名"都沒有修飾(如public)!!代碼如下:
//interface IRemoteQuery {
//   String queryByNum(int number);
//}
// 然後找到這個被修改後接口的文件路徑,按照此路徑在硬盤上將其後綴改為.aidl
//這樣就生成了aidl文件.在此過程中注意:接口名和aidl文件名必須相同.

//2 刷新工程,系統會自動生成用於用於遠程通信的IRemoteQuery.java
// 分析此IRemoteQuery.java
//(1)IRemoteQuery.java內部實際是一個名叫IRemoteQuery的接口
//(2)該IRemoteQuery接口內部最重要的是一個Stub類(即IRemoteQuery.Stub),此類繼承自Binder類且實現了IRemoteQuery業務接口
// 所以該類的對象具有遠程訪問的能力
//    
//3在客戶端建立一個包,包的名稱與aidl文件所在的包名一致!然後將服務端的aidl文件拷貝到此包下,然後刷新
//發現在客戶端的gen下生成了IRemoteQuery.java
//    
//4 自定義遠程服務類(RemoteQueryService),其繼承自service
//
//5 在RemoteQueryService裡面寫一個內部類RemoteQueryBinder繼承自IRemoteQuery.Stub
//即RemoteQueryBinder extends IRemoteQuery.Stub
//6 重寫服務的public IBinder onBind(Intent intent)方法,返回一個Binder對象即RemoteQueryBinder類對象給客戶端
//
//
//關於AIDL的服務端的總結:
//(1) 自動生成的Stub是核心重點,從生成的代碼可以看出:它繼承自Binder而且實現了我們定義的業務接口
// 所以它既可以有綁定的能力也有調用業務的能力(這點和剛才寫的調用本地服務的例子有異曲同工之妙)
//(2) AIDL的定義和接口很類似,但是"接口名"和"方法名"都沒有修飾!!!!比如public
//(3) 在客戶端和服務端都要此包!!因為這相當於一個通信協議!!!雙方都必須遵守,所以一式兩份!!!
public class RemoteQueryService extends Service {
	@Override
	public IBinder onBind(Intent intent) {
		return remoteQueryBinder;
	}

	RemoteQueryBinder remoteQueryBinder=new RemoteQueryBinder();
	private String [] names=new String [] {"小明","小王","小楊","小李"};
	
	private final class RemoteQueryBinder extends IRemoteQuery.Stub{
		@Override
		public String queryByNum(int number) throws RemoteException {
			return query(number);
		}		
	}
	
	public String query(int i){
		if(i>0&&i<5){
			return names[i-1];
		}
		return "查詢錯誤,請再次輸入";
	}
	
}
/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: D:\\workspace\\queryByRemoteService\\src\\com\\cn\\aidl\\IRemoteQuery.aidl
 */
package com.cn.aidl;
/**
 *注意:
 *此AIDL的定義和接口很類似,但是"接口名"和"方法名"都沒有修飾!!!!比如public
 */
public interface IRemoteQuery extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.cn.aidl.IRemoteQuery
{
private static final java.lang.String DESCRIPTOR = "com.cn.aidl.IRemoteQuery";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an com.cn.aidl.IRemoteQuery interface,
 * generating a proxy if needed.
 */
public static com.cn.aidl.IRemoteQuery asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.cn.aidl.IRemoteQuery))) {
return ((com.cn.aidl.IRemoteQuery)iin);
}
return new com.cn.aidl.IRemoteQuery.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_queryByNum:
{
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 = data.readInt();
java.lang.String _result = this.queryByNum(_arg0);
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.cn.aidl.IRemoteQuery
{
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 java.lang.String queryByNum(int number) throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(number);
mRemote.transact(Stub.TRANSACTION_queryByNum, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
}
finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}
static final int TRANSACTION_queryByNum = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public java.lang.String queryByNum(int number) throws android.os.RemoteException;
}

 

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved