一篇复习了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
转载请注明来自:Alex
Zhou,本文链接:http://codingnow.cn/android/529.html
分享到:
相关推荐
Android 使用AIDL跨进程通信--传递自定义对象 服务端进程-SystemApp(包含IRemoteBinder.aidl,Book.aidl) 客户端进程-ClientApp
Android中Service的进程通信方式 - AIDL入门实践
Android多进程通讯AIDL传递Parcelable对象
android aidl跨进程通信例子,简单明了
Android IPC多进程通信 aidl
Android使用AIDL实现跨进程的通信.rar
关于使用aidl进行跨进程通信的简单demo
Android跨进程使用aidl通信。demo中包含两个apk,服务端和客户端。
Android AIDL跨进程通信 的demo,包括两部分,两个项目
Android 进程间通信AIDL demo 博客地址:http://blog.csdn.net/bigboysunshine/article/details/70228223
android进程间通信之AIDL的简单的示例代码
项目包括两部分,客户端和服务端,分别介绍了两个客户端的通信实现,及潜在的问题,由浅入深,其中包括基本数据类型和自定义数据类型的接口格式。
Android进程间的通信之AIDL简单实例,主要是一下流程,希望大神们勿喷,也希望对初学者有所帮助
Android进程间通信AIDL技术讲解
NULL 博文链接:https://venus585625.iteye.com/blog/855874
由于android系统中应用程序...Service和Content Provider类似,也可以访问其他应用程序中的数据,但不同的是,Content Provider返回的是Cursor对象,而Service返回的是Java对象,这种可以跨进程通讯的服务叫AIDL服务。
###Android的跨进程通信---------aidl 做android也有一段时间了,一直没有在博客中去做过这样的总结,刚好这段时间学习开始总结点东西,想着一些简单的问题就不在上面总结了,而之前一些写的都是关于C一方面的总结,...
Android系统中的进程之间不能共享内存,因此,需要提供一些机制在不同进程之间进行数据通信。
本篇文章主要介绍了详解Android跨进程IPC通信AIDL机制原理,详细的介绍了AIDL的概念和使用,具有一定的参考价值,有兴趣的可以了解一下