昨天咱們主管說準備把項目拆分一下,如今項目依賴了好幾個負責串口通信Library,準備把這些Library變成獨立的APP,經過Android跨進程機制進行數據交互。而後讓我寫一個跨進程通訊的Demo進行測試。java
跨進程通訊的方式有好幾種,我這裏用的是AIDL的方式。android
首先實現同一應用內跨進程通訊,而後在實現APP間通訊。由於AIDL是c/s模式,因此咱們先建立一個服務端應用。git
服務端包名:com.aidl.service github
<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方法
}
複製代碼
① 、在項目的根目錄下建立一個Msg的AIDL文件。包名和項目包名一致,而且Msg.aidl聲明爲parcelable類型,Msg.aidl路徑和Msg.java路徑一致。 測試
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文件
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();
}
}
複製代碼
運行截圖以下:
android:process=":remote"
複製代碼
須要使用action進行啓動:
Intent intent = new Intent();
intent.setAction("com.aidl.service.MyService");
複製代碼
上面咱們已經完成了服務端的功能,而且實現activity和service的雙向通訊。如今只須要將activity的功能放到另外一個應用內實現就好了。
包名:com.aidl.client
將服務端的AILD文件夾拷貝到客戶端,而且包名和服務端同樣,保持不變。服務端和客戶端AIDL目錄以下。
咱們知道客戶端的包名是com.aidl.client,而Msg.aidl路徑是com.aidl.service,因此咱們要在com.aidl.service目錄下建立Msg.java。
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();
}
}
複製代碼
客戶端運行截圖:
完整項目已經上傳到GitHub上去了:github.com/Zhengyi66/A…