Android-深入理解AIDL

最近從新溫習AIDL,發現技術這玩意就跟女人一樣,你過久沒去了解就會對它陌生卻又充滿新鮮感,然後查看網上的多半是胡扯,粘貼,我這裏整合下,裏面如果有錯誤望大家及時指出。廢話不多說,進入主題

首先來了解幾點常識:

1,一個Android應用程序對應一個進程;

2,Android應用程序進程間需要藉助IPC輕量級通訊協議;

3,切勿把線程和進程的概念搞混亂。一個進程可以包含多個線程,但是一個線程只會附屬於一個進程,可以理解成1對多的關係;

4,我們常見的Handler它是運行在UI主線程的,它負責的是異步處理數據,執行也是父線程和子線程;所以別把它和進程的概念混在一起。

進入主題,Android進程間的通訊:AIDL

這裏我以爲大家比較熟悉的C/S模式來講解整個通訊過程;但是我並沒有去新建立兩個項目了,就一個項目中,模擬進程通訊。不多說,先上項目圖


第一步,首先建立兩個aidl文件,forActivity.adil,forService.aidl 先來看看它們內部實現

package com.aidl;
interface forActivity{
  void perAction();
  void showString(int count);
}
package com.aidl;
import com.aidl.forActivity;
interface forService{
	 void registerTestCall(forActivity fa);
	 void callBack();
}



一看,哎喲,這裏面的編碼規則和java文件一樣,但是這個時候,我其他地方要調用怎麼辦?彆着急編譯器會默認在gen文件中生成對應.java文件

打開其中一個文件查看下其中源碼,先不詳細分析,慢慢來,就好比追女生一樣,要慢慢來,急不得

/*
 * This file is auto-generated.  DO NOT MODIFY.
 * Original file: F:\\workspace\\AndroidAIDL\\src\\com\\example\\androidaidl\\aidl\\forActivity.aidl
 */
package com.example.androidaidl.aidl;
public interface forActivity extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.example.androidaidl.aidl.forActivity
{
private static final java.lang.String DESCRIPTOR = "com.example.androidaidl.aidl.forActivity";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an com.example.androidaidl.aidl.forActivity interface,
 * generating a proxy if needed.
 */
public static com.example.androidaidl.aidl.forActivity asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.example.androidaidl.aidl.forActivity))) {
return ((com.example.androidaidl.aidl.forActivity)iin);
}
return new com.example.androidaidl.aidl.forActivity.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_performAction:
{
data.enforceInterface(DESCRIPTOR);
this.performAction();
reply.writeNoException();
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
private static class Proxy implements com.example.androidaidl.aidl.forActivity
{
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 void performAction() throws android.os.RemoteException
{
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_performAction, _data, _reply, 0);
_reply.readException();
}
finally {
_reply.recycle();
_data.recycle();
}
}
}
static final int TRANSACTION_performAction = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
}
public void performAction() throws android.os.RemoteException;
}

第二步,新建mAIDLActivity.java文件,它模擬Client , 新建mAIDLService.java文件,它模擬Server;

           先看看mAIDLActivity.java文件;

public class mAIDLActivity extends Activity {
	private static final String TAG = "AIDLActivity";
	private Button btnOk;
	private Button btnCancel;
	private Button btnCallBack;

	private void Log(String str) {
		android.util.Log.d(TAG, "------ " + str + "------");
	}
    
	@Override
	protected void onCreate(Bundle savedInstanceState) {
		// TODO Auto-generated method stub
		super.onCreate(savedInstanceState);
		setContentView(R.layout.main);
		btnOk = (Button) findViewById(R.id.btn_ok);
		btnCancel = (Button) findViewById(R.id.btn_cancel);
		btnCallBack = (Button) findViewById(R.id.btn_callback);
		btnOk.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
                          //綁定服務
			  Intent intent = new Intent(mAIDLActivity.this,mAIDLService.class);
			  bindService(intent, mcConnection, Context.BIND_AUTO_CREATE);
			  //startService(intent);
			}
		});
		btnCancel.setOnClickListener(new OnClickListener() {
			public void onClick(View v) {
                                //取消綁定
				unbindService(mcConnection);
				/*unbindService(mConnection);
				// stopService(intent);
*/			}
		});
		btnCallBack.setOnClickListener(new OnClickListener() {

			@Override
			public void onClick(View v) {
				try {
                                    //進程數據交互通訊
					mService.callBack();
				} catch (RemoteException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		});
	}
    forService mService;
    forActivity mActivity = new forActivity.Stub() {
		
		@Override
		public void perAction() throws RemoteException {
			Log("執行了啦");
		}

		@Override
		public void showString(int count) throws RemoteException {
			Log(count+"");
		}
		
	};
    
    ServiceConnection mcConnection = new ServiceConnection() {
		
		@Override
		public void onServiceDisconnected(ComponentName name) {
			
		}
		
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			mService = forService.Stub.asInterface(service);
			try {
				mService.registerTestCall(mActivity);
			} catch (RemoteException e) {

			}
		}
	};
}
這三個按鈕的作用我就不用說了吧,那麼明白的解釋在那裏還不懂的話,那你就別繼續看了,好好看看片,擼一管撤退吧。

先分析下上述文件

ServiceConnection mcConnection = new ServiceConnection() {
		
		@Override
		public void onServiceDisconnected(ComponentName name) {
			
		}
		
		@Override
		public void onServiceConnected(ComponentName name, IBinder service) {
			mService = forService.Stub.asInterface(service);
			try {
				mService.registerTestCall(mActivity);
			} catch (RemoteException e) {

			}
		}
	};
ServiceConnection的使用和介紹我上一篇博文已經說了,大家可以去看看,說實在的就是如果不是研究AIDL,這傢伙我估計都不會看到.

看這句代碼

mService = forService.Stub.asInterface(service);
如果直接看的話不看源碼,我第一想到的就是實例化?強轉,?一大堆不靠譜的邏輯,作爲一個裝逼程序猿,如果遇到不知道的情況,別瞎猜,看源碼纔是王道.來打開forService.文件
public interface forService extends android.os.IInterface
{
/** Local-side IPC implementation stub class. */
public static abstract class Stub extends android.os.Binder implements com.aidl.forService
{
private static final java.lang.String DESCRIPTOR = "com.aidl.forService";
/** Construct the stub at attach it to the interface. */
public Stub()
{
this.attachInterface(this, DESCRIPTOR);
}
/**
 * Cast an IBinder object into an com.aidl.forService interface,
 * generating a proxy if needed.
 */
public static com.aidl.forService asInterface(android.os.IBinder obj)
{
if ((obj==null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin!=null)&&(iin instanceof com.aidl.forService))) {
return ((com.aidl.forService)iin);
}
return new com.aidl.forService.Stub.Proxy(obj);
}

這裏我們發現,Stub是forService的內部靜態抽象類,並且是繼承Binder和實例化了接口forService. 查看方法adInterface中的實現,它分三步來判斷

 1,如果是空,直接給你空,讓你一邊玩去

  2,如果傳入的Ibinder對象就是com.aidl.forService,因爲forService的繼承的IInterface,看IInterface的介紹Base class for Binder interfaces. When defining a new interface, you must derive it from IInterface.那得列直接強轉成forService對象返回去,萬事大吉;
  3.如果爲空,那就new一個新的,對象嘛.程序猿從來不缺.

下面繼續分析mAIDLService文件.不多說,先看源碼

public class mAIDLService extends Service {
     
	@Override
	public IBinder onBind(Intent intent) {
		return mIBinder;
	}
	forActivity mActivity;
	int count=0;
	forService.Stub mIBinder  = new forService.Stub() {
		
		@Override
		public void registerTestCall(forActivity fa) throws RemoteException {
			mActivity = fa;
		}
		
		@Override
		public void callBack() throws RemoteException {
			mActivity.perAction();
			mActivity.showString(++count);
		}
	};
}

它這裏相對就簡單了,基本不用多說了吧,這裏要注意的就是
public IBinder onBind(Intent intent) {
		return mIBinder;
	}
它返回的是當前new出來的forService對象.也就是我們前面ServiceConnection回調拿到的IBinder,

那這裏就慢慢明朗了,整個相互間的通訊也就清楚了,當按下btnCallBack按鈕的時候,首先會調用forService中的callBack方法,而callBack方法的實現中又調用了forActivity的perAction.通過forActivity和forService的這次握手,就達到了mAIDLActivity和mAIDLService一直及時通訊

說到這裏有朋友跟我說ContentProvider就可以直接實現兩個應用間的數據傳遞了啊,爲什麼還要用AIDL,我轉頭一聲呵呵,我列出下面幾個區分點估計大家就明白了

1.ContentProvider是單向性的,不及時的,而AIDL是雙向性,及時的。就這麼來說吧。ContentProvider就好比你看到一個漂亮的妹子,你一直看着她,但是她卻對你無視,你看不清楚她身體的變化;AIDL就是你看到那個漂亮的妹子,她也看着,你下面的異樣,立即反饋給了她,而你也看到了她嘴邊的異樣,這比喻好理解嗎?哈哈哈

 好了中間有些地方如果有錯或者大家要補充的直接留言吧,然後懇請轉載的指明地址,不然又是一堆廢文到處跑。

下篇博文準備分析下IBinder和Binder!

參考網友論文

http://blog.csdn.net/saintswordsman/article/details/5130947

源碼下載

http://download.csdn.net/detail/eran12101030/7993485

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章