Douya - 開源的 Material Design 豆瓣客戶端。
豆芽
Douban, Yet Another.
另一個 Material Design 的豆瓣客戶端。
開放源代碼
由于豆瓣關閉了個人開發者 API Key 申請,此應用已不可能向公眾發布,因此決定提前開放源代碼,也給有興趣者做些 HACKING。
以下是關于豆芽的說明。
部分特性
預覽
圖片:
視頻:
關于名字
豆芽的名字取自“Douban, Yet Another”的縮寫和中文詞語“豆芽”的拼音正好相同的巧合。
取名之后,我才得知豆瓣的 Windows Phone 客戶端的名字也叫做“豆芽”。所以相對于豆瓣官方應用“一個叫‘豆瓣’的App”,也正好將這個應用稱為“另一個叫豆芽的應用”了。
為什么要有豆芽?
直接訪問豆瓣的所有人里,最普遍而一致的用法是圍繞電影、電視、書、唱片、活動(我們叫做”條目”的東西)的評分評論、發現和討論。我們會把和網站同步的評分評論作為一個起點和基礎,在手機上重新構建圍繞個人興趣的發現和討論。
一個叫“豆瓣”的App——豆瓣日志
直接訪問豆瓣的所有人里,最普遍而一致的用法是圍繞電影、電視、書、唱片、活動(我們叫做”條目”的東西)的評分評論、發現和討論。我們會把和網站同步的評分評論作為一個起點和基礎,在手機上重新構建圍繞個人興趣的發現和討論。
一個叫“豆瓣”的App——豆瓣日志
豆瓣從來不是一個單一的網站,而對于豆瓣的用法自然不盡相同。使用豆瓣是為了獲取信息,但信息的獲取是基于條目和算法,還是基于友鄰和人,這個問題在豆瓣的多次改版中大概一直懸而未決。
這次,一個叫“豆瓣”的應用選擇的是基于條目的推薦。但我個人作為一個重度豆瓣用戶,重視的卻恰好是基于人的推薦,喜歡的是友鄰間的雞犬相聞,以及閑逛時從條目評論、廣播、日記中發現新友鄰的驚喜。正如我在某次“還我舊版”運動中聽到的聲音,“不管怎么改版,只要友鄰們還在就好”,改版是豆瓣不斷良好發展的必經之路,但這句話中對友鄰的珍重又令我感受到了豆瓣最寶貴的特質。
豆瓣作為一個工具的價值可以通過條目很好體現,但豆瓣作為一個獨一無二的社區,只能通過它獨有的、克制的、以人為本的方式才能維系。作為一個普通但也深愛豆瓣的用戶,我希望豆瓣在這個方向上也不要失落,因為一個只有工具屬性的網站對我而言將再也沒有這樣的歸屬感。
我在這一點上與豆瓣應用有了不同的追求,并且恰好有一些這方面的能力,又恰好豆瓣提供了開放的 API,于是就想要將這個想法實現出來了。
選擇開始豆芽這個項目,還有一個原因是我希望在豆瓣繼續看到平臺原生的設計。
豆瓣廣播在幾年前就已經是國內少有的幾個 Android Design 的應用,這一點一直令我欽佩和喜愛。在豆瓣應用最開始的版本中,也曾有過 Material Design 的嘗試,但隨著和 iOS 風格設計的雜糅,逐漸顯得不合時宜,以至于最終選擇了完全的 iOS 風格。我對此一直感到有些遺憾,況且 Material Design 也是一款更加優秀的設計語言。所以,我希望實現未能見到的另一種可能性。
指導原則
豆芽的最終目標是為豆瓣中基于友鄰的信息獲取方式提供在移動端的便利。為了優雅地實現這個目標,豆芽將主要遵循以下的原則:
- 遵循 Material Design 規范,且指導思想優先于細節規定。
- 像素完美,但更注重以人為本。
- 實現精確,代碼可以自我辯護。
- 行為合格,支持屏幕旋轉和平板布局。
- 功能崇尚簡約,不打擾用戶。
- 行為默認值合理,且用戶可調節。
- 積極表現豆瓣特性,如廣播、友鄰、豆郵等。
- 通過細節設計,提倡用心、考慮到他人的內容。
規則可以被打破,但前提是理解規則。
功能架構
豆芽的架構將與當前網站的設計十分類似。
你可能會問,難道豆芽只是要做一個豆瓣網站的移動端界面么?并非如此。豆芽的最終目標是為基于友鄰的信息獲取方式提供便利,所以架構設計也是為此服務。而架構與當前網頁端設計基本相同,則是因為現在網頁端正是一個符合這個目標的設計,并且與移動端的導航也可以很好地契合。
讓我們詳細地規劃一下豆芽吧。
導航采用抽屜一級導航 + 選項卡二級導航的方式。工具欄上將顯示全局的動作。
- 工具欄
- 提醒:所有類別的提醒,可以查看歷史提醒
- 豆郵:用戶間的郵件往來,希望鼓勵鄭重而非聊天。
- 搜索:立即訪問想要的內容。
- 用戶:點擊后顯示個人頁面,相當于“我的豆瓣”。
- 首頁
- 友鄰廣播:友鄰互動、友鄰推薦、系統定制的推薦。
- 九點:友鄰的日記、博客文章等,有深度的內容。
- 一刻:全站范圍的熱門內容推薦。
- 同城:基于地理位置的內容。
- 線上活動:基于共同興趣的內容。
- 讀書
- 分類瀏覽、首頁推薦:入口,以及最有可能發現新內容的地方。
- 我讀:管理自己的讀書標記、創造內容。
- 動態:查看友鄰的閱讀動態,互動、獲得推薦。
- 豆瓣猜:基于算法的推薦。
- 電影
- 類似讀書。
- 音樂
- 類似讀書。
- 設置:提供應用設置等。
在子頁面設計中,豆芽將盡量鼓勵長內容和用心的互動。因為我相信只有豆瓣值得這樣嘗試。
實現狀況
我在最初的二十天內沖刺實現了應用的網絡層、賬戶系統等基礎架構,和查看友鄰廣播需要的大部分功能,大約 8000 行代碼。
在接下來的八十天中,由于課業、其他事情和速度瓶頸,實現過程有所減慢。但是,應用的細節功能和界面交互都正在不斷地被實現和優化。代碼量達到了 14000 行,同時為此應用而寫作的多個開源庫的數千行代碼并沒有被計入。
目前實現了友鄰廣播的查看、回應、刪除等操作,提醒的查看,以及相關的設置條目。剩下的工作也正在繼續進行中。
實現架構
數據層面
應用除了對少數內容進行緩存,其他內容均直接從網絡獲取。
- 基于 Android 賬戶系統提供用戶賬戶和身份認證。
- 使用 Volley 及部分自定義增強處理網絡請求。
- 使用 Gson 自動填充數據模型。
- 使用 Glide 加載圖片。
- 使用 DiskLRUCache 及自定義增強對首頁數據進行緩存。
- 使用 EventBus 同步不同頁面間對象狀態。
界面層面
使用 Support Library 中的 AppCompat、Design、CardView、RecyclerView 進行 Material Design 實現,在必要時引入/自己寫作第三方庫以實現部分界面元素和效果。
使用框架的 Shared Element Transition 實現在 Android 5.0 以上的界面過渡動畫。
界面實現一般分為 Activity、Fragment、Adapter 三個模塊,分別負責作為容器,發起請求、展示數據和用戶交互,以及數據/交互綁定。
實現難點
網絡請求
Volley 本身是一個不算十分完備的庫,對于請求參數、重試、認證等方面都需要開發者自己實現。在豆芽中,應用對 Volley 進行了包裝,增加了以上功能,并且盡力做到了通用,為之后 API 層建立提供了很多方便。
磁盤緩存
DiskLRUCache 是一個只實現了同步讀取寫入的庫,因此豆芽對其進行了包裝,提供了異步讀寫的 API,正確實現,提高了應用的響應速度。
狀態同步
由于各個界面獨自獲取數據,數據本身與常規的 ContentProvider 機制中不同,是去中心化的,即可能遇到狀態不同步的問題。
具體地說,即有可能用戶在廣播詳情界面中點贊后,回到主界面列表視圖,發現并未更新狀態。
而豆芽解決方案則是使用 EventBus,在請求完成后通知所有界面刷新同一數據。
界面動畫
Android 5.0 以上提供了 SharedElementTransition,然而默認情況下共享的界面元素在動畫時卻會被放置在其他界面元素之上,導致其突然越過 AppBar 或 StatusBar 的情況。
通過大量的文檔閱讀、源代碼分析和調試,經過大約一周的時間,最終實現了較為理想的效果。
屏幕旋轉
Android 在屏幕旋轉時,會銷毀視圖和 Activity 并重建,此時如何保存視圖狀態和已加載的數據、正在進行的網絡請求即是問題。
Android 對部分視圖狀態提供了自動保存恢復,而豆芽對于其他需要保存的狀態則通過自定義的 onSaveViewState()
和onRestoreViewState()
。
對于數據,豆芽通過自定義的一個無界面的 RetainDataFragment
進行數據保留,并且接口十分簡單易用。
同時,由于網絡請求的異步特性,豆芽通過自定義的一個 RequestFragment
實現了網絡請求在 Activity 重建期間的保留,并且能夠在 Activity 重建完成后將請求前的狀態和請求結果回調至新的 Activity。
平板適配
Android 本身的資源系統提供了對不同配置的很好支持,通過建立不同的資源文件,即可在手機和平板上使用不同的界面設定。
此外,由于采用了 RecyclerView,通過在運行時判斷當前設備配置,可以動態給界面設置為 1、2、3 列視圖,充分利用屏幕空間。
啟動速度
Android 默認在冷啟動應用進程至能夠調用 Activity.onCreate()
前會加載應用主題中的背景作為預覽,而默認背景是白色,與應用在上部擁有綠色 AppBar 的效果不相匹配。
為了生成適應于不同屏幕大小、系統版本的圖片,我使用 bash 編寫了一系列腳本,并實現了一個通用的模板化 SVG 格式,詳情見 MaterialColdStart 和 AndroidSVGScripts。
經過自定義窗口背景和其他優化,應用在手機上已經可以達到立即啟動的視覺效果。
派生開源庫
為此項目誕生的五個開源庫:
- MaterialColdStart,800+ Stars
- MaterialProgressBar,500+ Stars
- CustomTabsHelper,200+ Stars
- MaterialEditText
- SystemUiHelper
第三方庫
關于使用
請參考 HACKING.md,自行提供 API Key 和 Secret 即可使用。
請不要安裝從不可靠的來源獲取的 APK,以免泄漏您的用戶名和密碼。