奔跑的肥猪

导航

IPC 调用示例

这几天看了高焕堂关于

高焕堂——Android框架底层结构知多少?

http://www.android1.net/Topic.aspx?BoardID=11&TopicID=703

看看人家写的东西和大陆这边的文章还是有一些差距。拿了高先生的代码自己编译了一下,有所收获。特将代码贴出。

Android中一个app就是一个process,那么跨process如何通讯呢?答案是IPC,但是自己在模拟器上测试了了一下,

感觉速度还是挺慢的。以下几点应该注意以下:

1. 注册remote process,在androidmenifest.xml中测试远程服务:

	<service android:name="com.fp.app.service.FPService" android:process=":remote">
			<intent-filter>
				<action android:name="com.fp.app.service.FPService" />
			</intent-filter>
       </service>

其中

<action android:name="com.fp.app.service.FPService" /> 为client段调用的名称,你可以定义多个remote process,只要保证 intent filter中名称不一样即可。
2. 如果启动了多个remote process,在启动另外之前,应该将前面的process ubind.
super.unbindService(mConnection);
否则,会抛出如下错误:
I/ActivityManager(  583): Stopping service: com.fp.app.readbinder/com.fp.app.service.myService
E/ActivityThread(  868): Activity com.fp.app.readbinder.IPCSyncActivity has leaked ServiceConnection com.fp.app.readbinder.IPCSyncActivity$2@4373599
E/ActivityThread(  868): android.app.ServiceConnectionLeaked: Activity com.fp.app.readbinder.IPCSyncActivity has leaked ServiceConnection com.fp.app
E/ActivityThread(  868):        at android.app.ActivityThread$PackageInfo$ServiceDispatcher.<init>(ActivityThread.java:886)
E/ActivityThread(  868):        at android.app.ActivityThread$PackageInfo.getServiceDispatcher(ActivityThread.java:781)
E/ActivityThread(  868):        at android.app.ApplicationContext.bindService(ApplicationContext.java:820)
E/ActivityThread(  868):        at android.content.ContextWrapper.bindService(ContextWrapper.java:307)
E/ActivityThread(  868):        at com.fp.app.readbinder.IPCSyncActivity.bindService(IPCSyncActivity.java:48)
E/ActivityThread(  868):        at com.fp.app.readbinder.IPCSyncActivity.onCreate(IPCSyncActivity.java:41)
E/ActivityThread(  868):        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1123)
E/ActivityThread(  868):        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2231)
E/ActivityThread(  868):        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2284)
E/ActivityThread(  868):        at android.app.ActivityThread.access$1800(ActivityThread.java:112)
E/ActivityThread(  868):        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1692)
E/ActivityThread(  868):        at android.os.Handler.dispatchMessage(Handler.java:99)
E/ActivityThread(  868):        at android.os.Looper.loop(Looper.java:123)
E/ActivityThread(  868):        at android.app.ActivityThread.main(ActivityThread.java:3948)
E/ActivityThread(  868):        at java.lang.reflect.Method.invokeNative(Native Method)
E/ActivityThread(  868):        at java.lang.reflect.Method.invoke(Method.java:521)
E/ActivityThread(  868):        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:782)
E/ActivityThread(  868):        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:540)
E/ActivityThread(  868):        at dalvik.system.NativeStart.main(Native Method)
W/ActivityManager(  583): Unbind failed: could not find connection for android.os.BinderProxy@436f90f0
E/ActivityThread(  868): Activity com.fp.app.readbinder.IPCSyncActivity has leaked ServiceConnection com.fp.app.readbinder.IPCSyncActivity$1@4373598
E/ActivityThread(  868): android.app.ServiceConnectionLeaked: Activity com.fp.app.readbinder.IPCSyncActivity has leaked ServiceConnection com.fp.app
E/ActivityThread(  868):        at android.app.ActivityThread$PackageInfo$ServiceDispatcher.<init>(ActivityThread.java:886)
E/ActivityThread(  868):        at android.app.ActivityThread$PackageInfo.getServiceDispatcher(ActivityThread.java:781)
E/ActivityThread(  868):        at android.app.ApplicationContext.bindService(ApplicationContext.java:820)
E/ActivityThread(  868):        at android.content.ContextWrapper.bindService(ContextWrapper.java:307)
E/ActivityThread(  868):        at com.fp.app.readbinder.IPCSyncActivity.bindService(IPCSyncActivity.java:46)
E/ActivityThread(  868):        at com.fp.app.readbinder.IPCSyncActivity.onCreate(IPCSyncActivity.java:41)
E/ActivityThread(  868):        at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1123)
E/ActivityThread(  868):        at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2231)
E/ActivityThread(  868):        at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2284)
E/ActivityThread(  868):        at android.app.ActivityThread.access$1800(ActivityThread.java:112)
E/ActivityThread(  868):        at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1692)
E/ActivityThread(  868):        at android.os.Handler.dispatchMessage(Handler.java:99)
E/ActivityThread(  868):        at android.os.Looper.loop(Looper.java:123)
E/ActivityThread(  868):        at android.app.ActivityThread.main(ActivityThread.java:3948)
E/ActivityThread(  868):        at java.lang.reflect.Method.invokeNative(Native Method)
E/ActivityThread(  868):        at java.lang.reflect.Method.invoke(Method.java:521)
E/ActivityThread(  868):        at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:782)
E/ActivityThread(  868):        at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:540)
E/ActivityThread(  868):        at dalvik.system.NativeStart.main(Native Method)
W/ActivityManager(  583): Unbind failed: could not find connection for android.os.BinderProxy@436f6ba8
3. 是否process启动,可以通过ddms观察状态,画红线部分为新的remote process.一般一个process会启动3个或者3个以下thread 进行ipc通讯.

废话少说,可以通过下面的代码进行体会:
package com.fp.app.debug;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;

import android.util.Log;

public class DebugLog {
	public final static boolean DEBUG = false;

	public static void log(String message) {
		if (true) {
			String fullClassName = Thread.currentThread().getStackTrace()[3].getClassName();
			String className = fullClassName.substring(fullClassName.lastIndexOf(".") + 1);
			String methodName = Thread.currentThread().getStackTrace()[3].getMethodName();
			int lineNumber = Thread.currentThread().getStackTrace()[3].getLineNumber();

			Log.d(className + "." + methodName + "():" + lineNumber, message);
		}
	}
	
	
	public static void printThreadId(String message) {
		if (DEBUG) {
			Log.d(message, String.valueOf(Thread.currentThread().getId()));
		}
	}

	public static void log(String tag, String message) {
		if (DEBUG) {
			String methodName = Thread.currentThread().getStackTrace()[3].getMethodName();
			int lineNumber = Thread.currentThread().getStackTrace()[3].getLineNumber();

			Log.d(tag + "." + methodName + "():" + lineNumber, message);
		}
	}

	public static void printTrace(String message) {
		if (DEBUG) {
			printIllegalArgumentException("", message);
		}
	}

	public static String getStackTrace(Throwable throwable) {
		Writer writer = new StringWriter();
		PrintWriter printWriter = new PrintWriter(writer);
		throwable.printStackTrace(printWriter);
		return writer.toString();
	}

	public static void printIllegalArgumentException(String tag, String arg) {
		if (DEBUG) {
			final Throwable throwable = new IllegalArgumentException(arg);
			Log.w(tag, arg, throwable);
		}
	}

}
package com.fp.app.readbinder;

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;
import android.widget.LinearLayout;
import android.widget.TextView;

public class IPCSyncActivity extends Activity implements OnClickListener {
	@Override
	protected void onDestroy() {
		super.unbindService(mConnection);
		super.unbindService(mConnection2);
		super.onDestroy();
	}

	private static final int BTNTOPMARGIN = 10;
	private static final int BTNHEIGHT = 50;
	private static final int BTNWIDTH = 120;
	private static final String STREXIT = "exit";
	private static final String STRBINDSERVICE1 = "bind service connection 1";
	private static final String STRBINDSERVICE2 = "bind service connection 2";
	private static final int EXIT = 104;
	private static final int BINDSERVICE = 102;
	private static final int STARTSERVICE = 101;
	private final int WC = LinearLayout.LayoutParams.WRAP_CONTENT;
	private final int FP = LinearLayout.LayoutParams.FILL_PARENT;
	private Button btnBindService1, btnBindService2, btnExit;
	public TextView headerText;
	private IBinder mBinder1, mBinder2;

	public void onCreate(Bundle icicle) {
		super.onCreate(icicle);
		LinearLayout layout = new LinearLayout(this);
		layout.setOrientation(LinearLayout.VERTICAL);
		setView(layout);
		String tna = Thread.currentThread().getName();
		Thread.currentThread().setName(tna + "-ac01");
		bindService();
	}

	private void bindService() {
		bindService(new Intent("com.fp.app.service.myService"), mConnection, Context.BIND_AUTO_CREATE);
		bindService(new Intent("com.fp.app.service.myService"), mConnection2, Context.BIND_AUTO_CREATE);
	}

	private void setView(LinearLayout layout) {
		setBtn(layout, btnBindService1, STRBINDSERVICE1, STARTSERVICE);
		setBtn(layout, btnBindService2, STRBINDSERVICE2, BINDSERVICE);
		setBtn(layout, btnExit, STREXIT, EXIT);
		setTv(layout);

	}

	private void setBtn(LinearLayout layout, Button btn, String text, int resId) {
		btn = new Button(this);
		btn.setId(resId);
		btn.setText(text);
		btn.setBackgroundResource(R.drawable.music_play);
		btn.setOnClickListener(this);
		layout.addView(btn, getPara());
	}

	private void setTv(LinearLayout layout) {
		headerText = new TextView(this);
		headerText.setTextColor(Color.WHITE);
		headerText.setText("");
		LinearLayout.LayoutParams tvParam = new LinearLayout.LayoutParams(FP, WC);
		tvParam.topMargin = BTNTOPMARGIN;
		layout.addView(headerText, tvParam);
		setContentView(layout);
	}

	private LinearLayout.LayoutParams getPara() {
		LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(BTNWIDTH, BTNHEIGHT);
		param.topMargin = BTNTOPMARGIN;
		return param;
	}

	public void onClick(View v) {
		switch (v.getId()) {
		case STARTSERVICE:
			onTransaction1();
			break;
		case BINDSERVICE:
			onTransaction2();
			break;
		case EXIT:
			finish();
			break;
		}
	}

	private ServiceConnection mConnection = new ServiceConnection() {
		public void onServiceConnected(ComponentName className, IBinder ibinder) {
			mBinder1 = ibinder;
		}

		public void onServiceDisconnected(ComponentName className) {
		}
	};
	private ServiceConnection mConnection2 = new ServiceConnection() {
		public void onServiceConnected(ComponentName className, IBinder ibinder) {
			mBinder2 = ibinder;
		}

		public void onServiceDisconnected(ComponentName className) {
		}
	};

	private void onTransaction2() {
		Parcel pc = Parcel.obtain();
		Parcel pc_reply = Parcel.obtain();
		try {
			mBinder2.transact(1, pc, pc_reply, 0);
			headerText.setText(pc_reply.readString());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void onTransaction1() {
		Parcel p = Parcel.obtain();
		Parcel p_reply = Parcel.obtain();
		try {
			mBinder1.transact(0, p, p_reply, 0);
			headerText.setText(p_reply.readString());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
}
package com.fp.app.readbinder;

import com.fp.app.debug.DebugLog;

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;
import android.widget.LinearLayout;
import android.widget.TextView;

public class mainActivity extends Activity implements OnClickListener {
	@Override
	protected void onDestroy() {
		super.unbindService(mConnection);
		super.onDestroy();
	}

	private static final int BTNTOPMARGIN = 10;
	private static final int BTNHEIGHT = 50;
	private static final int BTNWIDTH = 120;
	private static final String STRIPCSYNC = "transfer to ipc sync";
	private static final String STREXIT = "exit";
	private static final String STRIPCCALL = "ipc call";
	private static final String STRBINDSERVICE = "bind service";
	private static final String STRSTARTSERVICE = "start service";
	private static final int IPCSYNC = 105;
	private static final int EXIT = 104;
	private static final int IPCCALL = 103;
	private static final int BINDSERVICE = 102;
	private static final int STARTSERVICE = 101;
	private final int WC = LinearLayout.LayoutParams.WRAP_CONTENT;
	private final int FP = LinearLayout.LayoutParams.FILL_PARENT;
	private Button btnStartService, btnBindService, btnIPCCall, btnExit,btnTransferTOIPCSync;
	public TextView headerText;
	private IBinder mBinder = null;

	public void onCreate(Bundle icicle) {
		super.onCreate(icicle);
		LinearLayout layout = new LinearLayout(this);
		layout.setOrientation(LinearLayout.VERTICAL);
		setView(layout);
		String tna = Thread.currentThread().getName();
		Thread.currentThread().setName(tna + "-ac01");
	}

	private void setView(LinearLayout layout) {
		setBtn(layout, btnStartService, STRSTARTSERVICE, STARTSERVICE);
		setBtn(layout, btnBindService, STRBINDSERVICE, BINDSERVICE);
		setBtn(layout, btnIPCCall, STRIPCCALL, IPCCALL);
		setBtn(layout, btnExit, STREXIT, EXIT);
		setBtn(layout, btnTransferTOIPCSync, STRIPCSYNC, IPCSYNC);
		setTv(layout);

	}

	private void setBtn(LinearLayout layout, Button btn, String text, int resId) {
		btn = new Button(this);
		btn.setId(resId);
		btn.setText(text);
		btn.setBackgroundResource(R.drawable.music_play);
		btn.setOnClickListener(this);
		layout.addView(btn, getPara());
	}

	private void setTv(LinearLayout layout) {
		headerText = new TextView(this);
		headerText.setTextColor(Color.WHITE);
		headerText.setText("");
		LinearLayout.LayoutParams tvParam = new LinearLayout.LayoutParams(FP, WC);
		tvParam.topMargin = BTNTOPMARGIN;
		layout.addView(headerText, tvParam);
		setContentView(layout);
	}

	private LinearLayout.LayoutParams getPara() {
		LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(BTNWIDTH, BTNHEIGHT);
		param.topMargin = BTNTOPMARGIN;
		return param;
	}

	private ServiceConnection mConnection = new ServiceConnection() {
		public void onServiceConnected(ComponentName className, IBinder ibinder) {
			mBinder = ibinder;
		}

		public void onServiceDisconnected(ComponentName className) {
		}
	};

	public void onClick(View v) {
		switch (v.getId()) {
		case STARTSERVICE:
			startService();
			break;
		case BINDSERVICE:
			bindService();
			break;
		case IPCCALL:
			transact();
			break;
		case EXIT:
			finish();
			break;
		case IPCSYNC:
			transfer();
			break;
		}
	}

	private void transfer() {
		Intent targetIntent = new Intent(this, IPCSyncActivity.class);
		startActivity(targetIntent);
	}

	private void transact() {
		DebugLog.printTrace("transact");
		Parcel pc = Parcel.obtain();
		pc.writeString("budoudou");
		Parcel pc_reply = Parcel.obtain();
		try {
			mBinder.transact(1, pc, pc_reply, 0);
			headerText.setText(pc_reply.readString());
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	private void bindService() {
		bindService(new Intent("com.fp.app.service.FPService"), mConnection, Context.BIND_AUTO_CREATE);
		DebugLog.printTrace("bindService");
	}

	private void startService() {
		startService(new Intent("com.fp.app.service.FPService"));
		DebugLog.printTrace("startService");
	}
}
package com.fp.app.readbinder;

import com.fp.app.debug.DebugLog;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.TextView;

public class subActivity extends Activity implements OnClickListener {
	private final int WC = LinearLayout.LayoutParams.WRAP_CONTENT;
	private final int FP = LinearLayout.LayoutParams.FILL_PARENT;
	private Button btn;
	public TextView tv;

	public void onCreate(Bundle icicle) {
		super.onCreate(icicle);
		LinearLayout layout = new LinearLayout(this);
		layout.setOrientation(LinearLayout.VERTICAL);
		setBtn(layout);
		setTV(layout);
	}

	private void setTV(LinearLayout layout) {
		tv = new TextView(this);
		tv.setTextColor(Color.WHITE);
		tv.setText("");
		LinearLayout.LayoutParams param2 = new LinearLayout.LayoutParams(FP, WC);
		param2.topMargin = 10;
		layout.addView(tv, param2);
		setContentView(layout);
		DebugLog.printTrace("onCreate");
		tv.setText(Thread.currentThread().getName() + "-myActivity");
	}

	private void setBtn(LinearLayout layout) {
		btn = new Button(this);
		btn.setId(101);
		btn.setText("exit");
		btn.setBackgroundResource(R.drawable.music_play);
		btn.setOnClickListener(this);
		LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(120, 50);
		param.topMargin = 10;
		layout.addView(btn, param);
	}

	public void onClick(View v) {
		switch (v.getId()) {
		case 101:
			finish();
			break;
		}
	}
}
package com.fp.app.service;

import com.fp.app.debug.DebugLog;
import com.fp.app.readbinder.subActivity;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;

public class FPService extends Service {
	private IBinder mBinder = null;

	@Override
	public void onCreate() {
		Thread.currentThread().setName(Thread.currentThread().getName() + "-onCreate");
		mBinder = new myBinder();
		DebugLog.printTrace("service onCreate");
	}

	@Override
	public void onStart(Intent intent, int startId) {
		Thread.currentThread().setName(Thread.currentThread().getName() + "-onStart");
		Intent i = new Intent(getApplicationContext(), subActivity.class);
		i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		getApplicationContext().startActivity(i);
		DebugLog.printTrace("service onStart");
	}

	@Override
	public IBinder onBind(Intent intent) {
		Thread.currentThread().setName(Thread.currentThread().getName() + "-onBind");
		Intent in = new Intent(this.getApplicationContext(), subActivity.class);
		in.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
		startActivity(in);
		DebugLog.printTrace("service onBind");
		return mBinder;
	}

	public class myBinder extends Binder {

		public myBinder() {
			Thread.currentThread().setName(Thread.currentThread().getName() + "-myBinder");
		}

		@Override
		public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws android.os.RemoteException {
			DebugLog.log(data.readString());
			reply.writeString(Thread.currentThread().getName());		
			DebugLog.printTrace("onTransact");
			return true;
		}
	}
}
package com.fp.app.service;

import android.app.Service;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.os.Parcel;

public class myService extends Service {
	private static int count = 0;

	public IBinder onBind(Intent intent) {
		count++;
		return new myBinder();
	}

	public class myBinder extends Binder {
		private int value = 0;


		public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws android.os.RemoteException {
			if (code == 0) {
				value += 5;
				try {
					Thread.sleep(8000);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			} else if (code == 1)
				value += 300;
			reply.writeString(" count:" + String.valueOf(count) + " value:" + String.valueOf(value));
			return true;
		}
	}
}
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
	package="com.fp.app.readbinder">
	<application android:icon="@drawable/icon">
		<activity android:name=".mainActivity" android:label="@string/app_name">
			<intent-filter>
				<action android:name="android.intent.action.MAIN" />
				<category android:name="android.intent.category.LAUNCHER" />
			</intent-filter>
		</activity>
		<activity android:name=".IPCSyncActivity" />
		<activity android:name=".subActivity" android:process=":remote">
		</activity>
		<service android:name="com.fp.app.service.FPService" android:process=":remote">
			<intent-filter>
				<action android:name="com.fp.app.service.FPService" />
			</intent-filter>
		</service>
	   <service android:name="com.fp.app.service.myService" android:process=":remote">
			<intent-filter>
				<action android:name="com.fp.app.service.myService" />
			</intent-filter>
		</service>

	</application>
</manifest>

posted on 2011-07-11 17:24  布兜兜  阅读(768)  评论(0编辑  收藏  举报