Android-多狀態載入佈局的開發-Tips

大俠咕咚發表於2017-12-21

本文將結合自己的專案開發實踐,簡單分享一下關於多狀態 Layout 的開發實踐 Tips。

個人主頁 咕咚

博文地址: loading_layout_practice

什麼是多狀態 Layout

對於大多數 App 而言,專案中都有多狀態載入 View 這種需求,如下圖所示。

demo

對應到開發中,我們通常會開發一個對應的自定義 layout 用於根據頁面不同的狀態來顯示不同的提示 view。

在專案中,我們大多會在開發初期就把這套 layout 框架寫好,然後其他人的自己的開發過程中直接使用即可。如下所示:

<name.gudong.MJMultipleStatusLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <ListView
        android:id="@+id/lv_activity_center"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</name.gudong.MJMultipleStatusLayout>
複製程式碼

這篇文章不討論如何去實現這樣的自定義 loading layout,Github 上這樣的 layout 太多了,這裡主要思考、總結在實際開發中開發這樣的自定義 Layout 時應該注意那些地方。

但是為了說明方便,這裡還是採用的方案簡單敘述一下。(為了後文描述方便,這裡把這個多狀態自定義 Layout 先稱為 MultipleStatusLayout。)

實現方案

在實現 MultipleStatusLayout 時,首先選擇繼承一個 ViewGroup 作為自己的父類,然後預設把內部的第一個子 View 作為 ContentView,其它各種情形下對應要顯示的 layout view,根據不同的載入狀態,在 MultipleStatusLayout 中通過動態 addView 去控制對應 layout 的載入顯示,也可以通過 ViewStub 把不同情形的 layout 進行懶載入,然後對外提供不同的方法,方便外部呼叫、控制不同狀態下的 layout 顯示。

嗯,簡單說來就是這樣,原理很簡單,實現起來也沒什麼技術難度,對於一般的開發人員只要一開始明白具體的產品邏輯和實現思路,相信花不了多少時間就可以完成這樣的 MultipleStatusLayout。具體這種方式的實現可以參看一個開源專案 的實現。

Tips

考慮到 MultipleStatusLayout 開發完成後,會在專案中的很多頁面中應用,而且很多時候是作為頁面頂級父容器而存在,所以開發過程中一定要注意其效能還有穩定性,否則一旦出現問題,整個專案中應用到該 MultipleStatusLayout 的頁面都會隨之出現問題。

以下就從效能角度、可維護性、穩定性等方面考慮出發,列舉一些開發 tips。

選擇最合理的父容器

首先 FrameLayout、RelativeLayout、LinearLayout 都可以作為 MultipleStatusLayout 的父類,拋開現在的應用場景不談,都知道 RelativeLayout 在 layout 時需要 measure 兩次,所以對於一個未來要在很多頁面中使用的 Layout ,把 RelativeLayout 作為父類這個方案首先 pass 掉。

這裡關於 RelativeLayout 多說兩句,儘管在內部 layout 時它會執行兩次 measure 但是也不能說 RelativeLayout 有效能問題,否則 Android Studio 的 activity 生成模板中也不會使用 RelativeLayout 作為預設根佈局(AndroidStudio3.0 之前),Google 使用 RelativeLayout 作為模板預設佈局容器應該是考慮到 RelativeLayout 的另一個優點:使用 RelativeLayout 可以有效降低佈局巢狀的深度。如果做過佈局優化的話,大家應該知道佈局層次越深,layout 效能就越差,官方的效能優化建議也是讓佈局結構寬而淺,而不是窄而深,所以這裡預設設定為 RelativeLayout 根佈局是有道理的。

但是因為 MultipleStatusLayout 中顯示的 view 大都需要居中顯示,所以使用 RelativeLayout 相對比較容易控制居中位置,這可能是很多人選擇 RelativeLayout 作為父類的初衷。這裡自己可以做一下權衡。

關於 LinearLayout 和 FrameLayout,如果按照上一節提到的實現方案,其實都可以採用,不過考慮到該類 Layout 的應用場景,建議選擇 FrameLayout。

因為MultipleStatusLayout 未來在大多數情況下是作為頁面父容器存在的,既然是父容器,內容可能會有各種變化,這時使用 LinearLayout 這種線性佈局就會在佈局時顯得特別侷限,比如一些頁面可能需要在 MultipleStatusLayout 之上顯示一個 FloatActionButton 或者其他的 view,這時使用 FrameLayout 就會好做很多也會靈活很多。

選擇最優的載入 View 方式

如何控制這些多狀態對應的 View ? 對於一般的情形,至少有兩種 View 型別,一種是載入中的 loading 樣式 view,一種是異常狀態的 layout view,當然還可能有更多具體的情形。

不同的樣式對應一個不同的佈局,為了簡便我們可以一次性的把所有狀態對應的佈局都寫在一個 layout 佈局裡,然後可以通過控制隱藏、顯示來根據不同的狀態來展示不同 view,這是最直接的想法。

但是,只要多思考一步,就會發現這種方式非常不可取。因為很多時候,MultipleStatusLayout 作為一個父容器只關心自己的 ContentView,異常頁面和載入頁面甚至可能沒有機會出現,但是現在這樣做就表示,這個頁面不論有沒有異常或者載入邏輯,你的佈局裡都會存在對應的 layout 佈局程式碼。這樣在介面繪製時就會白白耗掉多餘的時間。

而且這個 Layout 後續會在專案很多頁面用到,所以這裡的佈局耗時問題放大後就顯得很嚴重。

鑑於此,取而代之的更好的做法應該是動態去 addView,只有這個頁面第一次呼叫 loading 或者 showError 這樣的方法,我才去把對應佈局載入進來,當然這裡使用 ViewStub 也是一樣的效果。

這裡也就是說,只有呼叫了相應的方法,才去載入對應的 layout.

資源命名

其實這個問題是自己開發公用 Api 普遍面臨的問題,由於開發 MultipleStatusLayout 可能會定義一些顏色資源或者背景資源,這裡建議所有資源開頭使用一個固定的開頭,這樣可以防止跟主版本中的資源重名。進而早成一些奇怪的 UI 問題或者編譯問題。比如按鈕的背景你可以定義為 msl_btn_normal 而不是 btn_normal,文字的顏色你可以定義為 msl_text_white 而不是 text_white。這樣就可以有效避免一些資源衝突。

更多關於如何開發一個第三方庫,可以檢視天之界線開發第三方庫最佳實踐

提供友好的方法呼叫方式

既然是提供給大家使用,你就應該在方法命名上多花點心思,最好見名之意,這樣大家呼叫時也會舒服很多。

另外對外提供 Api 時也應該保持克制。不要一下子提供出去太多的方法,不論有用沒用,一下子都對外提供,這樣會對後續的維護造成隱形的負擔,因為提供的公用方法越多,表示你後續都要對這些方法進行維護。

最好的原則就是用到什麼提供什麼,不要提前設計。

另外,隨著專案迭代,對外提供方法的引數可能會變得多起來,比如以前顯示錯誤頁面的方法是

void showErrorView(Stirng error) 
複製程式碼

後來要增加自定義的 icon 或者點選事件響應,這時你就需要擴充套件方法引數,往往這種引數可能會變得很多不可收拾,這時建議使用 Build 構建模式設計,如下示例所示:

showErrorView(StatusViewConfig config) 
複製程式碼

呼叫時就可以這樣呼叫

showErrorView(new StatusViewConfig.StatusViewBuild(getContext())
                .icon(icon)
                .message(message)
                .subMessage(subMessage)
                .layoutMode(mLayoutMode)
                .withActionText(actionText, clickListener)
                .build())
複製程式碼

良好的文件

當你開發完成後,最好趁熱寫一份簡單明瞭的使用文件出來,這樣大家就可以直接對照文件使用你寫的庫,不用去關心程式碼實現,直接呼叫 Api 就可以完成自己的業務需求,同時也省的自己去面對面跟別人講怎麼使用了。

前段時間在 V 站上看到一個問題,說你們公司使用什麼樣的文件管理工具?其中有一個回答言簡意賅,很有意思,四個字 口口相傳

其實對於任何一個專案都是,有時間寫點文件,梳理自己思路的同時方便別人,何樂而不為。

其他

這種 Layout 在專案中會隨著專案的更新迭代而不斷的更新,所以一開始你就應該知道,後續還要不斷迭代更新,所以程式碼設計實現時應該留意擴充套件性。

另外,相關的開源方案有很多,建議一開始可以參考一些好的方案,然後結合自己專案的實際需求,來開發維護屬於自己專案的一套框架。因為多狀態 loading 載入提示框架大都和產品設計強相關,不具備一般的通用性。

下面列舉一些自己收集到的多狀態載入開源方案,方便對比。

開源方案

StatefulLayout

progress-activity

StateLayout

MultipleStatusView

總結

同樣功能的 Layout 可能在不同的業務場景下實現方式也會有很大的區別,所以不論哪種實現方式,無所謂好壞,只要適合就好。但是開發此類 Layout 要遵循的基本準則、以及要注意的點應該大都相同,希望此文可以給你一些啟示幫助。

關注我

相關文章