iT邦幫忙

2021 iThome 鐵人賽

DAY 2
2
Mobile Development

Jetpack Compose X Android Architecture X Functional Reactive Programming系列 第 2

便利貼 App 專案介紹

Screenshot

https://user-images.githubusercontent.com/7949400/124440143-e457ba00-ddac-11eb-93f4-1d3470001528.gif

專案介紹

相信大家都有用過便利貼吧!在開會討論時便利貼是一個很好用的工具,不同的顏色可以代表不同的分類方式,在便利貼上也可以寫字、畫圖,另外還可以移動便利貼的位置來做一些整理。以下是這專案的基本需求:

專案需求

  • 使用者可以任意新增、刪除便利貼。
  • 使用者可以編輯便利貼上的文字以及背景顏色。
  • 使用者可以使用手勢任意拖拉便利貼的位置。
  • 可以與其他使用者一起線上編輯。

需求分析

這不是一個典型的 Mobile app ,我所謂的典型指的是可以使用 Android 內建元件來構建出整個 App 的版型,在這個 app 中,除了 Float Action Button,跟一些簡單的按鈕除外,我們必須要想辦法畫出這個 app 的核心 - 便利貼。

除此之外,線上共同編輯也是一個非常具有挑戰的點。如果使用 Restful api 呼叫的話,這個 app 會發生什麼事呢?由於這會是一個非常需要即時回饋的系統,在一分鐘也會執行非常多次的操作,所以一分鐘內光是一個使用者就有可能發出 30 個以上的 api 請求,每一個 api 請求會帶有很多的資訊像是 header、access token、JSON 等等, 這對 Server 會是一個很大的負負擔!同時,後端的資料庫也會有大量的讀寫需求,更何況還有排隊以及延遲的問題,有非常多的技術問題要被解決。但其實說了這麼多,後端也不是我的戰場,以上這些是依我的個人過往的經驗所能想得到的問題,說不定在擴大規模後又有更多更難解決的問題。

最後,在手勢拖拉的部分,我可以預期到的是,便利貼的位置是每一分每一秒都在改變的,而這個特性正好適合使用 Reactive programming 的方式來處理,Reactive programming 就是一個處理非同步事件流(Asynchronous event stream)的編程方式,而便利貼在某個時間點中的位置就可以當作是一個事件,一個單一手勢的位置,也可以是一個事件。因此當手勢的事件連在一起變成一個事件串流時,就可以利用這個事件串流產生出便利貼相對應的位置。除此之外,還有許多 Reactive programming 使用上的好處,關於 Reactive programming ,在後面的文章中會有更詳細的介紹。

技術選擇

View

其實大家應該都知道我選擇什麼技術了,因為標題已經寫的很明顯了,但是我還是要假設一下,如果使用傳統的 Android View 來做這個便利貼 App ,會怎麼做?

如果使用大家最熟悉 xml 的話,有辦法完成這個 App 嗎?很可惜的是動態的 UI 元件不是 xml 的強項,所以中間的這些便利貼無法使用單純的 xml 。所以下一個明顯的選項就是自定義 UI 元件 (Custom View),在這裡我想到以下兩種方式:

  1. 一個 View group + 多個 View ,每一個 View 就是一個便利貼。
  2. 一個 Custom View ,其中全部的便利貼都是使用 Canvas 跟 paint 畫出來的。

第一種方法的話,如何處理手勢的事件將會是一大挑戰,是要全部交給 View group 來處理呢?還是每個 View 各自處理?全部交給 View group 來處理的話就必須要有方法能夠知道現在的手指是不是有碰到哪一個便利貼,而且這些便利貼還有可能重疊,這就會需要一些數學計算了。那如果手勢處理交給每一個 View 自己來做呢?看起來比較可行,但是要如何將位置資訊傳出去呢?畢竟這些座標資訊還是要傳給後台才能讓其他使用者看到對吧?所以每一個 View 都可能會需要一個 callback 來處理這些事件,這樣做的話可能也要小心不要產生 memory leak。

再來是第二種方法,這個方法看起來彈性很大很自由,但是取而代之的就享受不到 Android 幫你做的繪圖優化,像是每次畫面更新就是整個畫面一起畫,第一種方法的話,只要每個 View 自己呼叫 invalidate() 就好,不會影響到其他在同一個 View group 的 View,所以效能上可能會比較差。再來繪製順序也要自己管理,因為再也沒有內建的 z 值可以保證顯示的順序。但是相對的,要在這個 View 裡面設計架構時就不會有太多限制,不會有 framework 來限制你手勢管理還有便利貼與整個畫面之間的交互關係。

invalidate: 這是 Android View 中的一個公開函式,呼叫這個函式之後,這個 View 所繪製的內容就會強制更新到最新狀態。

那 Jetpack Compose 呢?他能很簡單的解決上述的很多問題,包含繪製上的優化,元件之間的互動關係等等,甚至還有 Preview 可以讓你不用 Build app 也可以直接看到結果長怎樣。那缺點呢?怎麼可能沒缺點呢?缺點就是,雖然程式碼看起來簡單,但是不是很容易就可以學得起來,學完一整套到能夠實際上戰場要花相對多的時間。

不過現在拉回來以這個專案來說,由於我已經研究 Jetpack Compose 有一段時間,所以這對我來說學習不是一個阻礙,但如果這專案還有其他成員的話可能就要先想想,如果有很多 junior developer,就不會是個好選項。

Backend

後端的部分,使用 Firebase Firestore 是一個非常棒的選擇,首先我不需要花很多時間去建立一個 Server,而且 Firestore 這種 NoSQL 的方式也非常適合我這個 App 的特性,firestore SDK 使用上也非常簡單,關於更詳細的內容,我會在之後一起介紹。

Reactive

Reactive programming 現在有幾個主流的函式庫,我將會直接採用他們中的其中一個,自己打造輪子不是聰明的作法。主要的選項有:

  1. RxJava
  2. Coroutine Flow

在這邊我放棄使用潮潮的 Coroutine Flow ,因為前陣子在 side project 使用時,還是有部分的 Api 是 Experimental 的,所以依我看來還沒有 RxJava 那麼的成熟穩定,還有一個非常重要的點,就是我對 Flow 非常的不熟,很多我在 RxJava 能夠輕易做到的事,可能要在 Flow 上試錯不少次才能找到相對應的作法。

小結

以上就是這專案的介紹以及技術的選擇,技術的選擇上沒有絕對的對錯,團隊的組成、需求、對工具的熟悉程度都會是影響的因素。但是在技術的選擇上,要盡量避免盲目的追求最新潮流,很多工程師都會很喜歡做這件事(也包含我),如果我在這專案的選擇是 Coroutine Flow 而不是 RxJava 的話,我可以預見的是可能帶給讀者很多錯誤的資訊,而且想要花最多心力寫的知識內容也會因此而降低質量,不是我想看到的結果。


上一篇
前言與自我回顧
下一篇
Jetpack Compose intro
系列文
Jetpack Compose X Android Architecture X Functional Reactive Programming30

尚未有邦友留言

立即登入留言