這篇文章主要內容來自於之前我講的一個PPT文檔,現在將其整理如下。歡迎指正。以下的內容都是來自於我自身的經驗,歡迎大家多提自己的建議。
1、一些概念
模式的定義:
每個模式都描述了一個在我們的環境中不斷出現的問題,然後描述了該問題的解決方案的核心。通過這種方式,你可以無數次地使用那些已有的解決方案,無需在重複相同的工作。
什麼是設計模式?
設計模式是在某種特別的情況下,針對某種問題的某種典型、通用的解決方案。
我們是需要適當瞭解並學習一些設計模式,在程式開發過程中,總是會涉及到一些架構設計,模組設計之類的東西,如果能很好理解並運行設計模式,你所設計的模組或架構將會要穩定得多,因為這些設計模式它們都是通用的解決方案,是經過實踐經驗了的。
比如說,在程式裡,可能會有通知模組,A模組的資料發生變化,B模組需要得到通知,對於這樣的需要,你可能會想到用"廣播","訊息"或者"回調"的方式來解決,的確,剛才我所說的那三種也能解決,但是,這三種都是存在一些缺點,比如說廣播,用Intent來傳輸資料很困難,對於"訊息",無法很好的跟蹤,對於"回調",有可能你A與B模組根本不可相互訪問。此時,如果你會用觀察者模式的問題,這種問題可以很輕鬆解決。
當然,這裡是需要具體問題具體分析的,我主要的意思就是說,要適當利用模式,我們不能為了用模式而去用模式,我們是要用模式來解決我們實際的問題。
概念完整性
關於概念完整性,在《人月神話》一書在有大量的闡述,這裡,我把我的理解寫出來,與大家分享。
1)概念完整性是系統設計中最重要的考慮因素。當你的系統規模越大,這一點體現得越明顯。
2)為了擷取概念的完整性,設計必須由一個人或者具有共識的小型團隊來完成。這一點很好理解,關於設計,可以讓所有的人蔘與,但是決定權在少數人手裡,如果大家都想參與設計,這是根本沒有辦法保證系統設計是統一完整的。
3)要獲得概念上的完整性,就必須有人控制這些概念,類似於貴族的專制統治。這裡,對於團隊中的專案經理或架構師必須對項目有絕對的權威,不然,這個項目裡面的就無法統一號令。
4)概念完整性表現有:
- 開發過程中,需求、設計、編碼的一致性
- 整個程式具有統一的風格,比如對話方塊樣式,按鈕風格,色調等UI元素
- 整個程式具體統一的結構,比如不同模組訪問網路,它們的調用方式一致,例如非同步訪問都用回調方式通知結果,相同的功能應該提取成共通模組。
- 開發人員能很好的執行需求人員和設計人員的意圖。
- 有完整的文檔,需求文檔,設計文檔,測試文檔,處理流程的文檔等。
如何保持概念完整性
- 在制度上給予保證,產品的負責人必須建立技術上的絕對權威
- 技術負責人員(SE,SL)必須嚴格執行項目的需求,設計,必須深入到編碼細節
- 在不同階段,保持與所有人員的持續溝通,鼓勵開發人員提意見。
- 讓開發人員參與設計,但不決定設計
- 通過持續的反饋和溝通來實現模組重用
2、設計之前應該做什麼
2.1 共通類的設計
2.1.1 Widget設計
- TextView
- EditText
- Button
- Title bar
- Tool bar
- ...
為什麼要提供這些共通控制項?
- 統一字型大小,如App字型不隨系統字型變化而變化
- 統一UI式樣,如Button, EditText具有相同的背景等
- 複用代碼
2.1.2 Adapter Items
- 根據式樣,提取需要在AdapterView中顯示的Item
- 簡單的複合布局
- 自繪製,從而提高滑動效能
- ListView中放Gallery時,提高上下滑動效能
- 盡量最佳化繪製
資料驅動
- Adapter Items提供核心的方法
- setData(Object data)
- getData();
- Adapter#getView實現更加簡單
- 實現簡單
- 不會因為UI變化而變化
下面程式碼範例了Adapter#getView()方法的實現,它返回BookView,BookView提供方法來接收資料,至於BookView的顯示,則根據設定的資料來顯示,這就是資料驅動UI。
@Overridepublic View getView(int position, View convertView, ViewGroup parent) { if (null == convertView) { convertView = new BookView(getContext()); convertView.setLayoutParameter(new AbsListView.LayoutParameter(150, 150)); } Book book = m_bookList.get(position); BookView bookView = (BookView)convertView; bookView.setBook(book); return convertView;}
2.1.3 Dialog
- 擴充於Dialog類
- 提供Dialog關閉的事件
- Dialog的高度隨內容的變化而變化
- 可以設定按鈕的文字,可見度,字型等方法
- 設定按鈕點擊事件的listener
- 要考慮對話方塊的三個屬性:Title, Content area, Action buttons
2.1.4 Utility
- Log
- DateFormat
- Bitmap
- Notification
- Shared Preference
- Environment
- Device
- ...
2.2 Task管理
線程只是一種機制,保證我們要完成的任務不運行在UI線程(也就是說不阻塞UI),完成的任務才是我們關注的核心,因此,我們可以通過設計,把線程封裝,讓使用者根本感覺不到是線程,他只用關心他要做的事情就行了。
這裡,我們可以設計一種"非同步鏈式調用"的架構,把線程進行了封裝。使用都只需要這樣用:
new TaskManager().next(task1).next(task2).next(task3)..execute();
這裡,task1, task2, task3是順序執行的,舉個例子:我們要訪問網路,取得一個圖片,使用這個TaskManager我們需要3個task,
task1:顯示一個ProgressDialog。
task2:訪問網路,建立bitmap。
task3:關閉對話方塊,顯示bitmap。
這一點,可以參考CoreLib工程中的task.TaskManager類。
關於TaskManager,有以下幾點需要注意:
- 封裝了線程
- 讓調用者只關注自己的業務處理
- 保證順序鏈式地執行某一個任務
- 上一個任務的輸出,作為下一個任務的輸入
- 能暫停、恢複任何一個任務
2.3 緩衝設計
- 把記憶體佔用量大的對象存放在緩衝中,如bitmap
- 利用了LruCache類來實現
- 利用了AsyncTask類來載入bitmap
- 不用再手動釋放bitmap記憶體,該操作有風險
- 不用再關心AbsListView的scroll狀態
關於緩衝的更多詳細細節,請參考[ 請參考CoreLib工程中的cache包 ]。
這樣做,有什麼好處, 不用再手動釋放bitmap內在,該操作有風險,因為該bitmap是否有View引用,如果當一個View在試圖繪製一個已經回收的bitmap,這裡會拋出異常。
2.4 線程管理
無訊息迴圈的線程:
new Thread(null, new Runnable() { public void run() { // Do you works. }}, "Thread_name_xxx").start();
什麼情況下使用這種線程:
- 做完一件事情就結束,這件事發生頻率不高,比如從SD card中讀取圖片資料
- 不需要複用線程
在使用線程,最好給線程加上名字,這樣利用高度與跟蹤。
有訊息迴圈的線程:
這樣的線程擁有訊息迴圈,當訊息佇列中沒有訊息時,這個線程會被掛起。我們要做一件事情時,只需要給它發送一個訊息就行了。
這種情況通常是為了複用線程,不用頻繁建立線程,比如音樂播放器程式,專門啟動一個有訊息迴圈的線程來獲得音樂的專輯圖片。
我們通常還要建立一個與這個線程的訊息迴圈(Looper)相關聯的Handler,由它來處理訊息,注意,這做的事情是運行在後台線程的。
3,程式架構如何設計
Android程式的結構
- UI層
- 商務邏輯層
- 持久化資料(記憶體中,相當於全域資料)
- 資料加式(資料層的資料有時候需要進行加工成UI層需要的資料)
- 資料變化的通知機制
- 資料層
- 資料訪問(DB,檔案,網路等)
- 緩衝(圖片,檔案等)
- 設定檔(shared perference)
下面,我試著畫了一個Android程式的結構,如果有不好的地方,歡迎指正。
4,一些基本原則
下面列出一些通常的原則,我們應當在開發過程中遵循,歡迎補充與指正。
4.1 提供initialize()方法
在Activity.onCreate()或者View的構造方法中調用,在以後看代碼時,人們通常首先會去找initialize()這樣的方法。
4.2 封裝點擊事件
把View的點擊事件,提成方法,這樣在listener處只是一個方法調用者,一般的事件封裝為:onXXXClick(View v)。
4.3 設計一個BaseActivity類
讓所有的Activity都繼承自BaseActivity類,這樣,我們可以做很多有用的事情
- 定義共通屬性
- 顯示共通對話方塊(Progress dialog)
- 取得top activity
- 可以手動管理啟動的activity
4.4 設計Application類
- 存全域資料,比top activity, application context。
4.5 異常處理
- 報告功能是處理異常的精髓
- 在finally塊中執行清理操作
- 不要用try-catch-finally來判斷商務邏輯
- 考慮設計自訂的異常類
4.6 標註的使用
- 重寫的方法一定要加@Override
- 不使用的方法,不要刪除,可以標記為@Deprecated,這個做法在維護型的項目中特別有用。
4.7 註冊與反註冊
4.8 封裝Bitmap操作
我們應當把Bitmap操作封裝起來,比如從檔案載入,儲存,網路下載,動態計算sample size等。有了封裝後,我們可以對其集中最佳化。
4.9 繪製處理
一定要注意繪製方面的東西,不要在onDraw()/onTouchEvent()中建立新對象。