天天看点

Android的两种进程间通信方式Messenger和AIDL

Android中有事遇到在不同进程间进行通信,此时我们有两种实现方式。其一使用Messenger,其二使用AIDL。

Messenger在http://blog.csdn.net/chenfeng0104/article/details/7010244写的比较详细,需要了解的同学可以进去看看。我今天就对这几天研究的AIDL做个记录。

AIDL(Android Interface Definition Language)是一种接口定义语言,编译器通过*.aidl文件的描述信息生成符合通信协议的Java代码,我们无需自己去写这段繁杂的代码,只需要在需要的时候调用即可,通过这种方式我们就可以完成进程间的通信工作。

首先编写服务端app,创建一个demo,先看下文件结构:

要创建一个aidl文件AIDLService.aidl和入口Activity类MainActivity,app的Application类和app的Service类。(https://img-blog.csdn.net/20151030142702963)。

先看下aidl文件:

package com.aidl.binder.message;

interface AIDLService{
    String getMessage(String str);
    String infoMessage(String str);
}
           

接口中有两个未实现的方法。

AIDLServerService类实现:

package com.aidl.server;

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

import com.aidl.binder.message.AIDLService;

public class AIDLServerService extends Service {

    AIDLService mService;
    private String TAG = "AIDLServerService";

    @Override
    public void onCreate() {
        super.onCreate();

        mService = new AIDLService.Stub() {

            @Override
            public String infoMessage(String str) throws RemoteException {
                return "you call method infoMessage(String str) and parameter " + str ;
            }

            @Override
            public String getMessage(String str) throws RemoteException {
                return "you call method getMessage(String str) and parameter " + str ;
            }
        };
    }

    @Override
    public IBinder onBind(Intent intent) {
        return (IBinder) mService;
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        Log.e(TAG, "onDestory AIDLServerService");

        mService = null;
    }

    @Override
    public void unbindService(ServiceConnection conn) {
        super.unbindService(conn);
        Log.e(TAG, "unbindService");
    }



}
           
在AIDLServerService里我们实现了AIDLService的两个方法。并在onBind(Intent intent)方法中return AIDLService的对象。
Application类实现很简单,就是用于启动AIDLServerService.
           
public class AssistProjectApplication extends Application {

    @Override
    public void onCreate() {
        super.onCreate();

        startService(new Intent(this, AIDLServerService.class));
    }

    @Override
    public void onTerminate() {
        super.onTerminate();

    }

}
           

入口activity中不需要做处理。

AndroidManifest文件配置:

<application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <activity
            android:name="com.aidl.server.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="com.aidl.server.reside.menu.MenuActivity"/>

        <service android:name="com.aidl.server.AIDLServerService">
            <intent-filter>
                <action android:name="com.aidl.server.Action.AIDLServerService"/>
            </intent-filter>
        </service>

    </application>
           

现在看下客户端app的实现:

客户端创建一个和服务端包名及aidl文件一致的.aidl文件,方便考虑,可以直接copy到客户端。

Android的两种进程间通信方式Messenger和AIDL

客户端调用aidl的实现Activity:

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.util.Log;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.TextView;
import android.widget.Toast;

import com.aidl.binder.message.AIDLService;
import com.syp.assistprogect.R;

public class AIDLServiceActivity extends Activity implements OnClickListener{
    private String TAG = "AIDLServiceActivity";
    private TextView mTxtShow;
    private Button mBtnGet;
    private Button mBtnInfo;
    private Button mBtnBinder;

    private AIDLService mService = null;
    private boolean isBinder = false;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_aidl_ipc_layout);

        mTxtShow = (TextView) findViewById(R.id.txt_ipc_aidl_show);
        mBtnGet = (Button) findViewById(R.id.btn_ipc_get);
        mBtnInfo = (Button) findViewById(R.id.btn_ipc_info);
        mBtnBinder = (Button) findViewById(R.id.btn_ipc_bundle_aidl);

        mBtnGet.setOnClickListener(this);
        mBtnInfo.setOnClickListener(this);
        mBtnBinder.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        int id = v.getId();
        switch (id) {
        case R.id.btn_ipc_get:
            if(isBinder && mService != null){
                try {
                    String data = mService.getMessage("aidl test");
                    Log.i(TAG, "call getMessage() and return :" + data);
                    mTxtShow.setText(mService.getMessage("aidl test"));
                } catch (RemoteException e) {
                    Log.e(TAG, e.toString());
                }
            }

            break;
        case R.id.btn_ipc_info:

            if(isBinder && mService != null){
                try {
                    String data = mService.getMessage("aidl test");
                    Log.i(TAG, "call infoMessage() and return :" + data);
                    mTxtShow.setText(mService.infoMessage("aidl test"));
                } catch (RemoteException e) {
                    Log.e(TAG, e.toString());
                }
            }

            break;
        case R.id.btn_ipc_bundle_aidl:
            binderAIDLService();

            break;
        default:
            break;
        }
    }

    private String serviceAction = "com.aidl.server.Action.AIDLServerService";//服务端service的action
    private void binderAIDLService(){
        Intent intent = new Intent(serviceAction);
        bindService(intent, mConnection, Context.BIND_AUTO_CREATE);
        Log.e(TAG, "binderAIDLService ->intent = " + intent);
    } 

    ServiceConnection mConnection = new ServiceConnection() {

        @Override
        public void onServiceDisconnected(ComponentName name) {
            mService = null;
            isBinder = false;
            Toast.makeText(AIDLServiceActivity.this, "service has disconnected", Toast.LENGTH_SHORT).show();
        }

        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
            mService = AIDLService.Stub.asInterface(service);
            isBinder = true;
            Toast.makeText(AIDLServiceActivity.this, "service has Connected", Toast.LENGTH_SHORT).show();
        }
    };

    protected void onDestroy() {
        super.onDestroy();
        if(mService != null){
            unbindService(mConnection);
            mService = null;
        }
    };

}
           

注意在退出activity时,要断开binderservice的连接,请看onDestroy();

最后我在使用时发现一个奇怪的事情,如果我把客户端aidl中的两个方法换下顺序,`package com.aidl.binder.message;

interface AIDLService{

String infoMessage(String str);

String getMessage(String str);

}`

发现在调用getMessage(String str)方法时,返回的结果是infoMessage(String str)的实现。

找了很久问题所在,发现在我们创建aidl文件后,在服务端app下gen生成的方法如下

Android的两种进程间通信方式Messenger和AIDL

在客户端app下的gen目录生成两方法如下

Android的两种进程间通信方式Messenger和AIDL

最终调用方法时是由TRANSACTION_getMessage的值来决定的,和方法名称没关系。所以在使用aidl实现多个方法时,注意保持方法顺序在CS两点的一直。