Android開發經驗實戰總結

之前一直想寫一篇總結 Android 開發經驗的文章,估計當時的我還達不到某種水平,因此思路跟不上,下筆又捉襟見肘。近日,思路較爲明朗,因而從新操起鍵盤開始碼字一番。先聲明一下哈,本人不是大廠的程序猿。去年畢業前,就一直在當前創業小團隊從事本身熱愛的打碼事業至今。下面總結是創建在我當前的技術水平和認知上寫的,若有不一樣見解歡迎留下評論互相交流。java

1.理解抽象,封裝變化

目前 Android 平臺上絕大部分開發都是用着 Java ,而跟 Java 這樣一門面向對象的語言打交道,難免要觸碰到 抽象封裝 的概念。我身邊接觸過的一些開發者,有一部分還對這些概念停留在寫一個抽象類、接口、或者一個方法(或抽象方法)。至於爲何,我不大清楚是他們表達不出來,仍是不理解。下面我也不高談闊論,直接舉例子來解釋我所理解的抽象。android

//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" 這一點並不須要關心,這就是一種對可能發生變化的地方進行抽象封裝的體現,它所帶來的好處就是下降手抖出錯的機率,同時方便咱們進行修改。git

基於抽象和封裝,Java 自己不少 API 在設計上就有這樣的體現,如 Collections 中的不少排序方法:
程序員

這些方法都是基於 List 這個抽象的列表接口進行排序,至於這是一個用什麼樣的數據結構實現 List(ArrayList 仍是 LinkedList),排序方法自己並不關心。看,是否是體現了 JDK 的設計人員的一種抽象編程的思惟,由於 List 的具體實現可能有千萬種,若是每一類 List 都要寫一套排序方法,估計要哭瞎了。github

小結:把容易出現變化的部分進行抽象,就是對變化的一種封裝。數據庫

2.選好"車輪"

一個項目的開發,咱們不可能一切從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加固寶、愛加密...json

通常狀況下,我在選擇是否引入一些開源框架主要基於如下幾個因素:api

  • 藉助搜索引擎,若是網上有一大波資料,說明使用的人多,出了問題好找解決方案;固然,若是廣泛出現差評,就能夠直接Pass掉了
  • 看框架的做者或團隊,如 JakeWharton大神Facebook團隊等。大神和大公司出品的框架質量相對較高,可保證後續的維護和bug修復,不容易爛尾;
  • 關注開源項目的 commit密度,issue的提交、回覆、關閉數量,watch數,start數,fork數等。像那種個基本不怎麼提交代碼、提issue又不怎麼回覆和修復的項目,最好就pass掉;

針對不開源SDK的選擇,也主要基於如下幾點去考慮:緩存

  • 藉助搜索引擎,查明口碑;
  • 不少第三方SDK的官網首頁都會告訴你,多少應用已經接入了此SDK,若是你看到有很多知名應用在上面,那這個SDK能夠考慮嘗試一下了。諸如,友盟官網:

  • 查看SDK使用文檔、它們的開發者社區、聯繫客服。好的SDK,使用文檔確定會詳細指引你。出了問題,上開發者社區提問,他們的開發工程師也會社區上回答。實在不行只能聯繫客服,若是客服的態度都讓你不爽,那就能夠考慮換別家的SDK了。

小結:選好 "車輪" ,事半功倍

3.抽象依賴第三方框架

爲何要抽象依賴於第三方框架呢?這裏和第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 ,你就會發現你須要喪心病狂的去改動幾十上百個地方的代碼,不只工做量大,並且還容易出錯。形成這樣的緣由,就在於項目和加載圖片的框架之間造成了強耦合,而實際上,項目自己不該該知道我具體用了哪一個加載圖片的框架。

正確的方式,應該是對框架作一個抽象的封裝,以應對將來發生的變化,我直接舉本身的開源項目 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);

這樣一來,切換框架所帶來的代價就會變得很小,這就是不直接依賴於框架所帶來的好處。固然,以上只是我比較簡單的封裝,你也能夠進行更加細緻的處理。

小結:預留變動,不強耦合於第三方框架

4.從 MVC 到 MVP

說實話,在沒接觸 MVP 的架構以前,一直都是使用 MVC 的模式進行開發。而隨着項目愈來愈大,Activity或者 Fragment裏面代碼愈來愈臃腫,看的時候想吐,改的時候想屎...這裏撇開其餘各類各樣的架構不談,只對比MVC 和 MVP 。

  • View:佈局的xml文件
  • Controller:Activity、Fragment、Dialog等
  • Model:相關的業務操做處理數據(如對數據庫的操做、對網絡等的操做都應該在Model層裏)

你會發現,若是 View 層只包含了xml文件,那咱們 Android 項目中對 View 層可作操做的程度並不大,頂多就是用include複用一下佈局。而 Activity 等簡直就是一個奇葩,它雖然歸屬於 Controller 層,但實際上也幹着 View 層的活(View 的初始化和相關操做都是在Activity中)。就是這種既是 View 又是 Controller 的結構,違背了單一責任原則,也使得 Activity 等出現了上述的臃腫問題。

  • View:Activity、Fragment、Dialog、Adapter等,該層不包含任何業務邏輯
  • Presenter:中介,View 與 Model 不發生聯繫,都經過 Presenter 傳遞
  • Model:相關的業務操做處理數據(如對數據庫的操做、對網絡等的操做都應該在Model層裏)

相比 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 吧

5.歸檔代碼

把一些經常使用的工具類或業務流程代碼進行歸類整理,加入本身的代碼庫(尚未本身我的代碼倉庫的童鞋能夠考慮建一個了)。如加解密、拍照、裁剪圖片、獲取系統全部圖片的路徑、自定義的控件或動畫以及其其餘他一些經常使用的工具類等。歸檔有助於提升你的開發效率,在遇到新項目的時候隨手便可引入使用。若是你想要更好的維護本身的代碼庫,不妨在不泄露公司機密的前提下,把這個私人代碼庫加上詳細文檔給開源出去。這樣可以吸引更多開發者來使用這些代碼,也能夠得到相應的bug反饋,以便於着手定位修復問題,加強這個倉庫代碼的穩定性。

小結:合理歸檔代碼,能夠的話,加以開源維護

6.性能優化

關於性能優化的問題,大致都仍是關注那幾個方面:內存、CPU、耗電、卡頓、渲染、進程存活率等。對於這些地方的性能優化思路和分析方法,網絡上已經有不少答案了,此處不作贅述。我只想說如下幾點:

  • 不要過早的作性能優化,app先求能用再求好用。在需求都還沒完成的時候把大量時間花在優化上是本末倒置的;
  • 優化要用實際數聽說話,藉助測試工具進行檢測(如:網易的Emmagee、騰訊的GT和APT,科大訊飛的iTest,Google的Battery Historian)。畢竟老闆問你比之前耗電下降多少,總不能回答下降了一些吧???
  • 任何不以減低性能損耗來作保活的手段,都是耍流氓。

小結:合理優化,數據量化

7.實踐新技術

Rxjava、React Native、Kotlin...開始興起後,身邊有不少開發者會跟風直上。學習新技術的精神是很是值得鼓勵的,但沒有通過一段時間實踐觀察,就擅自把新技術引入到商業項目中,則有失穩當。對於大公司的團隊來講,會有專門團隊或項目去研究這些新興技術,以肯定是否在本身的產品線開發中引入。但做爲小公司,是否是就意味着沒有實踐嘗試新技術的機會呢?並非!我的有如下幾點建議:

  • 藉助搜索引擎。看此項技術坑多很少,口碑不錯可是坑多的話,則說明當前技術不成熟,能夠耐心等待更新;
  • 考慮學習成本。學習成本太大且不容易招到懂這方面的開發者的狀況下,建議不要引入該技術;
  • 高仿一個項目並開源。若是你想引入 React Native 作商業開發,最好先高仿實現一個應用而後將其開源。這樣一些對 RN 感興趣的開發者會運行你的代碼並反饋 bug 給你,有助於你知道一些新技術的坑,並尋找相應的解決方案,最終肯定是否引入該技術;
  • 下降入門門檻。實踐新技術的過程儘可能加以詳細的文檔記錄,這會有助於下降項目組其餘同事對新技術的入門門檻,能夠的話,也將學習文檔開源,得到更多開發者對此份文檔的反饋,也可糾正一些文檔中的錯誤;
  • 結合實際業務。全部新技術的引入都要考慮是否符合當下的業務需求,我聽過有些程序猿想引入新技術的緣由是由於以爲這種技術很酷,網上說很好用,很啥啥啥...本身徹底沒弄過就人云亦云。有時候好無語,感受在會用一些技術就像在炫技同樣;

小結:空談誤國,實幹興邦

8.UML

UML,馴服代碼和了解項目結構的利器,本人也在學習和體驗其好處的路途上。無論遇到大小項目,有了它,能夠更好的理清一些脈絡結構。對付舊的龐大項目代碼,或者有志閱讀某些開源項目代碼的開發者,絕對是居家必備。

小結:工欲善其事,必先利其器

9.自造"車輪"

前面 2 提到,項目不可能從0開始,是須要引入不少第三方框架的。這裏並不與 2 互相違背,而是建議有想提升技術逼格的開發者,能夠在空暇時間去編碼實現一個框架。若是你對網絡訪問、圖片加載方面頗有研究看法,不妨把這些腦海裏的思想落實成具體的代碼。也許你會發現,你動手去實踐的時候,考慮的東西會多得多,本身最終獲得的也會更多。(特別建議那些看過不少開源代碼,又至今未本身動手自擼一發的

小結:不要停留在 api 調用的層面

10.擴大技術圈

有空又經濟能力承受得起的時候,不妨去參加一些本身感興趣的技術交流會。不少都有大牛上臺演講,聽聽人家的解決方案,拓寬一下本身看問題的思路,也能夠多參加一些含金量高的線上活動。我有挺多開發者朋友,就是參加活動的時候認識的,有時候遇到一些技術問題,還會互相探討交換一下解決思路。挺讚的!

小結:拓寬技術視野

11.寫博客總結

這個可能沒什麼好說的,你們看了標題就懂了。它最大的好處在於:

  • 系統化記錄本身的解決方案;
  • 方便往後本身回顧;
  • 有問題也會有讀者評論反饋,促進技術交流;
  • 加強本身書面表達能力;

小結:認真總結,不斷完善

12.找個對象

程序猿不要總是對着電腦,趕忙找個對象提高一下幸福感。聽說幸福感高的程序猿,編碼效率高,出bug概率小...

總結:作個面向對象的程序員

大概就想到這些了,之後要是再有想寫的,另開新篇。絮絮不休寫了這麼多,最關鍵的仍是本身要落實,千萬不要據說過太多道理,卻依然過很差這一輩子哈!!!!

相關文章
相關標籤/搜索