Android使用多進程來進行串口讀寫

一、前言

前段時間在工作中有一個棘手的問題臭杰,接手了一個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)速度抄囚。

二霉赡、原理圖

先貼一下整個流程的原理圖

image

原理比較清晰,由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ū)給我留言

源碼地址:https://github.com/Giftedcat/AndroidSerialPortManager

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末卑笨,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子仑撞,更是在濱河造成了極大的恐慌赤兴,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,635評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件隧哮,死亡現(xiàn)場離奇詭異桶良,居然都是意外死亡,警方通過查閱死者的電腦和手機近迁,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,543評論 3 399
  • 文/潘曉璐 我一進店門艺普,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人鉴竭,你說我怎么就攤上這事歧譬。” “怎么了搏存?”我有些...
    開封第一講書人閱讀 168,083評論 0 360
  • 文/不壞的土叔 我叫張陵瑰步,是天一觀的道長。 經(jīng)常有香客問我璧眠,道長缩焦,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 59,640評論 1 296
  • 正文 為了忘掉前任责静,我火速辦了婚禮袁滥,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘灾螃。我一直安慰自己题翻,他們只是感情好,可當我...
    茶點故事閱讀 68,640評論 6 397
  • 文/花漫 我一把揭開白布腰鬼。 她就那樣靜靜地躺著嵌赠,像睡著了一般。 火紅的嫁衣襯著肌膚如雪熄赡。 梳的紋絲不亂的頭發(fā)上姜挺,一...
    開封第一講書人閱讀 52,262評論 1 308
  • 那天,我揣著相機與錄音彼硫,去河邊找鬼炊豪。 笑死凌箕,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的词渤。 我是一名探鬼主播陌知,決...
    沈念sama閱讀 40,833評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼掖肋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起赏参,我...
    開封第一講書人閱讀 39,736評論 0 276
  • 序言:老撾萬榮一對情侶失蹤志笼,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后把篓,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體纫溃,經(jīng)...
    沈念sama閱讀 46,280評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,369評論 3 340
  • 正文 我和宋清朗相戀三年韧掩,在試婚紗的時候發(fā)現(xiàn)自己被綠了紊浩。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 40,503評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡疗锐,死狀恐怖坊谁,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情滑臊,我是刑警寧澤口芍,帶...
    沈念sama閱讀 36,185評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站雇卷,受9級特大地震影響鬓椭,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜关划,卻給世界環(huán)境...
    茶點故事閱讀 41,870評論 3 333
  • 文/蒙蒙 一小染、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧贮折,春花似錦裤翩、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,340評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至振峻,卻和暖如春臼疫,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背扣孟。 一陣腳步聲響...
    開封第一講書人閱讀 33,460評論 1 272
  • 我被黑心中介騙來泰國打工烫堤, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 48,909評論 3 376
  • 正文 我出身青樓鸽斟,卻偏偏與公主長得像拔创,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子富蓄,可洞房花燭夜當晚...
    茶點故事閱讀 45,512評論 2 359