您现在的位置:首页 > >

android 精通IPC进程通信机制(三)(牛人高焕堂写的)


52

活用 Android 的 IPC 機制與 Binder 框架

????????????????????????????????????????????????????????????????????????????

第 3 章 IBinder 接口与 AIDL 机制

第3章

Activity

與 Service 的 IPC 通信機制

53

????????????????????????????????????????????????????????????????????????????



3



IBinder 接口 与 AIDL 机制

????????????

????????????

3.1 3.2 3.3

直接使用 IBinder 接口 自己撰写 Proxy/Stub 类别 使用 AIDL 方法

54

活用 Android 的 IPC 機制與 Binder 框架

????????????????????????????????????????????????????????????????????????????

3.1

直接使用 IBinder 接口

3.1.1 架构设计

前面两章介绍了典型的 IPC 框架是:

图 3-1

myActivity

直接調用 IBinder 接口的 transact()函数

在这图里,myActivity 直接使用 IBinder 接口里調用 myService 的功能。 当 myActivity 跨进程启动了 myService 时,这 myService 创建了小线程(及其 MQ):

第3章

Activity

與 Service 的 IPC 通信機制

55

????????????????????????????????????????????????????????????????????????????

图 3-2

myService

诞生小线程

然后,myService.onCreate()也创建 myBinder 对象:

56

活用 Android 的 IPC 機制與 Binder 框架

????????????????????????????????????????????????????????????????????????????

图 3-3 調用 myBinder()诞生对象 这 myService 調用了 myBinder()构造函数去诞生对象,此时 myBinder()調 用 Binder()构造函数。接着,Binder()构造函数調用 JNI 本地模块的 init()函数, 并将 myBinder 对象的指针传入到 JNI 本地模块,如下图:

第3章

Activity

與 Service 的 IPC 通信機制

57

????????????????????????????????????????????????????????????????????????????

图 3-4

Binder()

构造函数調用 JNI 本地程序

接下来,AMS(ActivityManagerService)调用 myService 的 onBind()函数, 回传了 myBinder 对象,就建立了 C/C++层的 JavaBBinder 对象:

58

活用 Android 的 IPC 機制與 Binder 框架

????????????????????????????????????????????????????????????????????????????

图 3-5 诞生 JavaBBinder 对象 于是,AMS 就传回 JavaBBinder 的 IBinder 接口给 myActivity。此时, myActivity 就能调用 IBinder 接口; 此时, 负责执行到 myBinder 的 onTransact() 函数的 BindThread 线程会送信息给 myService 里的小线程,由小线程去播放 mp3 音乐。

第3章

Activity

與 Service 的 IPC 通信機制

59

????????????????????????????????????????????????????????????????????????????

图 3-6

myBinder

传递讯息(Message)给 myService

在执行播放音乐的过程中, myService 里的小线程也会送讯息给 myActivity,将字符串显示于画面上:

60

活用 Android 的 IPC 機制與 Binder 框架

????????????????????????????????????????????????????????????????????????????

图 3-7

myService

里的小线程回送讯息给 myActivity

3.1.2 撰 写程序码

兹建立 Android 开发项目:

其 AndroidManifest.xml 文档的内容为:

第3章

Activity

與 Service 的 IPC 通信機制

61

????????????????????????????????????????????????????????????????????????????

// AndroidManifest.xml <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.misoo.pk01"> <application android:icon="@drawable/icon"> <activity android:name=".myActivity" android:label="@string/app_name"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> <service android:name=".myService" android:process=":remote"> <intent-filter> <action android:name="com.misoo.pk01.REMOTE_SERVICE" /> </intent-filter> </service> </application> </manifest>

此程序的执行画面如下:

62

活用 Android 的 IPC 機制與 Binder 框架

????????????????????????????????????????????????????????????????????????????

各源代码的档案为:
// myActivity.java package com.misoo.pk01; import android.app.Activity; import android.content.BroadcastReceiver; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.content.ServiceConnection; import android.os.Bundle; import android.os.IBinder; import android.os.Parcel; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; public class myActivity extends Activity implements OnClickListener { private final int WC = LinearLayout.LayoutParams.WRAP_CONTENT; private final int FP = LinearLayout.LayoutParams.FILL_PARENT; private Button btn, btn2, btn3; public TextView tv; private IBinder ib = null; private final String MY_S_EVENT = new String("com.misoo.pk01.myService.MY_S_EVENT"); protected final IntentFilter filter=new IntentFilter(MY_S_EVENT); private BroadcastReceiver receiver=new myIntentReceiver(); public void onCreate(Bundle icicle) { super.onCreate(icicle); LinearLayout layout = new LinearLayout(this); layout.setOrientation(LinearLayout.VERTICAL); btn = new Button(this); btn.setId(101);

第3章

Activity

與 Service 的 IPC 通信機制

63

????????????????????????????????????????????????????????????????????????????

btn.setText("play"); btn.setBackgroundResource(R.drawable.heart); btn.setOnClickListener(this); LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(80, 50); param.topMargin = 10; layout.addView(btn, param); btn2 = new Button(this); btn2.setId(102); btn2.setText("stop"); btn2.setBackgroundResource(R.drawable.heart); btn2.setOnClickListener(this); layout.addView(btn2, param); btn3 = new Button(this); btn3.setId(103); btn3.setText("exit"); btn3.setBackgroundResource(R.drawable.cloud); btn3.setOnClickListener(this); layout.addView(btn3, param); tv = new TextView(this); tv.setText("Ready"); LinearLayout.LayoutParams param2 = new LinearLayout.LayoutParams(FP, WC); param2.topMargin = 10; layout.addView(tv, param2); setContentView(layout); //--------------------------------registerReceiver(receiver, filter); //-----------------------------------------------------bindService(new Intent("com.misoo.pk01.REMOTE_SERVICE"), mConnection, Context.BIND_AUTO_CREATE); } private ServiceConnection mConnection = new ServiceConnection() { @Override public void onServiceConnected(ComponentName className, IBinder ibinder) { ib = ibinder; }

64

活用 Android 的 IPC 機制與 Binder 框架
@Override public void onServiceDisconnected(ComponentName name) { // TODO Auto-generated method stub } }; public void onClick(View v) { switch (v.getId()) { case 101: Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); try { ib.transact(1, data, reply, 0); } catch (Exception e) { e.printStackTrace(); } break; case 102: data = Parcel.obtain(); reply = Parcel.obtain(); try { ib.transact(2, data, reply, 0); } catch (Exception e) { e.printStackTrace(); } break; case 103: finish(); break; } } //---------------------------------------------------class myIntentReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { int bn = intent.getIntExtra("key",-1); if(bn == 0) tv.setText("Playing"); else tv.setText("Stop."); }

????????????????????????????????????????????????????????????????????????????

第3章
} }

Activity

與 Service 的 IPC 通信機制

65

????????????????????????????????????????????????????????????????????????????

// myService.java package com.misoo.pk01; import android.app.Service; import android.content.Context; import android.content.Intent; import android.media.MediaPlayer; import android.os.*; import android.util.Log;
public class myService extends Service implements Runnable { private IBinder mBinder = null; private Thread th1; public static Handler h; private MediaPlayer mPlayer = null; public static Context ctx; private final String MY_S_EVENT = new String("com.misoo.pk01.myService.MY_S_EVENT"); @Override public void onCreate() { super.onCreate(); ctx = this; mBinder = new myBinder(); //--------------------------------// MQ // Message //--------------------------------th1 = new Thread(this); th1.start(); } @Override public IBinder onBind(Intent intent) { return mBinder; }

诞生一个子线程及其 等待

public void run() { Looper.prepare();

66

活用 Android 的 IPC 機制與 Binder 框架
h = new EventHandler(Looper.myLooper()); Looper.loop(); } //--------------------------------------class EventHandler extends Handler { public EventHandler(Looper looper) { super(looper); } public void handleMessage(Message msg) { String obj = (String)msg.obj; if(obj.contains("play")) { if(mPlayer != null) return; //---------------------------------Intent in = new Intent(MY_S_EVENT); in.putExtra("key", 0); ctx.sendBroadcast(in); //---------------------------------mPlayer = MediaPlayer.create(ctx, R.raw.dreamed); try { mPlayer.start(); } catch (Exception e) { Log.e("Play", "error: " + e.getMessage(), e); } } else if(obj.contains("stop")) { if (mPlayer != null) { //---------------------------------Intent in = new Intent(MY_S_EVENT); in.putExtra("key", 1); ctx.sendBroadcast(in); //---------------------------------mPlayer.stop(); mPlayer.release(); mPlayer = null; } } }}}

????????????????????????????????????????????????????????????????????????????

第3章
// myBinder.java package com.misoo.pk01; import android.os.Binder; import android.os.Message; import android.os.Parcel;

Activity

與 Service 的 IPC 通信機制

67

????????????????????????????????????????????????????????????????????????????

public class myBinder extends Binder{ @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws android.os.RemoteException { switch(code){ case 1: // Message MQ to draw Graphic String obj = "play"; Message msg = myService.h.obtainMessage(1,1,1,obj); myService.h.sendMessage(msg); break; case 2: // Message MQ to stop drawing obj = "stop"; msg = myService.h.obtainMessage(1,1,1,obj); myService.h.sendMessage(msg); break; } return true; }}

将 将

丢到子线程的 丢到子线程的

3.2
3.2.1

自己撰写 Proxy/Stub 类别
架构设计

刚才的范例里, myActivity 直接使用 IBinder 接口来呼较远程的 myService 功能。在本节里,将自行撰写 Proxy-Stub 类别来将 IBinder 接口包装起来,让 App 与 IBinder 接口不再产生高度相依性,也简化 App 开发负担。例如:

68

活用 Android 的 IPC 機制與 Binder 框架

????????????????????????????????????????????????????????????????????????????

图 3-8 自己撰写 Proxy-Stub 类别 这 Proxy 提供较好用的 IA 接口给 Client 使用。而 Stub 类别则是屏蔽了 Binder 基类的 onTransact()函数,然后将 IA 接口里的 f1()和 f2()函数定义为抽 象函数。于是简化了 App 开发的负担:

第3章

Activity

與 Service 的 IPC 通信機制

69

????????????????????????????????????????????????????????????????????????????

图 3-9 简轻了 App 开发负担
3.2.2 范举(一 )

在这个范例里,定义了一个 IPlayer 接口,然后规划了 PlayerProxy 和 PlayerStub 两的类别,如下图:

70

活用 Android 的 IPC 機制與 Binder 框架

????????????????????????????????????????????????????????????????????????????

图 3-10 播放 MP3 的 Proxy/Stub 类别 于是,PlayerProxy 与 PlayerStub 两个类别遥遥相对了(因为它们分别摆在 跨进程 IPC 調用的两端)。兹写一个 App 来实现上图之结构。
<<

操作情境>> 此程序执行时,出现画面如下:

第3章

Activity

與 Service 的 IPC 通信機制

71

????????????????????????????????????????????????????????????????????????????

<<

撰写程序>> Step-1: 建立 Android 应用程序项目:

Step-2:

定义 IPlayer 接口。

// IPlayer.java package com.misoo.pkgx; public interface IPlayer { void play(); void stop(); String getStatus(); }

72

活用 Android 的 IPC 機制與 Binder 框架

????????????????????????????????????????????????????????????????????????????

Step-3:

撰写 mp3RemoteService 类。

// mp3RemoteService.java package com.misoo.pkgx; import android.app.Service; import android.content.Intent; import android.os.IBinder; public class mp3RemoteService extends Service { private IBinder mBinder = null; @Override public void onCreate() { mBinder = new PlayerAdapter(getApplicationContext()); } @Override public IBinder onBind(Intent intent) { return mBinder; } }

Step-4:

撰写 PlayerStub 类。

// PlayerStub.java package com.misoo.pkgx; import android.os.Binder; import android.os.Parcel; public abstract class PlayerStub extends Binder implements IPlayer{ @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws android.os.RemoteException { reply.writeString(data.readString()+ " mp3"); if(code == 1) this.play(); else if(code == 2) this.stop(); return true; } public abstract void play(); public abstract void stop(); public abstract String getStatus(); }

Step-5:

撰写 mp3Binder 类。

第3章
// mp3Binder.java package com.misoo.pkgx; import android.content.Context; import android.media.MediaPlayer; import android.util.Log;

Activity

與 Service 的 IPC 通信機制

73

????????????????????????????????????????????????????????????????????????????

public class mp3Binder extends PlayerStub{ private MediaPlayer mPlayer = null; private Context ctx; public mp3Binder(Context cx){ ctx= cx; } public void play(){ if(mPlayer != null) return; mPlayer = MediaPlayer.create(ctx, R.raw.test_cbr); try { mPlayer.start(); } catch (Exception e) { Log.e("StartPlay", "error: " + e.getMessage(), e); } } public void stop(){ if (mPlayer != null) { mPlayer.stop(); mPlayer.release(); mPlayer = null; } } public String getStatus() { return null; } }

Step-6:

撰写 ac01 类和 PlayerProxy 类(其提供 IPlayer 接口)。

// ac01.java package com.misoo.pkgx; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.graphics.Color; import android.os.Bundle; import android.os.IBinder; import android.os.Parcel; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button;

74

活用 Android 的 IPC 機制與 Binder 框架

????????????????????????????????????????????????????????????????????????????

import android.widget.LinearLayout; import android.widget.TextView; public class ac01 extends Activity implements OnClickListener { private final int WC = LinearLayout.LayoutParams.WRAP_CONTENT; private final int FP = LinearLayout.LayoutParams.FILL_PARENT; private Button btn, btn2, btn3; public TextView tv; private PlayerProxy pProxy = null; public void onCreate(Bundle icicle) { super.onCreate(icicle); LinearLayout layout = new LinearLayout(this); layout.setOrientation(LinearLayout.VERTICAL); btn = new Button(this); btn.setId(101); btn.setText(" play "); btn.setBackgroundResource(R.drawable.water); btn.setOnClickListener(this); LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(80, 50); param.topMargin = 10; layout.addView(btn, param);

btn2 = new Button(this); btn2.setId(102); btn2.setText(" stop "); btn2.setBackgroundResource(R.drawable.face); btn2.setOnClickListener(this); layout.addView(btn2, param); btn3 = new Button(this); btn3.setId(103); btn3.setText(" exit "); btn3.setBackgroundResource(R.drawable.earth); btn3.setOnClickListener(this); layout.addView(btn3, param); tv = new TextView(this); tv.setTextColor(Color.WHITE); tv.setText("Ready"); LinearLayout.LayoutParams param2 = new LinearLayout.LayoutParams(FP, WC); param2.topMargin = 10; layout.addView(tv, param2); setContentView(layout); startService(new Intent("com.misoo.pkgx.REMOTE_SERVICE")); bindService(new Intent("com.misoo.pkgx.REMOTE_SERVICE"), mConnection, Context.BIND_AUTO_CREATE); } private ServiceConnection mConnection = new ServiceConnection() {

第3章
{ pProxy = new PlayerProxy(ibinder);

Activity

與 Service 的 IPC 通信機制

75

????????????????????????????????????????????????????????????????????????????

public void onServiceConnected(ComponentName className, IBinder ibinder)

} public void onServiceDisconnected(ComponentName className) {} }; public void onClick(View v) { switch (v.getId()) { case 101: pProxy.play(); tv.setText(pProxy.getStatus()); break; case 102: pProxy.stop(); tv.setText(pProxy.getStatus()); break; case 103: unbindService(mConnection); stopService(new Intent("com.misoo.pkgx.REMOTE_SERVICE")); finish(); break; }} //----------------------------------------private class PlayerProxy implements IPlayer{ private IBinder ib; private String mStatus; PlayerProxy(IBinder ibinder){ ib = ibinder; } public void play(){ Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeString("playing"); try { ib.transact(1, data, reply, 0); mStatus = reply.readString(); } catch (Exception e) { e.printStackTrace(); } } public void stop(){ Parcel data = Parcel.obtain(); Parcel reply = Parcel.obtain(); data.writeString("stop"); try { ib.transact(2, data, reply, 0); mStatus = reply.readString(); } catch (Exception e) { e.printStackTrace(); } } public String getStatus() { return mStatus; } }}

<<

说明>>

76

活用 Android 的 IPC 機制與 Binder 框架
PlayerStub

????????????????????????????????????????????????????????????????????????????

类将 onTransact()函数隐藏起来,提供一个更具有美感、更亲 切的新接口给 mp3Binder 类使用。隐藏了 onTransact()函数之后,mp3Binder 类的开发者就不必费心去了解 onTransact() 函数了。于是, PlayerProxy 与 PlayerStub 两个类遥遥相对, 并且将 IPC 细节知识(例如 transact()和 onTransact() 函数之参数等)包夹起来。
3.2.3 范举(二 )

刚才的范例里,PlayerProxy 和 PlayerStub 是分别撰写在两个独立的文档 里。我们也可以将它们定义于同一个代码文档里。兹再看一个范例,也是基 于 Android 的 Activity 和 Service 框架基类,如下:

图 3-11

Android

框架里的常见基类

如果想提供较好用的 IA 接口,可设计 IA.Stub 类别,如下图:

第3章

Activity

與 Service 的 IPC 通信機制

77

????????????????????????????????????????????????????????????????????????????

图 3-12

IA.Stub

类别的角色

定义了 IA.Stub 类别之后,也可以定义 IA.Proxy 类别。其过程与上一个 范例是一致的,只是我们将把上述两个类别定义摆在同一个源代码档案里。

撰写程序>> Step-1: 建立 Android 应用程序项目:
<<

78

活用 Android 的 IPC 機制與 Binder 框架

????????????????????????????????????????????????????????????????????????????

定义 IA 接口。 // IA.java(接口)
Step-2:

package com.misoo.pk01; import android.os.Binder; import android.os.IBinder; import android.os.Parcel; import android.os.RemoteException; public interface IA { int f1(int x)throws RemoteException; public static abstract class Stub extends Binder implements IA { @Override public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws android.os.RemoteException{ int x = data.readInt(); int y = this.f1(x); reply.writeInt(y); return true; } public abstract int f1(int x) throws RemoteException; public static IA asInterface(IBinder obj){ return new Proxy(obj); } //--------------------------------------------private static class Proxy implements IA{ private IBinder mRemote; public Proxy(IBinder ibinder){ mRemote = ibinder; } public int f1(int x) throws RemoteException { // TODO Auto-generated method stub Parcel data = Parcel.obtain(); data.writeInt(x); Parcel reply = Parcel.obtain(); mRemote.transact(0, data, reply, 0); return reply.readInt();

第3章
} } } } // myService.java package com.misoo.pk01; import android.app.Service; import android.content.Intent; import android.os.IBinder; import android.os.RemoteException;

Activity

與 Service 的 IPC 通信機制

79

????????????????????????????????????????????????????????????????????????????

public class myService extends Service { @Override public IBinder onBind(Intent intent) { return mBinder; } public int mySf1(int x){ return x + 1000; } //--------------------------------------------private final IA.Stub mBinder = new IA.Stub() { @Override public int f1(int x) throws RemoteException { return mySf1(x); } }; }

// myActivity.java package com.misoo.pk01; import android.app.Activity; import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.graphics.Color; import android.os.Bundle; import android.os.IBinder;

80

活用 Android 的 IPC 機制與 Binder 框架

????????????????????????????????????????????????????????????????????????????

import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; import android.widget.LinearLayout; import android.widget.TextView; public class myActivity extends Activity implements OnClickListener { private final int WC = LinearLayout.LayoutParams.WRAP_CONTENT; private final int FP = LinearLayout.LayoutParams.FILL_PARENT; private Button btn, btn2; private TextView tv; private IA ia; private int state_var_A = 0; public void onCreate(Bundle icicle) { super.onCreate(icicle); if(state_var_A == 0){ show_layout_01(); goto_state_01(); } } private void show_layout_01(){ LinearLayout layout = new LinearLayout(this); layout.setOrientation(LinearLayout.VERTICAL); btn = new Button(this); btn.setBackgroundResource(R.drawable.heart); btn.setId(101); btn.setText("Run"); btn.setOnClickListener(this); LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(120, 55); param.topMargin = 10; layout.addView(btn, param); btn2 = new Button(this); btn2.setBackgroundResource(R.drawable.heart); btn2.setId(102); btn2.setText("Exit"); btn2.setOnClickListener(this); layout.addView(btn2, param); tv = new TextView(this); tv.setTextColor(Color.WHITE); tv.setText("");

第3章

Activity

與 Service 的 IPC 通信機制

81

????????????????????????????????????????????????????????????????????????????

LinearLayout.LayoutParams param2 = new LinearLayout.LayoutParams(FP, WC); param2.topMargin = 10; layout.addView(tv, param2); setContentView(layout); } private void goto_state_01(){ state_var_A = 1; bindService(new Intent("com.misoo.pk01.REMOTE_SERVICE"), mConnection, Context.BIND_AUTO_CREATE); } private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder ibinder) { ia = IA.Stub.asInterface(ibinder); } public void onServiceDisconnected(ComponentName className) { } }; public void onClick(View v) { int ret=0; switch(v.getId()){ case 101: if(state_var_A == 1){ try { ret = ia.f1(188); } catch (Exception e) { e.printStackTrace(); } tv.setText(String.valueOf(ret)); } break; case 102: if(state_var_A == 1) { stopService(new Intent("com.misoo.pk01.REMOTE_SERVICE")); finish(); } break; } }}

82

活用 Android 的 IPC 機制與 Binder 框架

????????????????????????????????????????????????????????????????????????????

3.3
AIDL

使用 AIDL

的目的是定义 Proxy/Stub 来封装 IBinder 接口,以便产生更亲切贴心 的新接口。所以,在 App 里可以选择使用 IBinder 接口,也可以使用 AIDL 来 定义出新接口。由于 IBinder 接口只提供单一函数(即 transact()函数)来进行远 距通信,調用起来比较不方便。所以 Android 提供 aidl.exe 工具来协助产出 Proxy 和 Stub 类,以化解这个困难。

架构设计>> 此范例使用 Android-SDK 的/tools/里的 aidl.exe 工具程序,根据接口定义 档(如下述的 mp3PlayerInterface.aidl)而自动产出 Proxy 及 Stub 类,其结构如 下:
<<

3.3.1

范例

第3章

Activity

與 Service 的 IPC 通信機制

83

????????????????????????????????????????????????????????????????????????????

图 3-10

AIDL

的源代码架构

藉由开发工具自动产出 Proxy 及 Stub 类的程序码,再分别转交给 ac01 和

84

活用 Android 的 IPC 機制與 Binder 框架

????????????????????????????????????????????????????????????????????????????

开发者。于是,ac01 和 mp3Binder 两端的开发者都不必具备 IPC 的知识,因而两者皆能享受到「不知而亦能用」之美好效益。
mp3Binder <<

操作情境>> 此程序执行时,出现画面如下:

撰写程序>> Step-1: 建立 Android 应用程序项目:
<<

Step-2:

定义 mp3PlayerInterface 接口(含 Proxy 和 Stub 类)。

// mp3PlayerInterface.aidl package com.misoo.pkaz; interface mp3PlayerInterface { void play();

第3章
void stop(); }

Activity

與 Service 的 IPC 通信機制

85

????????????????????????????????????????????????????????????????????????????

使用 Android-SDK 所含的 aidl.exe 工具,将上述的 mp3PlayerInterface.aidl 档翻译成为下述的 mp3PlayerInterface.java 档案。
// mp3PlayerInterface.java /* * This file is auto-generated. DO NOT MODIFY. * Original file: mp3PlayerInterface.aidl */ package com.misoo.pkgx; import java.lang.String; import android.os.RemoteException; import android.os.IBinder; import android.os.IInterface; import android.os.Binder; import android.os.Parcel; public interface mp3PlayerInterface extends android.os.IInterface { /** Local-side IPC implementation stub class. */ public static abstract class Stub extends android.os.Binder implements com.misoo.pkgx.mp3PlayerInterface { private static final java.lang.String DESCRIPTOR = "com.misoo.pkaz.mp3PlayerInterface"; /** Construct the stub at attach it to the interface. */ public Stub() { this.attachInterface(this, DESCRIPTOR); } /** * Cast an IBinder object into an mp3PlayerInterface interface, * generating a proxy if needed. */ public static com.misoo.pkgx.mp3PlayerInterface asInterface(android.os.IBinder obj) { if ((obj==null)) { return null;

86

活用 Android 的 IPC 機制與 Binder 框架

????????????????????????????????????????????????????????????????????????????

} com.misoo.pkgx.mp3PlayerInterface in = (com.misoo.pkgx.mp3PlayerInterface)obj.queryLocalInterface(DESCRIPTOR); if ((in!=null)) { return in; } return new com.misoo.pkgx.mp3PlayerInterface.Stub.Proxy(obj); } public android.os.IBinder asBinder() { return this; } 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_play: { data.enforceInterface(DESCRIPTOR); this.play(); reply.writeNoException(); return true; } case TRANSACTION_stop: { data.enforceInterface(DESCRIPTOR); this.stop(); reply.writeNoException(); return true; } } return super.onTransact(code, data, reply, flags); } private static class Proxy implements com.misoo.pkgx.mp3PlayerInterface {

第3章

Activity

與 Service 的 IPC 通信機制

87

????????????????????????????????????????????????????????????????????????????

private android.os.IBinder mRemote; Proxy(android.os.IBinder remote) { mRemote = remote; } public android.os.IBinder asBinder() { return mRemote; } public java.lang.String getInterfaceDescriptor() { return DESCRIPTOR; } public void play() 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_play, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } } public void stop() 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_stop, _data, _reply, 0); _reply.readException(); } finally { _reply.recycle(); _data.recycle(); } }

88

活用 Android 的 IPC 機制與 Binder 框架

????????????????????????????????????????????????????????????????????????????

} static final int TRANSACTION_play = (IBinder.FIRST_CALL_TRANSACTION + 0); static final int TRANSACTION_stop = (IBinder.FIRST_CALL_TRANSACTION + 1); } public void play() throws android.os.RemoteException; public void stop() throws android.os.RemoteException; }

从表面上看来,此 mp3PlayerInterface.java 是蛮复杂的,其实它的结构是 清晰又简单的,只要对于类继承、反向調用和接口等对象导向观念必须有足 够的认识,就很容易理解了。
Step-3:

撰写 mp3Service 类别。

// mp3Service.java package com.misoo.pkgx; import android.app.Service; import android.content.Intent; import android.os.IBinder; public class mp3Service extends Service { IBinder ib = null; @Override public void onCreate() { super.onCreate(); ib = new mp3Binder(this.getApplicationContext()); } @Override public void onDestroy() { } @Override public IBinder onBind(Intent intent) { return ib; } }

Step-4:

撰写 mp3Binder 类别。

// mp3Binder.java package com.misoo.pkgx; import android.content.Context; import android.media.MediaPlayer; import android.util.Log;

第3章

Activity

與 Service 的 IPC 通信機制

89

????????????????????????????????????????????????????????????????????????????

public class mp3Binder extends mp3PlayerInterface.Stub{ private MediaPlayer mPlayer = null; private Context ctx; public mp3Binder(Context cx){ ctx= cx; } public void play(){ if(mPlayer != null) return; mPlayer = MediaPlayer.create(ctx, R.raw.test_cbr); try { mPlayer.start(); } catch (Exception e) { Log.e("StartPlay", "error: " + e.getMessage(), e); } } public void stop(){ if (mPlayer != null) { mPlayer.stop(); mPlayer.release(); mPlayer = null; } } }

Step-5:

撰写 myButton 类别。

// myButton.java package com.misoo.pkgx; import android.content.Context; import android.widget.Button; public class myButton extends Button{ public myButton(Context ctx){ super(ctx); super.setBackgroundResource(R.drawable.byw); } public int get_width(){ return 90; } public int get_height(){ return 50; } }

Step-6:

撰写 ac01 类。

// ac01.java package com.misoo.pkgx; import android.app.Activity; import android.content.ComponentName;

90

活用 Android 的 IPC 機制與 Binder 框架

????????????????????????????????????????????????????????????????????????????

import android.content.Context; import android.content.Intent; import android.content.ServiceConnection; import android.graphics.Color; import android.os.Bundle; import android.os.IBinder; import android.os.RemoteException; import android.view.View; import android.view.View.OnClickListener; import android.widget.LinearLayout; import android.widget.TextView; public class ac01 extends Activity implements OnClickListener { private final int WC = LinearLayout.LayoutParams.WRAP_CONTENT; private final int FP = LinearLayout.LayoutParams.FILL_PARENT; private mp3PlayerInterface mp3_interface = null; private myButton btn, btn2, btn3; public TextView tv; public void onCreate(Bundle icicle) { super.onCreate(icicle); LinearLayout layout = new LinearLayout(this); layout.setOrientation(LinearLayout.VERTICAL); btn = new myButton(this); btn.setId(101); btn.setText("play"); btn.setOnClickListener(this); LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(btn.get_width(), btn.get_height()); param.topMargin = 10; layout.addView(btn, param); btn2 = new myButton(this); btn2.setId(102); btn2.setText("stop"); btn2.setOnClickListener(this); layout.addView(btn2, param); btn3 = new myButton(this); btn3.setId(103); btn3.setText("exit"); btn3.setOnClickListener(this); layout.addView(btn3, param); tv = new TextView(this); tv.setTextColor(Color.WHITE); tv.setText("Ready"); LinearLayout.LayoutParams param2 = new LinearLayout.LayoutParams(FP, WC); param2.topMargin = 10; layout.addView(tv, param2); setContentView(layout);

第3章

Activity

與 Service 的 IPC 通信機制

91

????????????????????????????????????????????????????????????????????????????

//-----------------------------------------------------------------------------startService(new Intent("com.misoo.pkgx.REMOTE_SERVICE")); bindService(new Intent("com.misoo.pkgx.REMOTE_SERVICE"), mConnection, Context.BIND_AUTO_CREATE); } private ServiceConnection mConnection = new ServiceConnection() { public void onServiceConnected(ComponentName className, IBinder ibinder) { mp3_interface = mp3PlayerInterface.Stub.asInterface(ibinder); //setTitle("service connected."); } public void onServiceDisconnected(ComponentName className) {} }; public void onClick(View v) { switch(v.getId()){ case 101: tv.setText("play..."); try { mp3_interface.play(); } catch (RemoteException e) { e.printStackTrace(); } break; case 102: tv.setText("stop."); try { mp3_interface.stop(); } catch (RemoteException e) { e.printStackTrace(); } break; case 103: unbindService(mConnection); stopService(new Intent("com.misoo.pkgx.REMOTE_SERVICE")); finish(); break; }}}

<<

说明>> 对于 Anrdoid 的初学者而言, Android 的 AIDL 机制可说是最难弄懂的。 希望本章能带给你清晰的思路◆



热文推荐
友情链接: 大学学习资料 人文社科 经营营销资料 工程资料大全 IT文档 自然科学