AIDL---Androidのリモートインタフェース(1)
より良いデザインAndroidソフトウェアはAIDL IPCメカニズムを熟知し、Windows ActiveX COMのようにより多重化され、Symbianのようなサーバメカニズムを提供することができます.サービスは、バックグラウンドでUIのないウィンドウを実行することをうまく解決します.私たちはandroid 123というaidlファイルを作成しました.aidlは、Android SDKドキュメントに変更されたサンプルコードです.
一、AIDLファイルの作成
package cn.com.android123;//導入宣言
import cn.com.android123.IAtmService;//インタフェースを宣言し、ここでは、銀行ATMプログラムinterface IBankAccountService{int getAccountBalance();//整数を返し、パラメータなしvoid setOwnerNames(in Listnames);//返さず、ListパラメータBankAccount createAccount(in String name,int startingDeposit,in IAtmService)を含む;//カスタムタイプint getCustomerList(in String branch,out String[]customerList);整形を返し、ブランチを入力し、顧客リストを出力します.
二、一つのインタフェースを実現する
クライアントにバインドを提供するエクスポートインタフェースが表示されます.
三、クライアントインタラクション
Android.osが提供するParcelableタイプはデータを伝達するために使用され、通常はEclipse+ADTプラグインを使用して完成し、EclipseでPackage Explorer viewビューを右クリックし、Create Aidl preprocess file for Parcelable classes(aidlプリコンパイルファイルの作成)を選択し、最終的にandroid 123という名前を作成する.aidlファイル
import android.os.Parcel;import android.os.Parcelable;public final class Rect implements Parcelable { public int left; public int top; public int right; public int bottom; public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { public Rect createFromParcel(Parcel in) { return new Rect(in); } public Rect[] newArray(int size) { return new Rect[size]; } }; public Rect() { } private Rect(Parcel in) { readFromParcel(in);}public void writeToParcel(Parcel out){//現在のデータをParcelに書き込むout.writeInt(left);out.writeInt(top);out.writeInt(right);out.writeInt(bottom);}public void readFromParcel(Parcel in){//Parcelからデータを読み込むleft=in.readInt();top=in.readInt();right=in.readInt();bottom=in.readInt(); }}
IPC呼び出し方式
一、AIDLファイルの作成
package cn.com.android123;//導入宣言
import cn.com.android123.IAtmService;//インタフェースを宣言し、ここでは、銀行ATMプログラムinterface IBankAccountService{int getAccountBalance();//整数を返し、パラメータなしvoid setOwnerNames(in List
二、一つのインタフェースを実現する
クライアントにバインドを提供するエクスポートインタフェースが表示されます.
public class RemoteService extends Service {
@Override
public IBinder onBind(Intent intent) {
if (IRemoteService.class.getName().equals(intent.getAction())) {
return mBinder;
}
if (ISecondary.class.getName().equals(intent.getAction())) {
return mSecondaryBinder;
}
return null;
}
//
private final IRemoteService.Stub mBinder = new IRemoteService.Stub() {
public void registerCallback(IRemoteServiceCallback cb) {
if (cb != null) mCallbacks.register(cb);
}
public void unregisterCallback(IRemoteServiceCallback cb) {
if (cb != null) mCallbacks.unregister(cb);
}
};
//
private final ISecondary.Stub mSecondaryBinder = new ISecondary.Stub() {
public int getPid() {
return Process.myPid();
}
public void basicTypes(int anInt, long aLong, boolean aBoolean,
float aFloat, double aDouble, String aString) {
}
};
}
三、クライアントインタラクション
Android.osが提供するParcelableタイプはデータを伝達するために使用され、通常はEclipse+ADTプラグインを使用して完成し、EclipseでPackage Explorer viewビューを右クリックし、Create Aidl preprocess file for Parcelable classes(aidlプリコンパイルファイルの作成)を選択し、最終的にandroid 123という名前を作成する.aidlファイル
import android.os.Parcel;import android.os.Parcelable;public final class Rect implements Parcelable { public int left; public int top; public int right; public int bottom; public static final Parcelable.Creator
IPC呼び出し方式
public class RemoteServiceBinding extends Activity {
/** The primary interface we will be calling on the service. */
IRemoteService mService = null;
/** Another interface we use on the service. */
ISecondary mSecondaryService = null;
Button mKillButton;
TextView mCallbackText;
private boolean mIsBound;
/**
* Standard initialization of this activity. Set up the UI, then wait
* for the user to poke it before doing anything.
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.remote_service_binding);
// Watch for button clicks.
Button button = (Button)findViewById(R.id.bind);
button.setOnClickListener(mBindListener);
button = (Button)findViewById(R.id.unbind);
button.setOnClickListener(mUnbindListener);
mKillButton = (Button)findViewById(R.id.kill);
mKillButton.setOnClickListener(mKillListener);
mKillButton.setEnabled(false);
mCallbackText = (TextView)findViewById(R.id.callback);
mCallbackText.setText("Not attached.");
}
/**
* Class for interacting with the main interface of the service.
*/
private ServiceConnection mConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
// This is called when the connection with the service has been
// established, giving us the service object we can use to
// interact with the service. We are communicating with our
// service through an IDL interface, so get a client-side
// representation of that from the raw service object.
mService = IRemoteService.Stub.asInterface(service);
mKillButton.setEnabled(true);
mCallbackText.setText("Attached.");
// We want to monitor the service for as long as we are
// connected to it.
try {
mService.registerCallback(mCallback);
} catch (RemoteException e) {
// In this case the service has crashed before we could even
// do anything with it; we can count on soon being
// disconnected (and then reconnected if it can be restarted)
// so there is no need to do anything here.
}
// As part of the sample, tell the user what happened.
Toast.makeText(RemoteServiceBinding.this, R.string.remote_service_connected,
Toast.LENGTH_SHORT).show();
}
public void onServiceDisconnected(ComponentName className) {
// This is called when the connection with the service has been
// unexpectedly disconnected -- that is, its process crashed.
mService = null;
mKillButton.setEnabled(false);
mCallbackText.setText("Disconnected.");
// As part of the sample, tell the user what happened.
Toast.makeText(RemoteServiceBinding.this, R.string.remote_service_disconnected,
Toast.LENGTH_SHORT).show();
}
};
/**
* Class for interacting with the secondary interface of the service.
*/
private ServiceConnection mSecondaryConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className,
IBinder service) {
// Connecting to a secondary interface is the same as any
// other interface.
mSecondaryService = ISecondary.Stub.asInterface(service);
mKillButton.setEnabled(true);
}
public void onServiceDisconnected(ComponentName className) {
mSecondaryService = null;
mKillButton.setEnabled(false);
}
};
private OnClickListener mBindListener = new OnClickListener() {
public void onClick(View v) {
// Establish a couple connections with the service, binding
// by interface names. This allows other applications to be
// installed that replace the remote service by implementing
// the same interface.
bindService(new Intent(IRemoteService.class.getName()),
mConnection, Context.BIND_AUTO_CREATE);
bindService(new Intent(ISecondary.class.getName()),
mSecondaryConnection, Context.BIND_AUTO_CREATE);
mIsBound = true;
mCallbackText.setText("Binding.");
}
};
private OnClickListener mUnbindListener = new OnClickListener() {
public void onClick(View v) {
if (mIsBound) {
// If we have received the service, and hence registered with
// it, then now is the time to unregister.
if (mService != null) {
try {
mService.unregisterCallback(mCallback);
} catch (RemoteException e) {
// There is nothing special we need to do if the service
// has crashed.
}
}
// Detach our existing connection.
unbindService(mConnection);
unbindService(mSecondaryConnection);
mKillButton.setEnabled(false);
mIsBound = false;
mCallbackText.setText("Unbinding.");
}
}
};
private OnClickListener mKillListener = new OnClickListener() {
public void onClick(View v) {
// To kill the process hosting our service, we need to know its
// PID. Conveniently our service has a call that will return
// to us that information.
if (mSecondaryService != null) {
try {
int pid = mSecondaryService.getPid();
// Note that, though this API allows us to request to
// kill any process based on its PID, the kernel will
// still impose standard restrictions on which PIDs you
// are actually able to kill. Typically this means only
// the process running your application and any additional
// processes created by that app as shown here; packages
// sharing a common UID will also be able to kill each
// other's processes.
Process.killProcess(pid);
mCallbackText.setText("Killed service process.");
} catch (RemoteException ex) {
// Recover gracefully from the process hosting the
// server dying.
// Just for purposes of the sample, put up a notification.
Toast.makeText(RemoteServiceBinding.this,
R.string.remote_call_failed,
Toast.LENGTH_SHORT).show();
}
}
}
};
// ----------------------------------------------------------------------
// Code showing how to deal with callbacks.
// ----------------------------------------------------------------------
/**
* This implementation is used to receive callbacks from the remote
* service.
*/
private IRemoteServiceCallback mCallback = new IRemoteServiceCallback.Stub() {
/**
* This is called by the remote service regularly to tell us about
* new values. Note that IPC calls are dispatched through a thread
* pool running in each process, so the code executing here will
* NOT be running in our main thread like most other things -- so,
* to update the UI, we need to use a Handler to hop over there.
*/
public void valueChanged(int value) {
mHandler.sendMessage(mHandler.obtainMessage(BUMP_MSG, value, 0));
}
};
private static final int BUMP_MSG = 1;
private Handler mHandler = new Handler() {
@Override public void handleMessage(Message msg) {
switch (msg.what) {
case BUMP_MSG:
mCallbackText.setText("Received from service: " + msg.arg1);
break;
default:
super.handleMessage(msg);
}
}