Android跨进程通信-AIDL详解示例(client+server)

本文介绍Android中AIDL(Android Interface Definition Language)的原理及应用,通过实例展示如何利用AIDL实现跨进程通信,包括服务端与客户端的具体实现步骤。

 

1.什么是aidl:aidl是 Android Interface definition language的缩写,一看就明白,它是一种android内部进程通信接口的描述语言,通过它我们可以定义进程间的通信接口
icp:interprocess communication :内部进程通信

 

2.既然aidl可以定义并实现进程通信,那么我们怎么使用它呢?我们来详细介绍:

 

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 接口,是一种序列化方式。

 

 

package com.zgs.aidl.demo;

import android.os.Parcel;
import android.os.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文件:

 

package com.zgs.aidl.demo;

parcelable User;

 

 

IRemoteService.aidl文件源码:

 

package com.zgs.aidl.demo;

import com.zgs.aidl.demo.User;
/**  
*远程的服务
*IRemoteService.aidl
*
*可以引用其它aidl文件中定义的接口,但是不能够引用你的java类文件中定义的接口
*/
interface IRemoteService {
    //返回基本类型
    int getId();
    //返回对象
    User getUser();
 
}

 

 

RemoteService.java文件源码:

 

package com.zgs.aidl.demo.service;

import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
import android.util.Log;

import com.zgs.aidl.demo.IRemoteService;
import com.zgs.aidl.demo.User;


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.zgs.adnroidaidlservice"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="17" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.zgs.aidl.demo.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>
       
       
       
        <!-- android:process="name" name的值是随便取的 ,android:exported:是否允许被其它程序调用-->
   <service
    android:name="com.zgs.aidl.demo.service.RemoteService"
   android:exported="true"
   android:process=":remote" >
   <intent-filter>
     <action android:name="com.zgs.aidl.demo.service.REMOTESERVICE" />
   </intent-filter>
  </service>
 </application>

</manifest>

服务端的Activty是自动生成的。没写任何其他代码,这里就不贴出来了。

 

 

 


 接着需要创建一个客户端Android工程,目录结构如下图:

 

 

先把User.java,User.aidl,IRemoteService.aidl三个文件复制到客户端,注意包名必须跟服务端所在的包名一致。
创建客户端主界面类MainActivity.java

 

package com.zgs.aidl.client;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle;
import android.os.IBinder;
import android.os.RemoteException;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;

import com.zgs.aidl.demo.IRemoteService;
import com.zgs.aidl.demo.User;

public class MainActivity   extends Activity implements OnClickListener{
 
    private TextView callbackView;
    private Button bindButton;
    private boolean isBind;
    private final String REMOTE_SERVICE_ACTION = "com.zgs.aidl.demo.service.REMOTESERVICE";
 
    private IRemoteService mRemoteService;
 
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_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="bind_remote_service_text"/>
 
</LinearLayout>

 

先运行服务端程序,再运行你的客户端程序,点击绑定远程服务按钮,如果一切顺利,将会看到服务端返回的信息。如图:

 

 

 

点击按钮之后正确的效果如下:


 

 

原文链接:http://www.eoeandroid.com/forum.php?mod=viewthread&tid=201000

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值