Activity 與 Fragment 通訊(99%)完美解決方案

牛犇發表於2016-04-01

前言

最近一直在想著能否有一種更好的方案來解決:Android中Activity與Fragment之間通訊的問題,什麼叫更好呢,就是能讓Fragment的複用性高,效能還有好(不用反射),程式碼還要好維護,不需要為每對Activity和Fragment之間定義介面而發愁。

先簡單說下Javascript這門語言吧,或許有人就會問:我們們不是聊Android的java問題嗎?怎麼話題轉到JavaScript了。因為我的解決方案的啟發是從它來的,沒興趣的朋友可以略過。最近在學習javascript這門語言,同時自己搞Android(java)開發也有5年多時間了,所以在學習js的過程中,就會慣性的把這兩者進行比較。

與java語言的 嚴謹 相比 Javascript是一門“放蕩不羈”、”不拘小節”(寬泛)的語言。

為什麼要用“放蕩不羈”這個詞呢,下面是它的一個解釋:

放蕩不羈 [fàng dàng bù jī][解釋] 羈:約束。放縱任性,不加檢點,不受約束。

因為我覺得這個詞更能充分的體現js弱型別的特點。

在給變數賦值時 可以這樣寫:

還可以這樣寫:

甚至還可以這樣寫:

可以把任何型別的值賦給一個變數,也可以不加var關鍵字來宣告一個變數,是不是很任性,很不拘束啊。

“不拘小節”主要體現了JavaScript的語法更寬泛、更簡單的特點: 比如:

上面的程式碼說明了JavaScript在宣告函式時,不會有像java那麼嚴格的規定,語法不拘小節,語法更簡單(這裡沒有說java不好的意思)。

啟發點

JavaScript中有一個重要的點(萬事萬物皆物件),函式也不列外,並且函式可以作為另外一個函式的引數,如:

當我看到上面JavaScript中函式的用法時我眼前一亮,為啥我不可以借鑑之來解決android中activity與fragment通訊的問題呢?


Fragment的使命


先讓我們聊聊Fragment為什麼出現,這對於我們解決Activity與Fragment的通訊有幫助。一個新事物的產生總是為了解決舊事物存在的問題,Fragment是android3.0的產物,在android3.0之前解決手機、平板電腦的適配問題是很頭疼的,對ActivityGroup有印象的朋友,應該能深深的體會到ActivityGroup包裹的多個Activity之間切換等一系列的效能問題。由此Fragment誕生了。個人總結的Fragment的使命:

  • 解決手機、平板電腦等各種裝置的適配問題
  • 解決多個Activity之間切換效能問題
  • 模組化,因為模組化導致複用的好處

Fragment的使用

Fragment是可以被包裹在多個不同Activity內的,同時一個Activity內可以包裹多個Fragment,Activity就如一個大的容器,它可以管理多個Fragment。所有Activity與Fragment之間存在依賴關係。


Activity與Fragment通訊方案

上文提到Activity與Fragment之間是存在依賴關係的,因此它們之間必然會涉及到通訊問題,解決通訊問題必然會涉及到物件之間的引用。因為Fragment的出現有一個重要的使命就是:模組化,從而提高複用性。若達到此效果,Fragment必須做到高內聚,低耦合。

現在大家動動腳趾都能想到的解決它們之間通訊的方案有:handler,廣播,EvnetBus,介面等(或許還有別的方案,請大家多多分享),那我們就聊下這些方案。

handler方案:

先上程式碼

該方案存在的缺點:

  • Fragment對具體的Activity存在耦合,不利於Fragment複用
  • 不利於維護,若想刪除相應的Activity,Fragment也得改動
  • 沒法獲取Activity的返回資料
  • handler的使用個人感覺就很不爽(不知大家是否有同感)

廣播方案:

具體的程式碼就不寫了,說下該方案的缺點:

  • 用廣播解決此問題有點大材小用了,個人感覺廣播的意圖是用在一對多,接收廣播者是未知的情況
  • 廣播效能肯定會差(不要和我說效能不是問題,對於手機來說效能是大問題)
  • 傳播資料有限制(必須得實現序列化介面才可以)
    暫時就想到這些缺點,其他的缺點請大家集思廣益下吧。

EventBus方案:

具體的EventBus的使用可以自己搜尋下,個人對該方案的看法:

  • EventBus是用反射機制實現的,效能上會有問題(不要和我說效能不是問題,對於手機來說效能是大問題)
  • EventBus難於維護程式碼
  • 沒法獲取Activity的返回資料

介面方案

我想這種方案是大家最易想到,使用最多的一種方案吧,具體上程式碼:

這種方案應該是既能達到複用,又能達到很好的可維護性,並且效能也是槓槓的。但是唯一的一個遺憾是假如專案很大了,Activity與Fragment的數量也會增加,這時候為每對Activity與Fragment互動定義互動介面就是一個很頭疼的問題(包括為介面的命名,新定義的介面相應的Activity還得實現,相應的Fragment還得進行強制轉換)。 想看更好的解決方案請看下面章節。


大招來也

設計模式裡經常提到的一個概念就是封裝變化,同時受javascript中的函式的引數可以是函式物件的啟發下,我有了下面的想法,先上程式碼:程式碼地址

設計思路:

1. 用一個類來模擬Javascript中的一個Function

Function就是此類,它是一個基類,每個Functioon例項都有一個mFuncName 既然是方法(或者函式)它就有有引數和無引數之分
FunctionWithParam是Function的子類,代表有引數的方法類,方法引數通過泛型解決
FunctionNoParamAndResult是Function的子類,代表無參無返回值的方法類

2. 一個可以存放多個方法(或者函式)的類

Functions類就是此類,下面簡單介紹下Functions有4個主要方法:

  • addFunction(FunctionNoParamAndResult function) 新增一個無參無返回值的方法類
  • addFunction(FunctionWithParam function) 新增一個有參無返回值的方法類
  • invokeFunc(String funcName) 根據funcName呼叫一個方法
  • invokeFunc(String funcName,Param param) 根據funcName呼叫有參無返回值的方法類

使用舉例:程式碼地址

每個app都有的基礎activity(BaseActivity)

其中的一個activity:

每個app都會有的基礎fragment(BaseFragment)

MainActivity對應的MainFragment


看到這您是不是覺得已經結束了,當然是沒有了,因為還有2個問題沒解決。方法返回值和方法接收多個引數的問題。

方法返回值的問題

上程式碼:程式碼地址

FunctionWithResult無引數有返回值的方法類
FunctionWithParamAndResult 有引數也有返回值的方法類
在Functions類中定義新增和呼叫這2種方法類的 相應方法。

其次是方法含有多個引數的問題

在解決此問題時我想了很多辦法(比如怎樣引入多個泛型,但最終以失敗告終,希望有看了這篇文章的朋友可以多提下寶貴意見)。然後我就想到了用Bundle來解決多引數的問題,把多個引數放到Bundle中,但是在往Bundle中塞入資料時得有一個對應的key值,生成key值以及記住key值(記住key值是為了從Bundle中取資料)是一個繁瑣的事。同時Bundle不能傳遞非序列化物件。所以就封裝了一個FunctionParams類解決以上問題,請看類的實現: 程式碼地址

FunctionParams封裝了取引數的功能,比如:

取物件引數的功能,不需要傳人key值,只需要傳人需要即將取出來的類的Class例項即可

FunctionParamsBuilder類,看它的名字就知道是用了設計模式裡的Builder(構建)模式。該類是用來存放引數的,當所有的引數都存放完畢後呼叫create()方法建立一個FunctionParams物件事物都是有兩面性的,有缺點就有優點,只不過是在某些場合下優點大於缺點,還是反之。
FunctionParams解決了以上提到的Bundle傳遞多引數種種不便的問題,但同時FunctionParams也有一個缺點就是存引數的順序與取引數的順序一定要一致,比如:

但是這種缺點函式的定義來看也不是缺點。

Activity與Fragment之間的通訊是通過Functions的,即把變化的部分封裝在Functions是類中,Functions起一個橋樑作用。

此方案優點:

  • Fragment與Activity的耦合性幾乎沒有
  • 效能也好(沒用反射)
  • 可以從Activity獲取返回資料
  • 擴充套件性好(新增加的成對的Activity與Fragment之間的通訊只需做以下幾步:
    1.新增加Activity只需要覆蓋BaseActivity中的 setFunctionsForFragment(int fragmentId) 方法,把相應的回撥函式加入。
    2.相應的Fragment定義函式key值即可)

問題:大家關於傳遞多引數是否有更好的見解?有的話加我qq:704451290,或者發我郵箱704451290@qq.com

總結

簡單總結為以下幾點:

  • Fragment的使命
  • Activity與Fragment之間通訊的解決方案(handler,廣播,EventBus,介面)的優缺點。
  • 我自己關於Activity與Fragment之間通訊的解決方案(Functions),其實解決的主要是Fragment呼叫Activity的方案。希望大家能多提寶貴意見,多交流。程式碼地址

打賞支援我寫出更多好文章,謝謝!

打賞作者

打賞支援我寫出更多好文章,謝謝!

任選一種支付方式

Activity 與 Fragment 通訊(99%)完美解決方案 Activity 與 Fragment 通訊(99%)完美解決方案

相關文章