Android AIDL -通過一個比較完整的Demo快速運用
前端時間專案運用到AIDL,關於AIDL客戶端以及AIDL服務端網路上沒有一個比較完備的Demo.
而參考Demo無疑是一個比較快速的學習方法.因此,我寫了一個Demo.
供大家參考,也非常歡迎大家對其中寫的不好的地方進行指正.
好了,首先簡述下基本功能:
在AIDL 客戶端三個EditText中輸入三個值,點選提交按鈕,將這三個值傳入到AIDL服務端進行處理.
服務端處理後會執行客戶端的回撥函式:在AIDL客戶端介面進行重新整理,並顯示一個toast.
接下來看看程式碼結構:
需要注意的是,兩個工程中com.harlan.demo.aidl包內部的檔案必須保持一致.
(1)HarlanInfo.java:這是包中唯一的一個java檔案,是一個數據結構,該類實現了Parcelable介面
package com.harlan.demo.aidl; import android.os.Parcel; import android.os.Parcelable; /** * * <一句話功能簡述> * Parcelable是Android特有的功能,效率比實現Serializable介面高 * * @author Administrator * @version [版本號, 2012-12-10] * @see [相關類/方法] * @since [產品/模組版本] */ public class HarlanInfo implements Parcelable { private String name; private int age; private String place; public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getPlace() { return place; } public void setPlace(String place) { this.place = place; } /** * <預設建構函式> */ public HarlanInfo() { } /** * <預設建構函式> */ public HarlanInfo(Parcel in) { //注意順序 name = in.readString(); age = in.readInt(); place = in.readString(); } /** * seems meaningless * return 0; */ @Override public int describeContents() { return 0; } /** * 將物件序列化為一個Parcel物件 * 可以將Parcel看成是一個流,通過writeToParcel把物件寫到流裡面, * 再通過createFromParcel從流裡讀取物件 * 注意:寫的順序和讀的順序必須一致。 */ @Override public void writeToParcel(Parcel dest, int flags) { dest.writeString(name); dest.writeInt(age); dest.writeString(place); } /** * 例項化靜態內部物件CREATOR實現介面Parcelable.Creator * public static final一個都不能少,內部物件CREATOR的名稱也不能改變,必須全部大寫 */ public static final Parcelable.Creator<HarlanInfo> CREATOR = new Creator<HarlanInfo>(){ //將Parcel物件反序列化為HarlanInfo @Override public HarlanInfo createFromParcel(Parcel source) { HarlanInfo hlInfo = new HarlanInfo(source); return hlInfo; } @Override public HarlanInfo[] newArray(int size) { return new HarlanInfo[size]; } }; }
(2)HarlanInfo.aidl :協同HarlanInfo.java檔案"作戰",缺一不可.
package com.harlan.demo.aidl;
parcelable HarlanInfo;
(3)ICallBack.aidl:
這是客戶端回撥方法的介面,在客戶端實現其具體方法,在服務端呼叫執行.
package com.harlan.demo.aidl; interface ICallBack{ /** *callback of AIDLClient *handle by server **/ void handleByServer(String param); }
(4)ExecuteService.aidl:
這是從服務端獲取資料方法的介面,在服務端實現其具體方法,在客戶端呼叫執行.
引數info是由使用者輸入的資料構成的,同時傳遞的還要客戶端回撥方法的控制代碼,從而服務端可以呼叫客戶端的回撥方法.
該方法返回一個HarlanInfo的資料型別,客戶端獲得此資料,在介面上進行相應的顯示.
package com.harlan.demo.aidl;
import com.harlan.demo.aidl.HarlanInfo;
import com.harlan.demo.aidl.ICallBack;
interface ExecuteServiceAIDL
{
/**
*get info from server and
*Transfer a callback methods handle;
*if occur error ,will be return null
*對於非基本資料型別和String和CharSequence型別,要加上方向指示
*包括in、out和inout,in表示由客戶端設定,out表示由服務端設定,inout是兩者均可設定。
*/
HarlanInfo getServerHarlanInfo(in HarlanInfo info,ICallBack icallback);
}
好了,現在對com.harlan.demo.aidl包已經大致瞭解,build一下project,發現gen資料夾下面多出來一個包:
包中檔案可以隨便看看,不看也沒事.因為你只要在客戶端服務端相應的位置實現對應的介面就可以了.
先來看看服務端,因為服務端相對簡單些,不需要介面什麼的,只是一個Service.
上程式碼:
package com.harlan.demo.service;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;
import com.harlan.demo.aidl.ExecuteServiceAIDL;
import com.harlan.demo.aidl.HarlanInfo;
import com.harlan.demo.aidl.ICallBack;
public class AIDLService extends Service
{
public static final String TAG = "AIDLService";
private ICallBack mCallBack;
/**
* 繫結服務
*/
@Override
public IBinder onBind(Intent intent)
{
// TODO Auto-generated method stub
return mBinder;
}
/**
* 建立服務
*/
@Override
public void onCreate()
{
super.onCreate();
}
/**
* 銷燬服務
*/
@Override
public void onDestroy()
{
super.onDestroy();
}
/**
* 啟動服務
*/
@Override
public void onStart(Intent intent, int startId)
{
super.onStart(intent, startId);
}
/**
* 解綁服務
*/
@Override
public boolean onUnbind(Intent intent)
{
mCallBack = null;
return super.onUnbind(intent);
}
ExecuteServiceAIDL.Stub mBinder = new ExecuteServiceAIDL.Stub()
{
//這裡實現了getServiceHarlanInfo介面
@Override
public HarlanInfo getServerHarlanInfo(HarlanInfo info, ICallBack icallback)
throws RemoteException
{
Log.d(TAG,"getServerHarlanInfo");
mCallBack = icallback;
mCallBack.handleByServer("The msg is from server");
HarlanInfo newInfo = new HarlanInfo();
newInfo.setName(info.getName().toLowerCase());
newInfo.setAge(info.getAge() + 10);
newInfo.setPlace("Home");
return newInfo;
}
};
}
一目瞭然,服務端主要的功能就是實現了aidl中的getServerHarlanInfo(HarlanInfo info, ICallBack icallback)介面.返回了一個mBinder供客戶端呼叫.
寫好了服務,還得在Manifest檔案裡面配置一下:
<service
android:name=".AIDLService">
<intent-filter>
<action android:name="com.harlan.demo.aidl.service"/>
</intent-filter>
</service>
服務端寫好了,就來客戶端的了.客戶端主要是一個activity,介面相對簡單,如圖所示:
介面佈局相對簡單,就不貼程式碼了.
下面貼ClientActivity的程式碼:
package com.harlan.demo.activity;
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.os.RemoteException;
import android.util.Log;
import android.view.View;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;
import com.harlan.demo.aidl.ExecuteServiceAIDL;
import com.harlan.demo.aidl.HarlanInfo;
import com.harlan.demo.aidl.ICallBack;
public class ClientActivity extends Activity
{
public static final String TAG = "ClientActivity";
private static final String BIND_ACTION = "com.harlan.demo.aidl.service";
private EditText mEditTextName;
private EditText mEditTextAge;
private EditText mEditTextPlace;
private Button mButtonCommit;
private ExecuteServiceAIDL executeService;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_client);
getView();
//使用者點選提交按鈕,將資料傳至服務端進行處理
mButtonCommit.setOnClickListener(new View.OnClickListener()
{
@Override
public void onClick(View v)
{
//繫結服務
getServiceConnect();
}
});
}
private void getView()
{
mEditTextName = (EditText)findViewById(R.id.editText_name);
mEditTextAge = (EditText)findViewById(R.id.editText_age);
mEditTextPlace = (EditText)findViewById(R.id.editText_place);
mButtonCommit = (Button)findViewById(R.id.button_commit);
}
private void getServiceConnect()
{
Intent it = new Intent();
it.setAction(BIND_ACTION);
startService(it);
bindService(it, mserviceConnection, BIND_AUTO_CREATE);
}
ServiceConnection mserviceConnection = new ServiceConnection()
{
@Override
public void onServiceDisconnected(ComponentName name)
{
Log.d(TAG, "onServiceDisconnected");
}
@Override
public void onServiceConnected(ComponentName name, IBinder service)
{
Log.d(TAG, "onServiceConnected");
//獲取服務端傳過來的IBinder物件,通過該物件呼叫服務端的方法
executeService = ExecuteServiceAIDL.Stub.asInterface(service);
if (executeService != null)
{
handlerInfo();
}
}
};
private void handlerInfo()
{
String mName;
int mAge;
String mPlace;
if (mEditTextName.getText().toString().equals(""))
{
mEditTextName.setText("Harlan");
mName = "Harlan";
}
else
{
mName = mEditTextName.getText().toString();
}
if (mEditTextAge.getText().toString().equals(""))
{
mAge = 22;
}
else
{
mAge = Integer.parseInt(mEditTextAge.getText().toString());
}
if (mEditTextPlace.getText().toString().equals(""))
{
mPlace = "Nanjing";
}
else
{
mPlace = mEditTextPlace.getText().toString();
}
HarlanInfo mInfo = new HarlanInfo();
mInfo.setName(mName);
mInfo.setAge(mAge);
mInfo.setPlace(mPlace);
try
{
HarlanInfo serverInfo = new HarlanInfo();
//呼叫服務端的方法
serverInfo = executeService.getServerHarlanInfo(mInfo, mCallBack);
//更新介面
mEditTextName.setText(serverInfo.getName());
mEditTextAge.setText(String.valueOf(serverInfo.getAge()));
mEditTextPlace.setText(serverInfo.getPlace());
unbindService(mserviceConnection);
}
catch (RemoteException e)
{
e.printStackTrace();
}
}
ICallBack.Stub mCallBack = new ICallBack.Stub()
{
//客戶端回撥方法的具體實現
@Override
public void handleByServer(String param)
throws RemoteException
{
Toast.makeText(getApplicationContext(), param, Toast.LENGTH_LONG).show();
}
};
}
服務端呼叫客戶端回撥方法,在介面上顯示一個toast.客戶端根據服務端傳回來的資料,重新整理介面.
最後執行結果如圖所示: