曾經一直想寫一篇總結 Android 開發經驗的文章,預計當時的我還達不到某種水平,因此思路跟不上,下筆又捉襟見肘。近日,思路較爲明朗。因而又一次操起鍵盤開始碼字一番。java
先聲明一下哈,本人不是大廠的程序員。去年畢業前。就一直在當前創業小團隊從事本身熱愛的打碼事業至今。如下總結是創建在我當前的技術水平和認知上寫的,若有不一樣見解歡迎留下評論互相交流。android
眼下 Android 平臺上絕大部分開發都是用着 Java ,而跟 Java 這樣一門面向對象的語言打交道。難免要觸碰到 抽象 和 封裝 的概念。我身邊接觸過的一些開發人員。有一部分還對這些概念停留在寫一個抽象類、接口、或者一個方法(或抽象方法)。git
至於爲何。我不大清楚是他們表達不出來,仍是不理解。程序員
如下我也不高談闊論,直接舉樣例來解釋我所理解的抽象。github
//Activity 間使用 Intent 傳遞數據的兩種寫法 如下均是僞代碼形式。請忽略一些細節
//寫法一
//SrcActivity 傳遞數據給 DestActivity
Intent intent = new Intent(this,DestActivity.class);
intent.putExtra("param", "clock");
SrcActivity.startActivity(intent);
//DestActivity 獲取 SrcActivity 傳遞過來的數據
String param = getIntent.getStringExtra("param");
//寫法二
//SrcActivity 傳遞數據給 DestActivity
Intent intent = new Intent(this,DestActivity.class);
intent.putExtra(DestActivity.EXTRA_PARAM, "clock");
SrcActivity.startActivity(intent);
//DestActivity 獲取 SrcActivity 傳遞過來的數據
public final static String EXTRA_PARAM = "param";
String param = getIntent.getStringExtra(EXTRA_PARAM);
寫法一。存在的問題是,假設 SrcActivity 和 DestActivity 哪一個把 "param" 打錯成 "para" 或者 "paran" 。傳遞的數據都沒法成功接收到。而寫法二則不會出現此類問題,因爲兩個 Activity 之間傳遞數據僅僅需要知道 EXTRA_PARAM 變量就能夠。至於 EXTRA_PARAM 變量到底是 "param" 、 "para" 、"paran" 這一點並不需要關心,這就是一種對可能發生變化的地方進行抽象封裝的體現。它所帶來的優勢就是減小手抖出錯的機率,同一時候方便咱們進行改動。數據庫
基於抽象和封裝,Java 自己很是多 API 在設計上就有這種體現,如 Collections 中的很是多排序方法:編程
這些方法都是基於 List 這個抽象的列表接口進行排序。至於這是一個用什麼樣的數據結構實現 List(ArrayList 仍是 LinkedList),排序方法自己並不關心。看,是否是體現了 JDK 的設計人員的一種抽象編程的思惟,因爲 List 的詳細實現可能有千萬種。假設每一類 List 都要寫一套排序方法,預計要哭瞎了。json
小結:把easy出現變化的部分進行抽象,就是對變化的一種封裝。api
一個項目的開發。咱們不可能一切從0作起,假設真是這樣,那相同要哭瞎。緩存
所以,善於借用已經作好的 "車輪" 很重要,如:
網絡訪問框架:okhttp、retrofit、android-async-http、volley
圖片載入框架:Android-Universal-Image-Loader、Glide、Fresco、Picasso
緩存框架:DiskLruCache、 Robospice
Json解析框架:Gson、Fastjson、Jackson
事件總線:EventBus、Otto
ORM框架:GreenDAO、Litepal
還有其它各類各樣開源的本身定義控件、動畫等。除了以上提到的開源框架,也包含一些不開源的SDK
數據統計:友盟統計,百度統計...
奔潰蒐集:騰訊bugly、bugtags...
雲存儲:七牛...
即便通信:環信、融雲、阿里百川...
推送:小米推送、騰訊推送、百度推送...
安全加固:360加固寶、愛加密...
普通狀況下,我在選擇是否引入一些開源框架主要基於下面幾個因素:
大神和大公司出品的框架質量相對較高。可保證興許的維護和bug修復,不easy爛尾;
針對不開源SDK的選擇,也主要基於下面幾點去考慮:
諸如。友盟官網:
好的SDK。使用文檔確定會具體指引你。出了問題。上開發人員社區提問,他們的開發project師也會社區上回答。實在不行僅僅能聯繫客服,假設客服的態度都讓你不爽,那就可以考慮換別家的SDK了。
小結:選好 "車輪" 。事半功倍
爲何要抽象依賴於第三方框架呢?這裏和第1點是互相照顧的,就是減小咱們對詳細某個框架的依賴性,從而方便咱們高速切換到不一樣的框架去。講到這裏,你可能認爲很是抽象。那我直接舉一個載入圖片的樣例好了。
若是你當前爲項目引入一個載入圖片的框架 —— Android-Universal-Image-Loader,最簡單的作法就是增長對應的依賴包後。在不論什麼需要載入圖片的地方寫上如下這種代碼段。
ImageLoader imageLoader = ImageLoader.getInstance(); // Get singleton instance
// Load image, decode it to Bitmap and display Bitmap in ImageView (or any other view
// which implements ImageAware interface)
imageLoader.displayImage(imageUri, imageView);
// Load image, decode it to Bitmap and return Bitmap to callback
imageLoader.loadImage(imageUri, new SimpleImageLoadingListener() {
@Override
public void onLoadingComplete(String imageUri, View view, Bitmap loadedImage) {
// Do whatever you want with Bitmap
}
});
這種作法最簡單粗暴,但是帶來的問題也最嚴重的。假設我有幾十上百個地方都這麼寫,而在某一天。我據說Facebook出了個神器 Fresco。想要換掉 Android-Universal-Image-Loader ,你就會發現你需要喪心病狂的去修改幾十上百個地方的代碼,不只工做量大,而且還easy出錯。形成這種緣由,就在於項目和載入圖片的框架之間造成了強耦合。而實際上,項目自己不該該知道我詳細用了哪一個載入圖片的框架。
正確的方式,應該是對框架作一個抽象的封裝。以應對將來發生的變化。我直接舉本身的開源項目 AndroidAlbum 中的一種封裝作法好了。
大體代碼例如如下:
//一、聲明 ImageLoaderWrapper 接口,定義一些抽象的載入接口方法
public interface ImageLoaderWrapper {
/** * 顯示 圖片 * * @param imageView 顯示圖片的ImageView * @param imageFile 圖片文件 * @param option 顯示參數設置 */
public void displayImage(ImageView imageView, File imageFile, DisplayOption option);
/** * 顯示圖片 * * @param imageView 顯示圖片的ImageView * @param imageUrl 圖片資源的URL * @param option 顯示參數設置 */
public void displayImage(ImageView imageView, String imageUrl, DisplayOption option);
/** * 圖片載入參數 */
public static class DisplayOption {
/** * 載入中的資源id */
public int loadingResId;
/** * 載入失敗的資源id */
public int loadErrorResId;
}
}
// 二、將 UniversalAndroidImageLoader 封裝成繼承 ImageLoaderWrapper 接口的 UniversalAndroidImageLoader ,
//這裏代碼有點長,感興趣可以查看項目源代碼中的實現 https://github.com/D-clock/AndroidAlbum
// 三、作一個ImageLoaderFactory
public class ImageLoaderFactory {
private static ImageLoaderWrapper sInstance;
private ImageLoaderFactory() {
}
/** * 獲取圖片載入器 * * @return */
public static ImageLoaderWrapper getLoader() {
if (sInstance == null) {
synchronized (ImageLoaderFactory.class) {
if (sInstance == null) {
sInstance = new UniversalAndroidImageLoader();//<link>https://github.com/nostra13/Android-Universal-Image-Loader</link>
}
}
}
return sInstance;
}
}
//四、在所有需要載入圖片的地方做例如如下的調用
ImageLoaderWrapper loaderWrapper = ImageLoaderFactory.getLoader();
ImageLoaderWrapper.DisplayOption displayOption = new ImageLoaderWrapper.DisplayOption();
displayOption.loadingResId = R.mipmap.img_default;
displayOption.loadErrorResId = R.mipmap.img_error;
loaderWrapper.displayImage(imagview, url, displayOption);
這樣一來,切換框架所帶來的代價就會變得很是小,這就是不直接依賴於框架所帶來的優勢。固然,以上僅僅是我比較簡單的封裝,你也可以進行更加仔細的處理。
小結:預留變動,不強耦合於第三方框架
說實話,在沒接觸 MVP 的架構以前,一直都是使用 MVC 的模式進行開發。
而隨着項目愈來愈大。Activity或者 Fragment裏面代碼愈來愈臃腫,看的時候想吐,改的時候想屎...這裏撇開其它各類各樣的架構不談,僅僅對照MVC 和 MVP 。
你會發現,假設 View 層僅僅包括了xml文件,那咱們 Android 項目中對 View 層可作操做的程度並不大。頂多就是用include複用一下佈局。
而 Activity 等簡直就是一個奇葩,它儘管歸屬於 Controller 層,但實際上也幹着 View 層的活(View 的初始化和相關操做都是在Activity中)。就是這樣的既是 View 又是 Controller 的結構,違背了單一責任原則。也使得 Activity 等出現了上述的臃腫問題。
相比 MVC,MVP在層次劃分上更加清晰了,不會出現一人身兼二職的狀況(有些單元測試的童鞋,會發現單元測試用例更好寫了)。在此處你可以看到 View 和 Model 之間是互不知道對方存在的,這樣應對變動的優勢更大。很是多時候都是 View 層的變化,而 Model 層發生的變化會相對較少,遵循 MVP 的結構開發後。改起來代碼來也沒那麼蛋疼。
這裏也有地方需要注意,因爲大量的交互操做集中在 Presenter 層中,因此需要把握好 Presenter 的粒度。一個 Activity 可以持有多個 View 和 Presenter。這樣也就可以避開一個碩大的 View 和 Presenter 的問題了。
推薦兩個不錯的 MVP 架構的項目給你們。還不明確的童鞋,可以自行體會一下其設計思想:
https://github.com/pedrovgs/EffectiveAndroidUI
https://github.com/antoniolg/androidmvp
小結:去加以實踐的理解 MVP 吧
把一些常用的工具類或業務流程代碼進行歸類整理。增長本身的代碼庫(尚未本身我的代碼倉庫的童鞋可以考慮建一個了)。如加解密、拍照、裁剪圖片、獲取系統所有圖片的路徑、本身定義的控件或動畫以及其其它他一些常用的工具類等。
歸檔有助於提升你的開發效率,在遇到新項目的時候隨手就能夠引入使用。假設你想要更好的維護本身的代碼庫,最好仍是在不泄露公司機密的前提下。把這個私人代碼庫加上具體文檔給開源出去。這樣可以吸引不少其它開發人員來使用這些代碼,也可以得到對應的bug反饋,以便於着手定位修復問題。加強這個倉庫代碼的穩定性。
小結:合理歸檔代碼,可以的話。加以開源維護
關於性能優化的問題。大致都仍是關注那幾個方面:內存、CPU、耗電、卡頓、渲染、進程存活率等。
對於這些地方的性能優化思路和分析方法,網絡上已經有很是多答案了。此處不作贅述。
我僅僅想說下面幾點:
畢竟老闆問你比曾經耗電減小多少,總不能回答減小了一些吧?
?
?
小結:合理優化,數據量化
Rxjava、React Native、Kotlin...開始興起後。身邊有很是多開發人員會跟風直上。學習新技術的精神是很是值得鼓舞的,但沒有通過一段時間實踐觀察,就擅自把新技術引入到商業項目中,則有失穩當。對於大公司的團隊來講,會有專門團隊或項目去研究這些新興技術。以肯定是否在本身的產品線開發中引入。
但做爲小公司,是否是就意味着沒有實踐嘗試新技術的機會呢?並不是!
我的有下面幾點建議:
實踐新技術的過程儘可能加以具體的文檔記錄,這會有助於減小項目組其它同事對新技術的入門門檻,可以的話,也將學習文檔開源,得到不少其它開發人員對此份文檔的反饋,也可糾正一些文檔中的錯誤。
所有新技術的引入都要考慮是否符合當下的業務需求,我聽過有些程序員想引入新技術的緣由是因爲認爲這樣的技術很是酷。網上說很是好用。很是啥啥啥...本身全然沒弄過就人云亦云。有時候好無語,感受在會用一些技術就像在炫技同樣;
小結:空談誤國,實幹興邦
UML,馴服代碼和了解項目結構的利器,本人也在學習和體驗其優勢的路途上。不管遇到大小項目,有了它,可以更好的理清一些脈絡結構。對付舊的龐大項目代碼。或者有志閱讀某些開源項目代碼的開發人員。絕對是居家必備。
小結:工欲善其事,必先利其器
前面 2 提到,項目不可能從0開始,是需要引入很是多第三方框架的。這裏並不與 2 互相違背。而是建議有想提升技術逼格的開發人員,可以在空閒時間去編碼實現一個框架。假設你對網絡訪問、圖片載入方面很是有研究看法。最好仍是把這些腦海裏的思想落實成詳細的代碼。或許你會發現。你動手去實踐的時候。考慮的東西會多得多,本身終於獲得的也會不少其它。
(特別建議那些看過很是多開源碼。又至今未本身動手自擼一發的)
小結:不要停留在 api 調用的層面
有空又經濟能力承受得起的時候,最好仍是去參加一些本身感興趣的技術交流會。很是多都有大牛上臺演講。聽聽人家的解決方式,拓寬一下本身看問題的思路,也可以多參加一些含金量高的線上活動。
我有挺多開發人員朋友,就是參加活動的時候認識的,有時候遇到一些技術問題,還會互相探討交換一下解決思路。
挺讚的!
小結:拓寬技術視野
這個可能沒什麼好說的,你們看了標題就懂了。它最大的優勢在於:
小結:認真總結,不斷無缺
程序員不要總是對着電腦。趕忙找個對象提高一下幸福感。聽說幸福感高的程序員。編碼效率高,出bug概率小...
總結:作個面向對象的程序猿
大概就想到這些了,之後要是再有想寫的。另開新篇。絮絮不休寫了這麼多,最關鍵的仍是本身要落實,千萬不要據說過太多道理,卻依舊過很差這一輩子哈!
!!。