Android跨进程通信-AIDL
来源:互联网 发布:淘宝的限时特价怎么做 编辑:程序博客网 时间:2024/05/04 01:44
转至:http://codingnow.cn/android/529.html
上一篇复习了Android生命周期和本地Service的使用,这一篇继续总结一下Android远程Service的使用,远程Service就是在新的进程中开启service,这样会遇到一个问题,就是进程间通信的问题。Android系统的进程之间不能共享内存,那怎么传递对象呢,需要把对象弄成操作系统可以识别的形式,在Android中,可以采用AIDL来公开服务的接口,采用远程过程调用(Remote Procedure Call,RPC)和代理模式来实现跨进程通信。AIDL:Android Interface Definition Language,即Android接口描述语言,ADT会根据aidl文件在gen目录下生成对应的java接口文件。我们需要手工创建一个Service的子类并实现生成的java接口,然后在AndroidManifest.xml文件中进行配置。远程服务可以为多个客户端服务,由于涉及到数据通信,一般采用bindService的方式。
下面我们通过一个demo来看看AIDL是如何实现的。
首先创建服务端Android工程。目录结构如图
代码如下
User.java,为了实现跨进程数据传递,需要实现Parcelable 接口,是一种序列化方式。
public
class
User
implements
Parcelable {
private
int
id;
private
String name;
public
User() {
}
public
User(Parcel parcel) {
this
.id = parcel.readInt();
this
.name = parcel.readString();
}
public
int
getId() {
return
id;
}
public
void
setId(
int
id) {
this
.id = id;
}
public
String getName() {
return
name;
}
public
void
setName(String name) {
this
.name = name;
}
@Override
public
int
describeContents() {
// TODO Auto-generated method stub
return
0
;
}
@Override
public
void
writeToParcel(Parcel dest,
int
flags) {
//顺序需与构造函数中read保持一致
dest.writeInt(id);
dest.writeString(name);
}
public
static
final
Parcelable.Creator<User> CREATOR =
new
Creator<User>() {
@Override
public
User createFromParcel(Parcel source) {
return
new
User(source);
}
@Override
public
User[] newArray(
int
size) {
return
new
User[size];
}
};
}
User.adil
parcelable User;
IRemoteService.aidl
/**
远程的服务
IRemoteService.aidl
*/
interface
IRemoteService {
//返回基本类型
int
getId();
//返回对象
User getUser();
}
RemoteService.java
public
class
RemoteService
extends
Service {
@Override
public
void
onCreate() {
Log.i(
this
.getClass().getName(),
"onCreate"
);
}
@Override
public
int
onStartCommand(Intent intent,
int
flags,
int
startId) {
Log.i(
this
.getClass().getName(),
"onStartCommand"
);
return
super
.onStartCommand(intent, flags, startId);
}
@Override
public
void
onDestroy() {
Log.i(
this
.getClass().getName(),
"onDestroy"
);
}
@Override
public
IBinder onBind(Intent intent) {
return
mRemoteServiceBinder;
}
@Override
public
boolean
onUnbind(Intent intent) {
Log.i(
this
.getClass().getName(),
"onUnbind"
);
return
super
.onUnbind(intent);
}
@Override
public
void
onRebind(Intent intent) {
Log.i(
this
.getClass().getName(),
"onRebind"
);
super
.onRebind(intent);
}
IRemoteService.Stub mRemoteServiceBinder =
new
IRemoteService.Stub() {
@Override
public
User getUser()
throws
RemoteException {
User user =
new
User();
user.setId(
123456
);
user.setName(
"alexzhou"
);
return
user;
}
@Override
public
int
getId()
throws
RemoteException {
return
123456
;
}
};
}
AndroidManifest.xml
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
manifest
xmlns:android
=
"http://schemas.android.com/apk/res/android"
package
=
"com.alexzhou.aidl.server"
android:installLocation
=
"internalOnly"
android:versionCode
=
"1"
android:versionName
=
"1.0"
>
<
uses-sdk
android:minSdkVersion
=
"8"
android:targetSdkVersion
=
"10"
/>
<
application
android:icon
=
"@drawable/ic_launcher"
android:label
=
"@string/app_name"
>
<
activity
android:name
=
".RemoteServiceActivity"
android:label
=
"@string/app_name"
>
<
intent-filter
>
<
action
android:name
=
"android.intent.action.MAIN"
/>
<
category
android:name
=
"android.intent.category.LAUNCHER"
/>
</
intent-filter
>
</
activity
>
<!-- android:process="name" name的值是随便取的 ,android:exported:是否允许被其它程序调用-->
<
service
android:name
=
"com.alexzhou.aidl.server.RemoteService"
android:exported
=
"true"
android:process
=
":remote"
>
<
intent-filter
>
<
action
android:name
=
"com.alexzhou.service.REMOTE_SERVICE"
/>
</
intent-filter
>
</
service
>
</
application
>
</
manifest
>
服务端的Activty是自动生成的。没写任何其他代码,这里就不贴出来了。
接着需要创建一个客户端Android工程,目录结构如下图:
代码如下:
先把User.java,User.aidl,IRemoteService.aidl三个文件复制到客户端,注意包名必须跟服务端所在的包名一致。
创建客户端主界面类ClientActivity.java
public
class
ClientActivity
extends
Activity
implements
OnClickListener{
private
TextView callbackView;
private
Button bindButton;
private
boolean
isBind;
private
final
String REMOTE_SERVICE_ACTION =
"com.alexzhou.service.REMOTE_SERVICE"
;
private
IRemoteService mRemoteService;
/** Called when the activity is first created. */
@Override
public
void
onCreate(Bundle savedInstanceState) {
super
.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViews();
setListeners();
callbackView.setText(
"no callback"
);
}
private
void
findViews() {
callbackView = (TextView)
this
.findViewById(R.id.callback);
bindButton = (Button)
this
.findViewById(R.id.bind);
}
private
void
setListeners() {
bindButton.setOnClickListener(
this
);
}
@Override
public
void
onClick(View view) {
switch
(view.getId()) {
case
R.id.bind:
this
.bindService(
new
Intent(REMOTE_SERVICE_ACTION), mConntectin, Context.BIND_AUTO_CREATE);
callbackView.setText(
"binding..."
);
break
;
}
}
private
ServiceConnection mConntectin =
new
ServiceConnection() {
@Override
public
void
onServiceDisconnected(ComponentName arg0) {
callbackView.setText(
"Disconnected!"
);
}
@Override
public
void
onServiceConnected(ComponentName name, IBinder binder) {
mRemoteService = IRemoteService.Stub.asInterface(binder);
isBind =
true
;
try
{
int
id = mRemoteService.getId();
User user = mRemoteService.getUser();
StringBuffer buffer =
new
StringBuffer();
buffer.append(
"id:"
);
buffer.append(id);
buffer.append(
"name"
);
buffer.append(user.getName());
callbackView.setText(buffer.toString());
}
catch
(RemoteException e) {
e.printStackTrace();
}
}
};
@Override
protected
void
onDestroy() {
if
(isBind) {
this
.unbindService(mConntectin);
isBind =
false
;
}
super
.onDestroy();
}
}
布局文件main.xml
<?
xml
version
=
"1.0"
encoding
=
"utf-8"
?>
<
LinearLayout
xmlns:android
=
"http://schemas.android.com/apk/res/android"
android:layout_width
=
"fill_parent"
android:layout_height
=
"fill_parent"
android:orientation
=
"vertical"
>
<
TextView
android:id
=
"@+id/callback"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
/>
<
Button
android:id
=
"@+id/bind"
android:layout_width
=
"wrap_content"
android:layout_height
=
"wrap_content"
android:text
=
"@string/bind_remote_service_text"
/>
</
LinearLayout
>
现在运行你的客户端程序,点击绑定远程服务按钮,如果一切顺利,将会看到服务端返回的信息。如图:
通过eclipse控制台Devices视图,可以看到远程服务进程已启动,如图:
可能会遇到的问题和解决办法:
(1)AIDL unable to start service not found
客户端和服务端activty包名相同了,改成不同就可以
(2)Not allowed to bind to service Intent
在服务端配置文件中把android:exported = false 改成 true,android:exported表示是否允许被其它程序调用
(3)Binder invocation to an incorrect interface
客户端aidl文件的包名跟service的包名不一样,改成一样的就ok
- Android跨进程通信-AIDL
- Android跨进程通信-AIDL
- Android AIDL跨进程通信
- Android AIDL跨进程通信
- Android 跨进程通信: AIDL
- Android:AIDL跨进程通信
- android 跨进程间通信AIDL
- Android跨进程通信 AIDL方式
- AIDL Android跨进程通信调用实例
- Android跨进程通信----AIDL使用方法
- android studio AIDL跨进程通信
- Android AIDL跨进程通信基础
- Android 跨进程通信之:AIDL
- Android中使用aidl跨进程通信
- Android跨进程通信——AIDL
- 从AIDL看Android跨进程通信
- Android使用Aidl实现跨进程通信
- Android跨进程通信-AIDL的使用
- 讲讲C++中的volatile关键字
- ACM想法题
- openstack services port
- linux内核中的IS_ERR
- <c:forEach>
- Android跨进程通信-AIDL
- UIScrollView
- Unloading Data Using the ORACLE_DATAPUMP Access Driver【每日一译】--20121225
- Sql Server中字符转换成整型或小数位的函数用法!
- cocos2d-x创建场景Scene及三要素
- 解决页面加载速度慢的6个方法
- 魔法数字Magic Number C语言代码
- 使用地图显示我的位置
- Mac OS 内存管理知识