一、前言
前段時間在工作中有一個棘手的問題臭杰,接手了一個Android項目,因需要投入使用的設(shè)備內(nèi)存醒柚小(RAM1GB)且使用到串口較多渴杆,頻次較高的原因,在某些頁面使用上會出現(xiàn)略微的卡頓宪塔,導(dǎo)致用戶體驗不是特別好磁奖,我當時的想法是:如果把1GB換成2GB,那么這把牌將絕殺某筐,可惜設(shè)備已經(jīng)訂好了比搭,換不得。
初步?jīng)Q定使用多線程的方式南誊,將串口讀寫的工作和業(yè)務(wù)代碼分開來身诺,一個是把代碼模塊化,另外一個是多進程便可以從系統(tǒng)處分配出更多的內(nèi)存以加快整個APP的響應(yīng)速度抄囚。
二霉赡、原理圖
先貼一下整個流程的原理圖
原理比較清晰,由Service和串口進程通信幔托,我們的Application與Service進行綁定穴亏,通過Messenger和Service進行交互,而數(shù)據(jù)由Application通過Eventbus進行下發(fā)給頁面
三柑司、實現(xiàn)功能
(一)Service和串口通信
我這邊開了兩個串口做演示迫肖,一個是ttyS0,波特率9600
另外一個是ttyS1,波特率9600
mSerialPortManager1 = new SerialPortManager(new File("/dev/ttyS0"), 9600)
.setOnSerialPortDataListener(new OnSerialPortDataListener() {
@Override
public void onDataReceived(byte[] bytes) {
/** 接收到串口數(shù)據(jù)*/
sendMessageToClient(101, new String(bytes));
}
});
mSerialPortManager2 = new SerialPortManager(new File("/dev/ttyS1"), 9600)
.setOnSerialPortDataListener(new OnSerialPortDataListener() {
@Override
public void onDataReceived(byte[] bytes) {
sendMessageToClient(102, new String(bytes));
}
});
(二)Service和Application的交互
Service和Application屬于不同的進程,所以涉及到跨進程通信
我使用的是Messenger攒驰,可參考http://www.reibang.com/p/671b07f5ef86
當然跨進程的方式有很多蟆湖,我這邊選了一個比較簡單的來使用
感興趣的同學可以自行深挖,此處不展開篇幅談多進程
因為實際使用如我這個項目中用了n多的指令和串口玻粪,所以我使用Message的what作為狀態(tài)碼code來區(qū)分不同的指令
這是service中接收數(shù)據(jù)的Handler
200是接收到application傳遞過來的Messenger隅津,用于初始化
201和202都是從主進程發(fā)過來的數(shù)據(jù),用于兩個串口
@SuppressLint("HandlerLeak")
class MyHandler extends Handler {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Bundle bundle = msg.getData();
switch (msg.what) {
/** 初始化成功*/
case 200:
Message message = Message.obtain(null, 100, 1, 1);
bundle.putString("key", "client create success");
message.setData(bundle);
mClient = msg.replyTo;
try {
mClient.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
break;
case 201:
/** 接收到用戶端需要發(fā)送數(shù)據(jù)指令201*/
boolean sendBytes = mSerialPortManager1.sendTxt(bundle.get("data").toString());
Log.i(TAG, "onSend: sendBytes = " + sendBytes);
Log.i(TAG, sendBytes ? "發(fā)送成功" : "發(fā)送失敗");
break;
case 202:
/** 接收到用戶端需要發(fā)送數(shù)據(jù)指令202*/
mSerialPortManager2.sendTxt(bundle.get("data").toString());
break;
default:
break;
}
}
}
這是Application中的Handler
數(shù)據(jù)來源于串口的數(shù)據(jù)回調(diào)
serialHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
super.handleMessage(msg);
Bundle bundle = msg.getData();
switch (msg.what) {
case 100:
/** 初始化時返回的數(shù)據(jù)*/
Log.i(TAG, "接收到Service發(fā)送的數(shù)據(jù)");
break;
case 101:
/** 接收101數(shù)據(jù)*/
EventBus.getDefault().post(new SerialDataEvent(msg.what, bundle.get("data").toString()));
break;
case 102:
/** 接收到102數(shù)據(jù)*/
EventBus.getDefault().post(new SerialDataEvent(msg.what, bundle.get("data").toString()));
break;
default:
break;
}
}
};
(三)Application下發(fā)數(shù)據(jù)和接收數(shù)據(jù)
數(shù)據(jù)下發(fā)就由EventBus來完成了劲室,非常好用
而頁面需要向串口傳數(shù)據(jù)我在Application中創(chuàng)建了一個全局的Messenger
mServer伦仍,在綁定Service的時候?qū)⑵涑跏蓟憧梢允褂?/p>
serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
Log.i(TAG, "onServiceConnected: ComponentName = " + name);
mServer = new Messenger(service);
Log.i(TAG, "連接成功...................");
Message message = Message.obtain(null, 200);
message.replyTo = mClient;
try {
mServer.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
發(fā)送數(shù)據(jù)的代碼
/**
* 發(fā)送數(shù)據(jù)至Service
* */
public static void sendMessageToServer(int code, String data) {
Message message = Message.obtain(null, code);
Bundle bundle = new Bundle();
bundle.putString("data", data);
message.setData(bundle);
try {
InitApplication.mServer.send(message);
} catch (RemoteException e) {
e.printStackTrace();
}
}
四很洋、總結(jié)
比起直接使用串口多了幾個步驟充蓝,便可以實現(xiàn)多進程的串口讀寫了
不僅運行速度有了明顯的提高,而且可以全局的讀寫串口數(shù)據(jù),并不是以前單一的頁面使用串口谓苟,也不需要頻繁的開關(guān)串口官脓,如果有多個頁面需要用到串口,也不用重復(fù)的寫無意義的代碼涝焙,可謂是一舉多得
有問題和建議都可以在評論區(qū)給我留言