使用AIDL实现两个APP之间跨进程通讯

昨天咱们主管说准备把项目拆分一下,如今项目依赖了好几个负责串口通信Library,准备把这些Library变成独立的APP,经过Android跨进程机制进行数据交互。而后让我写一个跨进程通讯的Demo进行测试。java

跨进程通讯的方式有好几种,我这里用的是AIDL的方式。android

1、同一个APP内Service和Activity通讯

首先实现同一应用内跨进程通讯,而后在实现APP间通讯。由于AIDL是c/s模式,因此咱们先建立一个服务端应用。git

一、建立一个服务端的APP,而后在建立一个Service服务。

服务端包名:com.aidl.service github

建立service
自动生成MyService类和manifest注册文件。

<service
            android:name=".MyService"
            android:enabled="true"
            android:exported="true">
            <intent-filter android:priority="1000">
                <action android:name="com.aidl.service.MyService"></action>
            </intent-filter>
        </service>
复制代码

固然你也能够手动建立。这里的enabled和exported属性要设置为true,容许其余应用调用。服务器

二、建立传送消息的消息对象

AIDL是不支持传递普通的Java对象的,不过支持Parcelable对象,因此咱们的消息对象要实现Parcelable。ide

public class Msg implements Parcelable {

    private String msg;
    private long time;
    public Msg(String msg){
        this.msg = msg;
    }
    public Msg(String msg, long time) {
        this.msg = msg;
        this.time = time;
    }
    protected Msg(Parcel in) {
        msg = in.readString();
    }
    public static final Creator<Msg> CREATOR = new Creator<Msg>() {
        @Override
        public Msg createFromParcel(Parcel in) {
            return new Msg(in);
        }
        @Override
        public Msg[] newArray(int size) {
            return new Msg[size];
        }
    };
    @Override
    public int describeContents() {
        return 0;
    }
    @Override
    public void writeToParcel(Parcel dest, int flags) {
        dest.writeString(msg);
    }
  	//set,get方法
}
复制代码
三、建立AIDL文件

① 、在项目的根目录下建立一个Msg的AIDL文件。包名和项目包名一致,而且Msg.aidl声明为parcelable类型,Msg.aidl路径和Msg.java路径一致。 测试

msg.aidl
②、建立一个收到消息的监听接口IReceiveMsgListener.aidl

package com.aidl.service;
import com.aidl.service.Msg;

interface IReceiveMsgListener {
   void onReceive(in Msg msg);
}
复制代码

导入Msg.aidl的完整路径import com.aidl.service.Msg。 onReceive()中Msg使用 in 输入标记。this

③、建立消息管理的接口IMsgManager.aidlspa

package com.aidl.service;
import com.aidl.service.IReceiveMsgListener;
import com.aidl.service.Msg;

interface IMsgManager {
   void sendMsg(in Msg msg);
   void registerReceiveListener(IReceiveMsgListener receiveListener);
   void unregisterReceiveListener(IReceiveMsgListener receiveListener);
}
复制代码

IMsgManager.aidl中提供了发送消息的方法、注册和解除消息监听的方法。一样要导入Msg.aidl 和IReceiveMsgListener.aidl的完整路径。3d

到这里AIDL文件编写完成。最后须要Make Project,编译器生成对应的Binder文件

在这里插入图片描述

四、编写MyService服务代码
public class MyService extends Service {
    //AIDL不支持正常的接口回调,使用RemoteCallbackList实现接口回调
    private RemoteCallbackList<IReceiveMsgListener> mReceiveListener = new RemoteCallbackList<IReceiveMsgListener>();

    public MyService() {
    }

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

    class MyBinder extends IMsgManager.Stub {
        
        //发送消息
        public void sendMsg(Msg msg) {
            receiveMsg(msg);
        }
        
        //注册
        @Override
        public void registerReceiveListener(IReceiveMsgListener receiveListener) throws RemoteException {
            mReceiveListener.register(receiveListener);
        }
        
        //解除注册
        @Override
        public void unregisterReceiveListener(IReceiveMsgListener receiveListener) throws RemoteException {
            boolean success = mReceiveListener.unregister(receiveListener);
            if (success){
                Log.d("tag","=== 解除注册成功");
            }else {
                Log.d("tag","=== 解除注册失败 ");
            }
        }

        @Override
        public boolean onTransact(int code, Parcel data, Parcel reply, int flags) throws RemoteException {
            return super.onTransact(code, data, reply, flags);
        }
    }
    
    //收到消息处理
    public void receiveMsg(Msg msg) {
        //通知Callback循环开始,返回N为实现mReceiveListener回调的个数
        final int N = mReceiveListener.beginBroadcast();
        msg.setMsg("我是服务器,我收到了:"+msg.getMsg());
        for (int i = 0; i < N; i++){
            IReceiveMsgListener listener = mReceiveListener.getBroadcastItem(i);
            if (listener != null){
                try {
                    listener.onReceive(msg);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        }
        //通知通知Callback循环结束
        mReceiveListener.finishBroadcast();
    }
}
复制代码

Service中经过Binder机制实现注册,解除注册和发送的方法。

Activity代码:

public class MainActivity extends AppCompatActivity {

    MyService.MyBinder binder = null;
    ServiceConnection mConnection;
    private ListView mListView;
    private EditText mEditText;
    private List<Msg> mMsgs = new ArrayList<>();
    private ListAdapter mAdapter;
    private IMsgManager mIMsgManager;
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            mAdapter.notifyDataSetChanged();
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mListView = (ListView) findViewById(R.id.listview);
        mEditText = (EditText) findViewById(R.id.edit_text);
        mAdapter = new ListAdapter(this, mMsgs);
        mListView.setAdapter(mAdapter);

        mConnection = new ServiceConnection() {
            @Override
            public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
                binder = (MyService.MyBinder) iBinder;
                IMsgManager msgManager = IMsgManager.Stub.asInterface(iBinder);
                mIMsgManager = msgManager;
                try {
                    mIMsgManager.asBinder().linkToDeath(mDeathRecipient, 0);
                    mIMsgManager.registerReceiveListener(mReceiveMsgListener);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void onServiceDisconnected(ComponentName componentName) {

            }
        };
		//注意Activity和Service是同一进程才能使用Intent通讯
        Intent intent = new Intent(MainActivity.this, MyService.class);
        bindService(intent, mConnection, BIND_AUTO_CREATE);//开启服务

        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (TextUtils.isEmpty(mEditText.getText().toString())) {
                    Toast.makeText(MainActivity.this, "消息为空", Toast.LENGTH_SHORT).show();
                    return;
                }
                binder.sendMsg(new Msg(mEditText.getText().toString().trim()));
            }
        });
        findViewById(R.id.btn_exit).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                MainActivity.this.finish();
            }
        });
    }

    private IReceiveMsgListener mReceiveMsgListener = new IReceiveMsgListener.Stub() {

        @Override
        public void onReceive(Msg msg) throws RemoteException {
            msg.setTime(System.currentTimeMillis());
            mMsgs.add(msg);
            mHandler.sendEmptyMessage(1);
        }
    };

    private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
        //当承载IBinder的进程消失时接收回调的接口
        @Override
        public void binderDied() {
            if (null == mIMsgManager) {
                return;
            }
            mIMsgManager.asBinder().unlinkToDeath(mDeathRecipient, 0);
            mIMsgManager = null;
            //断线重来逻辑
        }
    };

    @Override
    protected void onDestroy() {
        //解除注册
        if (null != mIMsgManager && mIMsgManager.asBinder().isBinderAlive()) {
            try {
                mIMsgManager.unregisterReceiveListener(mReceiveMsgListener);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        //解除绑定服务
        unbindService(mConnection);
        super.onDestroy();
    }
}
复制代码

运行截图以下:

在这里插入图片描述
若是想要实现同一应用内跨进程通讯须要修改Service的进程:

android:process=":remote"
复制代码

须要使用action进行启动:

Intent intent = new Intent();
 intent.setAction("com.aidl.service.MyService");
复制代码

2、两个或多个APP之间通讯

上面咱们已经完成了服务端的功能,而且实现activity和service的双向通讯。如今只须要将activity的功能放到另外一个应用内实现就好了。

一、建立客户端应用。

包名:com.aidl.client

二、将服务端的AIDL文件拷贝到客户端

将服务端的AILD文件夹拷贝到客户端,而且包名和服务端同样,保持不变。服务端和客户端AIDL目录以下。

在这里插入图片描述

三、拷贝Msg.Java对象

咱们知道客户端的包名是com.aidl.client,而Msg.aidl路径是com.aidl.service,因此咱们要在com.aidl.service目录下建立Msg.java。

在这里插入图片描述
编写Activity代码:

public class MainActivity extends AppCompatActivity {

    private IMsgManager myBinder;//定义AIDL
    private ListView mListView;
    EditText mEditText;
    private List<Msg> mMsgs = new ArrayList<>();
    private ListAdapter mAdapter;
    private IMsgManager mIMsgManager;
    private Msg mMsg;
    private Handler mHandler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case 1:
                    mAdapter.notifyDataSetChanged();
                    mListView.smoothScrollToPosition(mMsgs.size() - 1);
            }
        }
    };
    ServiceConnection mConnection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName componentName, IBinder iBinder) {
            myBinder = IMsgManager.Stub.asInterface(iBinder);
            IMsgManager msgManager = IMsgManager.Stub.asInterface(iBinder);
            mIMsgManager = msgManager;
            try {
                //连接到死亡代理,当IBinder死亡时收到回调
                mIMsgManager.asBinder().linkToDeath(mDeathRecipient, 0);
                //注册消息监听
                mIMsgManager.registerReceiveListener(mReceiveMsgListener);
            } catch (RemoteException e) {
                e.printStackTrace();
            }
        }
        @Override
        public void onServiceDisconnected(ComponentName name) {
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        mListView = (ListView) findViewById(R.id.listview);
        mEditText = (EditText) findViewById(R.id.edit_text);
        mSendCountTv = (TextView) findViewById(R.id.send_count_tv);
        mReceiveCountTv = (TextView) findViewById(R.id.receive_count_tv);
     	mMsg = new Msg("");
        mAdapter = new ListAdapter(this, mMsgs);
        mListView.setAdapter(mAdapter);
   
        Intent intent = new Intent();
        //跨进程通讯须要使用action启动
        intent.setAction("com.aidl.service.MyService");
        //android5.0以后,若是servicer不在同一个App的包中,须要设置service所在程序的包名
        intent.setPackage("com.aidl.service");
        //开启Service
        bindService(intent, mConnection, BIND_AUTO_CREATE);

        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                try {
                    String msg = mEditText.getText().toString().trim();
                    if (TextUtils.isEmpty(msg)) {
                        Toast.makeText(MainActivity.this, "消息不能为空", Toast.LENGTH_SHORT).show();
                        return;
                    }
                    mMsg.setMsg(msg);
                    //经过binder将消息传递到service
                    myBinder.sendMsg(mMsg);
                } catch (RemoteException e) {
                    e.printStackTrace();
                }
            }
        });
    }

    //消息回调监听
    private IReceiveMsgListener mReceiveMsgListener = new IReceiveMsgListener.Stub() {
		//收到服务端消息
        @Override
        public void onReceive(Msg msg) throws RemoteException {
            msg.setTime(System.currentTimeMillis());
            if (mMsgs.size() > 100) {
                mMsgs.clear();
            }
            mMsgs.add(msg);
            mHandler.sendEmptyMessage(1);
        }
    };

    private IBinder.DeathRecipient mDeathRecipient = new IBinder.DeathRecipient() {
        /** * 当承载IBinder的进程消失时接收回调的接口 */
        @Override
        public void binderDied() {
            if (null == mIMsgManager) {
                return;
            }
            mIMsgManager.asBinder().unlinkToDeath(mDeathRecipient, 0);
            mIMsgManager = null;
            //在这里从新绑定远程服务
        }
    };

    @Override
    protected void onDestroy() {
   		//解绑
        super.onDestroy();
    }
}
复制代码

客户端运行截图:

服务端截图 由于咱们服务端Activity也实现了IReceiveMsgListener 的接口,因此服务端Activity也能收到回调截图以下:
在这里插入图片描述
参考:部分参考Android开发艺术探索。

完整项目已经上传到GitHub上去了:github.com/Zhengyi66/A…

相关文章
相关标签/搜索