Android組件內(nèi)燎窘、組件間通信模塊的問題分析

對(duì)于一個(gè)App,組件通信必不可少蹄咖,通信類型可以分為點(diǎn)對(duì)點(diǎn)和點(diǎn)對(duì)面的的通信褐健,點(diǎn)對(duì)點(diǎn)即只有唯一的接收者可以響應(yīng)消息,點(diǎn)對(duì)面則類似于消息廣播澜汤,即所有注冊(cè)過的都可以響應(yīng)消息蚜迅。在Android中,通常使用消息機(jī)制來實(shí)現(xiàn)俊抵,但消息機(jī)制的耦合度比較高谁不。目前也有一些通信框架,如EventBus徽诲、Otto等事件總線框架刹帕,這些框架可以極大地降低組件間的耦合,但無法完美地實(shí)現(xiàn)點(diǎn)對(duì)點(diǎn)通信谎替,因此建議消息機(jī)制和事件總線機(jī)制結(jié)合使用偷溺。


組件之間的通信

舉例:fragment和fragment之間的通信,需要間接地使用宿主activity钱贯。主要有兩種方法:

  • 在A fragment中通過使用getActivity獲得宿主從而獲得宿主擁有的B fragment挫掏,進(jìn)而操作B fragment。
  • 在A fragment中編寫接口秩命,讓宿主activity實(shí)現(xiàn)該接口尉共,然后再fragment中把a(bǔ)ctivity當(dāng)成該接口使用。

然后弃锐,推薦使用第二種方式袄友。

  • 從實(shí)際使用的體驗(yàn)上來說,這種方式從一定程度上滿足了解耦霹菊,如果更改了宿主activity剧蚣,fragment的代碼不需要更改。
  • 從設(shè)計(jì)模式的角度來說浇辜,一個(gè)最基本原則就是開閉原則券敌。開閉原則是說模塊應(yīng)該對(duì)擴(kuò)展開放,而對(duì)修改關(guān)閉柳洋。模塊應(yīng)該盡量不修改代碼的情況下進(jìn)行擴(kuò)展待诅。
  • 第一種方式雖然行的通,但是明顯違反了設(shè)計(jì)模式的開閉原則熊镣。fragment設(shè)計(jì)之初就是一個(gè)獨(dú)立的開發(fā)組件卑雁,如果fragment要與宿主activity進(jìn)行交互募书,那么久需要知道activity是如何工作的,者本身就破壞了fragment的獨(dú)立性测蹲。也就是說這個(gè)fragment只能被這個(gè)activity獨(dú)占莹捡,不能再在另一個(gè)activity中使用。如果另一個(gè)B activity中也需要一個(gè)這樣的fragment扣甲,只能再重復(fù)寫一個(gè)被獨(dú)占的fragment篮赢,復(fù)用性被破壞。
  • 第二種方式琉挖,在fragment中定義了接口启泣,由宿主activity來實(shí)現(xiàn)接口處理任務(wù)。如果想換一個(gè)宿主activity示辈,只需要在新的activity中實(shí)現(xiàn)接口就好寥茫,fragment始終不需要改變。
  • 第二種方式實(shí)際上就是設(shè)計(jì)模式中的代理模式矾麻。多一個(gè)代理類出來纱耻,替原對(duì)象進(jìn)行一些操作。

EventBus

出名的框架為什么出名险耀?正是因?yàn)樗谧裱瓨?biāo)準(zhǔn)設(shè)計(jì)模式的基礎(chǔ)上弄喘,又優(yōu)雅地解決了棘手的問題。
https://github.com/greenrobot/EventBus

EventBus是一款針對(duì)Android優(yōu)化的發(fā)布/訂閱事件總線胰耗。主要功能是替代Intent,Handler,BroadCast在Fragment限次,Activity芒涡,Service柴灯,線程之間傳遞消息.優(yōu)點(diǎn)是開銷小,代碼更優(yōu)雅费尽。以及將發(fā)送者和接收者解耦赠群。

使用

  • 新建一個(gè)消息類,
    構(gòu)造時(shí)傳進(jìn)去一個(gè)字符串旱幼,然后可以通過getMsg()獲取出來查描。
public class FirstEvent { 
 
    private String mMsg;  
    public FirstEvent(String msg) {  
        // TODO Auto-generated constructor stub  
        mMsg = msg;  
    }  
    public String getMsg(){  
        return mMsg;  
    }  
}  
  • 注冊(cè)
    在接收消息的Activity的OnCreate()函數(shù)中注冊(cè)EventBus,在OnDestroy()函數(shù)中反注冊(cè)柏卤。
public class MainActivity extends Activity {  
  
    Button btn;  
    TextView tv;  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
                //注冊(cè)EventBus  
        EventBus.getDefault().register(this);  
  
        btn = (Button) findViewById(R.id.btn_try);  
        tv = (TextView)findViewById(R.id.tv);  
  
        btn.setOnClickListener(new View.OnClickListener() {  
            @Override  
            public void onClick(View v) {  
                // TODO Auto-generated method stub  
                Intent intent = new Intent(getApplicationContext(), SecondActivity.class);  
                startActivity(intent);  
            }  
        });  
    }  

    @Override  
    protected void onDestroy(){  
        super.onDestroy();  
        EventBus.getDefault().unregister(this);//反注冊(cè)EventBus  
    }  
}  
  • 發(fā)送消息
    是使用EventBus中的Post方法來實(shí)現(xiàn)發(fā)送的冬三,發(fā)送過去的是我們新建的消息類的實(shí)例!
public class SecondActivity extends Activity {  
    private Button btn_FirstEvent;  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_second);  
        btn_FirstEvent = (Button) findViewById(R.id.btn_first_event);  
  
        btn_FirstEvent.setOnClickListener(new View.OnClickListener() {  
  
            @Override  
            public void onClick(View v) {  
                // TODO Auto-generated method stub  
                EventBus.getDefault().post(new FirstEvent("FirstEvent btn clicked"));  
            }  
        });  
    }  
}  
  • 接收消息
    在接收消息的activity中重寫onEventMainThread(FirstEvent event)缘缚,參數(shù)就是自定義的消息類
public class MainActivity extends Activity {  
  
    Button btn;  
    TextView tv;  
  
    @Override  
    protected void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.activity_main);  
  
        EventBus.getDefault().register(this);  
  
        btn = (Button) findViewById(R.id.btn_try);  
        tv = (TextView)findViewById(R.id.tv);  
  
        btn.setOnClickListener(new View.OnClickListener() {  
            @Override  
            public void onClick(View v) {  
                // TODO Auto-generated method stub  
                Intent intent = new Intent(getApplicationContext(),  
                        SecondActivity.class);  
                startActivity(intent);  
            }  
        });  
    }  
  
    public void onEventMainThread(FirstEvent event) {  
        String msg = "onEventMainThread收到了消息:" + event.getMsg();  
        Log.d("harvic", msg);  
        tv.setText(msg);  
        Toast.makeText(this, msg, Toast.LENGTH_LONG).show();  
    }  
  
    @Override  
    protected void onDestroy(){  
        super.onDestroy();  
        EventBus.getDefault().unregister(this);  
    }  
}  

詳解

所謂發(fā)布/訂閱時(shí)間總線勾笆,肯定是有兩方,一方發(fā)布桥滨,一方觀察并接收:

  • 事件的發(fā)布:告知觀察者事件發(fā)生時(shí)通過EventBus.post函數(shù)實(shí)現(xiàn)窝爪,這個(gè)過程叫做事件的發(fā)布
  • 事件的接收:觀察者被告知事件發(fā)生叫做事件的接收

EventBus的接收函數(shù):
EventBus總共有4個(gè)函數(shù)可以接收post過來的的消息:

  1. onEvent
    如果使用onEvent作為訂閱函數(shù)弛车,那么該事件在哪個(gè)線程發(fā)布出來的,onEvent就會(huì)在這個(gè)線程中運(yùn)行蒲每,也就是說發(fā)布事件和接收事件線程在同一個(gè)線程纷跛。使用這個(gè)方法時(shí),在onEvent方法中不能執(zhí)行耗時(shí)操作邀杏,如果執(zhí)行耗時(shí)操作容易導(dǎo)致事件分發(fā)延遲贫奠。
  2. onEventMainThread
    如果使用onEventMainThread作為訂閱函數(shù),那么不論事件是在哪個(gè)線程中發(fā)布出來的望蜡,onEventMainThread都會(huì)在UI線程中執(zhí)行叮阅,接收事件就會(huì)在UI線程中運(yùn)行,這個(gè)在Android中是非常有用的泣特,因?yàn)樵贏ndroid中只能在UI線程中跟新UI浩姥,所以在onEvnetMainThread方法中是不能執(zhí)行耗時(shí)操作的。
  3. onEventBackgroundThread
    如果使用onEventBackgrond作為訂閱函數(shù)状您,那么如果事件是在UI線程中發(fā)布出來的勒叠,那么onEventBackground就會(huì)新建一個(gè)子線程再運(yùn)行onEventBackground,如果事件本來就是子線程中發(fā)布出來的膏孟,那么onEventBackground函數(shù)直接在該子線程中執(zhí)行眯分。
  4. onEventAsync
    使用這個(gè)函數(shù)作為訂閱函數(shù),那么無論事件在哪個(gè)線程發(fā)布柒桑,都會(huì)創(chuàng)建新的子線程在執(zhí)行onEventAsync弊决。

EventBus的消息接收機(jī)制:

  1. EventBus是怎么接收消息的?是根據(jù)參數(shù)中類的實(shí)例來判定的魁淳!
    這么說來飘诗,這個(gè)消息類必定是耦合在 發(fā)布/訂閱 雙方之間的,被兩者獨(dú)占界逛,不能被復(fù)用到其他消息通信之中昆稿。

  2. 既然有4個(gè)接收函數(shù)都可以充當(dāng)接收器,所以當(dāng)我們?cè)诮邮諘r(shí)息拜,同一個(gè)類的實(shí)例參數(shù)有兩個(gè)函數(shù)來接收會(huì)怎樣溉潭?答案是2個(gè)方法都執(zhí)行。因?yàn)镋ventBus只認(rèn)4大接收方法中的實(shí)例參數(shù)少欺。
    這個(gè)例子中喳瓣,三個(gè)方法都會(huì)被執(zhí)行。

    public void onEventMainThread(SecondEvent event) {  
        Log.d("harvic", "onEventMainThread收到了消息:" + event.getMsg());  
    }  

    public void onEventBackgroundThread(SecondEvent event){  
        Log.d("harvic", "onEventBackground收到了消息:" + event.getMsg());  
    }  

    public void onEventAsync(SecondEvent event){  
        Log.d("harvic", "onEventAsync收到了消息:" + event.getMsg());  
    }  

總結(jié)

EventBus在發(fā)送消息的時(shí)候赞别,簡化并統(tǒng)一了intent畏陕、handler、broadcast的操作氯庆;
在接收消息的時(shí)候蹭秋,又將如何進(jìn)行事件處理的線程封裝成四個(gè)方法提供使用扰付。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市仁讨,隨后出現(xiàn)的幾起案子羽莺,更是在濱河造成了極大的恐慌,老刑警劉巖洞豁,帶你破解...
    沈念sama閱讀 216,651評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盐固,死亡現(xiàn)場離奇詭異,居然都是意外死亡丈挟,警方通過查閱死者的電腦和手機(jī)刁卜,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,468評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來曙咽,“玉大人蛔趴,你說我怎么就攤上這事±欤” “怎么了孝情?”我有些...
    開封第一講書人閱讀 162,931評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長洒嗤。 經(jīng)常有香客問我箫荡,道長,這世上最難降的妖魔是什么渔隶? 我笑而不...
    開封第一講書人閱讀 58,218評(píng)論 1 292
  • 正文 為了忘掉前任羔挡,我火速辦了婚禮,結(jié)果婚禮上间唉,老公的妹妹穿的比我還像新娘绞灼。我一直安慰自己,他們只是感情好终吼,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,234評(píng)論 6 388
  • 文/花漫 我一把揭開白布镀赌。 她就那樣靜靜地躺著氯哮,像睡著了一般际跪。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上喉钢,一...
    開封第一講書人閱讀 51,198評(píng)論 1 299
  • 那天姆打,我揣著相機(jī)與錄音,去河邊找鬼肠虽。 笑死幔戏,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的税课。 我是一名探鬼主播闲延,決...
    沈念sama閱讀 40,084評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼痊剖,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了垒玲?” 一聲冷哼從身側(cè)響起陆馁,我...
    開封第一講書人閱讀 38,926評(píng)論 0 274
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎合愈,沒想到半個(gè)月后叮贩,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,341評(píng)論 1 311
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡佛析,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,563評(píng)論 2 333
  • 正文 我和宋清朗相戀三年益老,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寸莫。...
    茶點(diǎn)故事閱讀 39,731評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡捺萌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出膘茎,到底是詐尸還是另有隱情互婿,我是刑警寧澤,帶...
    沈念sama閱讀 35,430評(píng)論 5 343
  • 正文 年R本政府宣布辽狈,位于F島的核電站慈参,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏刮萌。R本人自食惡果不足惜驮配,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,036評(píng)論 3 326
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望着茸。 院中可真熱鬧壮锻,春花似錦、人聲如沸涮阔。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,676評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽敬特。三九已至掰邢,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間伟阔,已是汗流浹背辣之。 一陣腳步聲響...
    開封第一講書人閱讀 32,829評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留皱炉,地道東北人怀估。 一個(gè)月前我還...
    沈念sama閱讀 47,743評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親多搀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子歧蕉,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,629評(píng)論 2 354

推薦閱讀更多精彩內(nèi)容