行是知之始,知是行之成。这篇文章主要讲述Android Binder机制完全解析相关的知识,希望能为你提供帮助。
概述 之前我写过一篇文章Android Service全面解析,
简单实现了如何通过AIDL实现Service的跨进程通信(
IPC)
,
其实是通过Binder机制来实现的,
本文我们就重点来看看Binder机制的原理。
Binder可以提供系统中任何程序都可以访问的全局服务。这个功能当然是任何系统都应该提供的,
下面我们简单看一下android的Binder的框架:
Android Binder框架分为服务器接口、Binder驱动、以及客户端接口;
简单想一下,
需要提供一个全局服务,
那么全局服务那端即是服务器接口,
任何程序即客户端接口,
它们之间通过一个Binder驱动访问。
- 服务器接口: 实际上是Binder类的对象, 该对象一旦创建, 内部则会启动一个隐藏线程, 接收Binder驱动发送的消息, 收到消息后, 会执行Binder对象中的onTransact()函数, 并按照该函数的参数执行不同的服务器端代码。
- Binder驱动: 该对象也为Binder类的实例, 客户端通过该对象访问远程服务。
- 客户端接口: 获得Binder驱动, 调用其transact()发送消息至服务器。
( 1) Studio创建两个Module, app代表客户端程序, binder_server代表服务器端程序。
文章图片
( 2) 创建aidl文件
在app目录上右键, NEW-> AIDL-> AIDL File, 创建一个aidl文件( IMyAidlInterface.aidl) , 同时必须要指明包名, 包名必须和java目录下的包名一致。此aidl文件会默认生成到aidl目录下, aidl目录和java目录同级别。
文章图片
IMyAidlInterface.aidl文件内容:
interface IMyAidlInterface {
int plus(int a, int b);
String toUpperCase(String str);
}
build一下, 会自动生成IMyAidlInterface.java文件, 不同于Eclipse的gen目录, studio下的java文件目录为:
* (项目名)\\app\\build\\generated\\source\\aidl\\debug\\com\\hx\\binder\\IMyAidlInterface.java
关于IMyAidlInterface.java文件内容, 我们后面会具体分析, 这里先省略。
( 3) 将aidl文件连同目录一起拷贝到服务器端
文章图片
【Android Binder机制完全解析】( 4) 服务器端新建服务MyRemoteService
public class MyRemoteService extends Service {@
Override
public void onCreate() {
super.onCreate();
MainActivity.showlog("
onCreate()"
);
}@
Override
public int onStartCommand(Intent intent, int flags, int startId) {
MainActivity.showlog("
onStartCommand()"
);
return super.onStartCommand(intent, flags, startId);
}@
Override
public void onDestroy() {
super.onDestroy();
MainActivity.showlog("
onDestroy()"
);
}@
Override
public IBinder onBind(Intent intent) {
MainActivity.showlog("
onBind()"
);
return mBinder;
}@
Override
public boolean onUnbind(Intent intent) {
MainActivity.showlog("
onUnbind()"
);
return super.onUnbind(intent);
}IMyAidlInterface.Stub mBinder =
new IMyAidlInterface.Stub() {
@
Override
public String toUpperCase(String str) throws RemoteException {
if (str !=
null) {
return str.toUpperCase();
}
return null;
}@
Override
public int plus(int a, int b) throws RemoteException {
return a +
b;
}
};
}
在Manifest中进行注册:
<
service android:name=
"
.MyRemoteService"
android:exported=
"
true"
>
<
intent-filter>
<
action android:name=
"
com.hx.action.remoteService"
/>
<
/intent-filter>
<
/service>
( 4) 编写客户端代码
public class MainActivity extends Activity implements View.OnClickListener {private Button bindService;
private Button unbindService;
private Button plus;
private Button toUpperCase;
private IMyAidlInterface myAIDLInterface;
private ServiceConnection connection =
new ServiceConnection() {
@
Override
public void onServiceDisconnected(ComponentName name) {
myAIDLInterface =
null;
Toast.makeText(MainActivity.this, "
onServiceDisconnected"
, Toast.LENGTH_SHORT).show();
}@
Override
public void onServiceConnected(ComponentName name, IBinder service) {
myAIDLInterface =
IMyAidlInterface.Stub.asInterface(service);
Toast.makeText(MainActivity.this, "
onServiceConnected"
, Toast.LENGTH_SHORT).show();
}
};
@
Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindService =
(Button) findViewById(R.id.bind_service);
unbindService =
(Button) findViewById(R.id.unbind_service);
plus =
(Button) findViewById(R.id.plus);
toUpperCase =
(Button) findViewById(R.id.toUpperCase);
//button点击事件
bindService.setOnClickListener(this);
unbindService.setOnClickListener(this);
plus.setOnClickListener(this);
toUpperCase.setOnClickListener(this);
}@
Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bind_service:
Intent intent =
new Intent("
com.hx.action.remoteService"
);
//5.0以上安卓设备,
service intent必须为显式指出
Intent eintent =
new Intent(getExplicitIntent(this,intent));
bindService(eintent, connection, Context.BIND_AUTO_CREATE);
//bindService(intent, connection, BIND_AUTO_CREATE);
break;
case R.id.unbind_service:
if(myAIDLInterface !=
null){
unbindService(connection);
}
break;
case R.id.plus:
if (myAIDLInterface !=
null) {
try {
int result =
myAIDLInterface.plus(13, 19);
Toast.makeText(this, result +
"
"
, Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
} else {
Toast.makeText(this, "
服务器被异常杀死,
请重新绑定服务端"
, Toast.LENGTH_SHORT).show();
}
break;
case R.id.toUpperCase:
if (myAIDLInterface !=
null) {
try {
String upperStr =
myAIDLInterface.toUpperCase("
hello aidl service"
);
Toast.makeText(this, upperStr +
"
"
, Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
}
} else {
Toast.makeText(this, "
服务器被异常杀死,
请重新绑定服务端"
, Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
}public static Intent getExplicitIntent(Context context, Intent implicitIntent) {
// Retrieve all services that can match the given intent
PackageManager pm =
context.getPackageManager();
List<
ResolveInfo>
resolveInfo =
pm.queryIntentServices(implicitIntent, 0);
// Make sure only one match was found
if (resolveInfo =
=
null || resolveInfo.size() !=
1) {
return null;
}
// Get component info and create ComponentName
ResolveInfo serviceInfo =
resolveInfo.get(0);
String packageName =
serviceInfo.serviceInfo.packageName;
String className =
serviceInfo.serviceInfo.name;
ComponentName component =
new ComponentName(packageName, className);
// Create a new intent. Use the old one for extras and such reuse
Intent explicitIntent =
new Intent(implicitIntent);
// Set the component to be explicit
explicitIntent.setComponent(component);
return explicitIntent;
}
}
<
?xml version=
"
1.0"
encoding=
"
utf-8"
?>
<
LinearLayout xmlns:android=
"
http://schemas.android.com/apk/res/android"
android:id=
"
@
+
id/activity_main"
android:layout_width=
"
match_parent"
android:layout_height=
"
match_parent"
android:paddingBottom=
"
@
dimen/activity_vertical_margin"
android:paddingLeft=
"
@
dimen/activity_horizontal_margin"
android:paddingRight=
"
@
dimen/activity_horizontal_margin"
android:paddingTop=
"
@
dimen/activity_vertical_margin"
android:orientation=
"
vertical"
>
<
Button
android:id=
"
@
+
id/bind_service"
android:layout_width=
"
match_parent"
android:layout_height=
"
wrap_content"
android:text=
"
bind service"
/>
<
Button
android:id=
"
@
+
id/unbind_service"
android:layout_width=
"
match_parent"
android:layout_height=
"
wrap_content"
android:text=
"
unbind service"
/>
<
Button
android:id=
"
@
+
id/plus"
android:layout_width=
"
match_parent"
android:layout_height=
"
wrap_content"
android:text=
"
13 +
19"
/>
<
Button
android:id=
"
@
+
id/toUpperCase"
android:layout_width=
"
match_parent"
android:layout_height=
"
wrap_content"
android:textAllCaps=
"
false"
android:text=
"
hello aidl service"
/>
<
/LinearLayout>
运行程序, 看效果:
文章图片
我们首先点击BIND SERVICE按钮, 绑定服务, 会弹出“onServiceConnected”的Toast, 说明服务绑定成功, 获取到了服务器端的Binder驱动。
服务端Log:
文章图片
然后分别点击13+ 19和hello aidl service按钮, 可以通过Binder驱动调用服务端的代码并返回正确的计算结果。
最后点击UNBIND SERVICE按钮, 我们的期望是弹出“onServiceDisconnected”的Toast, 解除绑定, 实际上呢? 很遗憾没有弹出。
服务端Log:
文章图片
由于我们当前只有一个客户端绑定了此Service, 所以Service调用了onUnbind和onDestory。当我们继续点击13+ 19按钮, 发现依然可以正确执行得到结果, 也就是说即使onUnbind被调用, 连接也是不会断开的, 那么什么时候会断开连接呢?
即当服务端被异常终止的时候, 比如我们现在在手机的正在执行的程序中找到该服务, 并强行停止它:
文章图片
可以看到这时弹出了“onServiceDisconnected”的Toast, 说明连接被断开。之后再次点击13+ 19按钮, 则会弹出Toast提示“服务器被异常杀死, 请重新绑定服务端”。
原理分析 还记得我们上面根据aidl文件生成的Java文件吗? 我们来看看它的结构吧:
public interface IMyAidlInterface extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.hx.binder.IMyAidlInterface {
private static final java.lang.String DESCRIPTOR =
"
com.hx.binder.IMyAidlInterface"
;
/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}/**
* Cast an IBinder object into an com.hx.binder.IMyAidlInterface interface,
* generating a proxy if needed.
*/
public static com.hx.binder.IMyAidlInterface asInterface(android.os.IBinder obj) {
if ((obj =
=
null)) {
return null;
}
android.os.IInterface iin =
obj.queryLocalInterface(DESCRIPTOR);
if (((iin !=
null) &
&
(iin instanceof com.hx.binder.IMyAidlInterface))) {
return ((com.hx.binder.IMyAidlInterface) iin);
}
return new com.hx.binder.IMyAidlInterface.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_plus: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 =
data.readInt();
int _arg1;
_arg1 =
data.readInt();
int _result =
this.plus(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_toUpperCase: {
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 =
data.readString();
java.lang.String _result =
this.toUpperCase(_arg0);
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}private static class Proxy implements com.hx.binder.IMyAidlInterface {
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 int plus(int a, int b) throws android.os.RemoteException {
android.os.Parcel _data =
android.os.Parcel.obtain();
android.os.Parcel _reply =
android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(a);
_data.writeInt(b);
mRemote.transact(Stub.TRANSACTION_plus, _data, _reply, 0);
_reply.readException();
_result =
_reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}@
Override
public java.lang.String toUpperCase(java.lang.String str) throws android.os.RemoteException {
android.os.Parcel _data =
android.os.Parcel.obtain();
android.os.Parcel _reply =
android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString(str);
mRemote.transact(Stub.TRANSACTION_toUpperCase, _data, _reply, 0);
_reply.readException();
_result =
_reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}static final int TRANSACTION_plus =
(android.os.IBinder.FIRST_CALL_TRANSACTION +
0);
static final int TRANSACTION_toUpperCase =
(android.os.IBinder.FIRST_CALL_TRANSACTION +
1);
}public int plus(int a, int b) throws android.os.RemoteException;
public java.lang.String toUpperCase(java.lang.String str) throws android.os.RemoteException;
}
代码比较长, 但思路还是比较清晰的, IMyAidlInterface.java文件包含两个静态内部类—Stub和Proxy( 其中Proxy是Stub的内部类) 。
public static abstract class Stub extends android.os.Binder implements com.hx.binder.IMyAidlInterface
其中Stub是个抽象类, 它继承了Binder, 并实现了IMyAidlInterface接口。Stub提供了几个方法: asInterface、asBinder、onTransact, 但并没有实现IMyAidlInterface接口的方法, 所以需要交给Stub的实现类去实现。
private static class Proxy implements com.hx.binder.IMyAidlInterface
Proxy是Stub的内部类, 也实现了IMyAidlInterface接口。并提供了几个方法: asBinder、getInterfaceDescriptor, 并实现了IMyAidlInterface接口的方法plus和toUpperCase。
接下来看看服务端和客户端是如何和这个文件建立关联的吧。
服务端:
IMyAidlInterface.Stub mBinder =
new IMyAidlInterface.Stub() {
@
Override
public String toUpperCase(String str) throws RemoteException {
if (str !=
null) {
return str.toUpperCase();
}
return null;
}@
Override
public int plus(int a, int b) throws RemoteException {
return a +
b;
}
};
可以看到我们服务端提供的服务是由IMyAidlInterface.Stub来执行的, 上面分析过, Stub这个类是Binder的子类, 是不是符合我们文章开头所说的服务端其实是一个Binder类的实例。而且mBinder实现了IMyAidlInterface接口的方法。
接下来看Stub的onTransact()方法:
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_plus: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 =
data.readInt();
int _arg1;
_arg1 =
data.readInt();
int _result =
this.plus(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_toUpperCase: {
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 =
data.readString();
java.lang.String _result =
this.toUpperCase(_arg0);
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}
文章开头也说到服务端的Binder实例会根据客户端依靠Binder驱动发来的消息, 执行onTransact方法, 然后由其参数决定执行服务端的代码。
可以看到onTransact有四个参数: code , data , replay , flags
- code: 是一个整形的唯一标识, 用于区分执行哪个方法, 客户端会传递此参数, 告诉服务端执行哪个方法
- data: 客户端传递过来的参数
- reply: 服务器返回回去的值
- flags: 标明是否有返回值, 0为有( 双向) , 1为没有( 单向)
data.enforceInterface(DESCRIPTOR);
与客户端的writeInterfaceToken对应, 标识远程服务的名称
int _arg0;
_arg0 =
data.readInt();
int _arg1;
_arg1 =
data.readInt();
接下来分别读取了客户端传入的两个参数
int _result =
this.plus(_arg0, _arg1);
reply.writeNoException();
reply.writeInt(_result);
然后执行this.plus, 即我们服务端实现的plus方法; 返回result由reply写回。
toUpperCase同理, 可以看到服务端通过AIDL生成的Stub类, 封装了服务端本来需要写的代码。
客户端
客户端主要通过ServiceConnected与服务端连接
private ServiceConnection connection =
new ServiceConnection() {
@
Override
public void onServiceDisconnected(ComponentName name) {
isConnected =
false;
Toast.makeText(MainActivity.this, "
onServiceDisconnected"
, Toast.LENGTH_SHORT).show();
}@
Override
public void onServiceConnected(ComponentName name, IBinder service) {
isConnected =
true;
myAIDLInterface =
IMyAidlInterface.Stub.asInterface(service);
Toast.makeText(MainActivity.this, "
onServiceConnected"
, Toast.LENGTH_SHORT).show();
}
};
其实这个onServiceConnected中的IBinder实例, 其实就是我们文章开头所说的Binder驱动, 也是一个Binder实例。
在IMyAidlInterface.Stub.asInterface中最终调用了:
return new com.hx.binder.IMyAidlInterface.Stub.Proxy(obj);
这个Proxy实例传入了我们的Binder驱动, 并且封装了我们调用服务端的代码, 文章开头说, 客户端会通过Binder驱动的transact()方法调用服务端代码。
直接看Proxy中的plus方法
public int plus(int a, int b) throws android.os.RemoteException {
android.os.Parcel _data =
android.os.Parcel.obtain();
android.os.Parcel _reply =
android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(a);
_data.writeInt(b);
mRemote.transact(Stub.TRANSACTION_plus, _data, _reply, 0);
_reply.readException();
_result =
_reply.readInt();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
首先声明两个Parcel对象, 一个用于传递数据, 一个用户接收返回的数据
_data.writeInterfaceToken(DESCRIPTOR);
与服务器端的enforceInterfac对应
_data.writeInt(a);
_data.writeInt(b);
写入需要传递的参数
mRemote.transact(Stub.TRANSACTION_plus, _data, _reply, 0);
终于看到了我们的transact方法, 第一个对应服务端的code,_data,_reply分别对应服务端的data, reply, 0表示是双向的
_reply.readException();
_result =
_reply.readInt();
最后读出我们服务端返回的数据, 然后return。可以看到和服务端的onTransact基本是一行一行对应的。
注意:
- 当客户端调用transact方法发起RPC( 远程过程调用) 请求后, 当前线程会挂起, 等待服务器端的返回结果。所以如果一个远程方法很耗时, 那么不能再UI线程中调用此远程方法。
- 服务端的Binder方法( onTransact) 运行在Binder线程池中, 所以Binder方法不管是否耗时, 都应该采取同步机制, 因为它已经运行在一个线程中了。
AIDL其实通过我们写的aidl文件, 帮助我们生成了一个接口, 一个Stub类用于服务端, 一个Proxy类用于客户端调用。
文章图片
不依赖AIDL实现IPC通信 那么我们是否可以不通过写aidl文件来实现远程的通信呢? 下面向大家展示如何完全不依赖AIDL来实现客户端与服务端的通信。
服务端代码:
public class MyRemoteService extends Service {
private static final String DESCRIPTOR =
"
MyRemoteService"
;
private static final int TRANSACTION_plus =
0x110;
private static final int TRANSACTION_toUpperCase =
0x111;
@
Override
public void onCreate() {
super.onCreate();
MainActivity.showlog("
onCreate()"
);
}@
Override
public int onStartCommand(Intent intent, int flags, int startId) {
MainActivity.showlog("
onStartCommand()"
);
return super.onStartCommand(intent, flags, startId);
}@
Override
public void onDestroy() {
super.onDestroy();
MainActivity.showlog("
onDestroy()"
);
}@
Override
public IBinder onBind(Intent intent) {
MainActivity.showlog("
onBind()"
);
return mBinder;
}@
Override
public boolean onUnbind(Intent intent) {
MainActivity.showlog("
onUnbind()"
);
return super.onUnbind(intent);
}private MyBinder mBinder =
new MyBinder();
private class MyBinder extends Binder {
@
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_plus: {
data.enforceInterface(DESCRIPTOR);
int _arg0;
_arg0 =
data.readInt();
int _arg1;
_arg1 =
data.readInt();
int _result =
_arg0 +
_arg1;
reply.writeNoException();
reply.writeInt(_result);
return true;
}
case TRANSACTION_toUpperCase: {
data.enforceInterface(DESCRIPTOR);
java.lang.String _arg0;
_arg0 =
data.readString();
java.lang.String _result =
_arg0.toUpperCase();
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}};
}
<
service android:name=
"
.MyRemoteService"
android:exported=
"
true"
>
<
intent-filter>
<
action android:name=
"
com.hx.action.remoteService"
/>
<
/intent-filter>
<
/service>
客户端代码:
public class MainActivity extends Activity implements View.OnClickListener {
private Button bindService;
private Button unbindService;
private Button plus;
private Button toUpperCase;
private IBinder myBinder;
private static final String DESCRIPTOR =
"
MyRemoteService"
;
private static final int TRANSACTION_plus =
0x110;
private static final int TRANSACTION_toUpperCase =
0x111;
private ServiceConnection connection =
new ServiceConnection() {
@
Override
public void onServiceDisconnected(ComponentName name) {
myBinder =
null;
Toast.makeText(MainActivity.this, "
onServiceDisconnected"
, Toast.LENGTH_SHORT).show();
}@
Override
public void onServiceConnected(ComponentName name, IBinder service) {
myBinder =
service;
Toast.makeText(MainActivity.this, "
onServiceConnected"
, Toast.LENGTH_SHORT).show();
}
};
@
Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
bindService =
(Button) findViewById(R.id.bind_service);
unbindService =
(Button) findViewById(R.id.unbind_service);
plus =
(Button) findViewById(R.id.plus);
toUpperCase =
(Button) findViewById(R.id.toUpperCase);
//button点击事件
bindService.setOnClickListener(this);
unbindService.setOnClickListener(this);
plus.setOnClickListener(this);
toUpperCase.setOnClickListener(this);
}@
Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.bind_service:
Intent intent =
new Intent("
com.hx.action.remoteService"
);
//5.0以上安卓设备,
service intent必须为显式指出
Intent eintent =
new Intent(getExplicitIntent(this,intent));
bindService(eintent, connection, Context.BIND_AUTO_CREATE);
//bindService(intent, connection, BIND_AUTO_CREATE);
break;
case R.id.unbind_service:
if(myBinder !=
null){
unbindService(connection);
}
break;
case R.id.plus:
if (myBinder !=
null) {
android.os.Parcel _data =
android.os.Parcel.obtain();
android.os.Parcel _reply =
android.os.Parcel.obtain();
int _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeInt(78);
_data.writeInt(95);
myBinder.transact(TRANSACTION_plus, _data, _reply, 0);
_reply.readException();
_result =
_reply.readInt();
Toast.makeText(this, _result +
"
"
, Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
} finally {
_reply.recycle();
_data.recycle();
}
} else {
Toast.makeText(this, "
服务器被异常杀死,
请重新绑定服务端"
, Toast.LENGTH_SHORT).show();
}
break;
case R.id.toUpperCase:
if (myBinder !=
null) {
android.os.Parcel _data =
android.os.Parcel.obtain();
android.os.Parcel _reply =
android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
_data.writeString("
my new programe"
);
myBinder.transact(TRANSACTION_toUpperCase, _data, _reply, 0);
_reply.readException();
_result =
_reply.readString();
Toast.makeText(this, _result +
"
"
, Toast.LENGTH_SHORT).show();
} catch (RemoteException e) {
e.printStackTrace();
} finally {
_reply.recycle();
_data.recycle();
}
} else {
Toast.makeText(this, "
服务器被异常杀死,
请重新绑定服务端"
, Toast.LENGTH_SHORT).show();
}
break;
default:
break;
}
}public static Intent getExplicitIntent(Context context, Intent implicitIntent) {
// Retrieve all services that can match the given intent
PackageManager pm =
context.getPackageManager();
List<
ResolveInfo>
resolveInfo =
pm.queryIntentServices(implicitIntent, 0);
// Make sure only one match was found
if (resolveInfo =
=
null || resolveInfo.size() !=
1) {
return null;
}
// Get component info and create ComponentName
ResolveInfo serviceInfo =
resolveInfo.get(0);
String packageName =
serviceInfo.serviceInfo.packageName;
String className =
serviceInfo.serviceInfo.name;
ComponentName component =
new ComponentName(packageName, className);
// Create a new intent. Use the old one for extras and such reuse
Intent explicitIntent =
new Intent(implicitIntent);
// Set the component to be explicit
explicitIntent.setComponent(component);
return explicitIntent;
}
}
<
?xml version=
"
1.0"
encoding=
"
utf-8"
?>
<
LinearLayout xmlns:android=
"
http://schemas.android.com/apk/res/android"
android:id=
"
@
+
id/activity_main"
android:layout_width=
"
match_parent"
android:layout_height=
"
match_parent"
android:paddingBottom=
"
@
dimen/activity_vertical_margin"
android:paddingLeft=
"
@
dimen/activity_horizontal_margin"
android:paddingRight=
"
@
dimen/activity_horizontal_margin"
android:paddingTop=
"
@
dimen/activity_vertical_margin"
android:orientation=
"
vertical"
>
<
Button
android:id=
"
@
+
id/bind_service"
android:layout_width=
"
match_parent"
android:layout_height=
"
wrap_content"
android:text=
"
bind service"
/>
<
Button
android:id=
"
@
+
id/unbind_service"
android:layout_width=
"
match_parent"
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Android Permission介绍
- 详细教程论android studio中如何申请百度地图新版Key中SHA1值
- Android的自动对焦
- Android艺术开发探索第三章——View的事件体系(上)
- WeMall商城系统的Android app商城中的wemall-mobile代码
- Excel2007运用图文详细教程:只读密码设置与更改_Excel专区
- Excel2007新手图文详细教程:私人定制文档主题_Excel专区
- Excel2007新手图文详细教程:单元格显示出错代码的含义_Excel专区
- 新手必学:Excel 20076个更改技巧_Excel专区