iOS到Android到底有多遠

在iOS開發混了4年之後,又重拾荒廢了4年的Android,感慨時間過得太快,有時間我會回顧下2010當年的iOS/Android平臺的萌芽期歷史;

從重拾摸索,再到上線兩個App,四五個月時間。這段時間的學習和研究,頗多衝擊和體會,所以就有了這篇文章。本文主要從iOS轉Android開發角度,對比兩個平臺應用開發的異同。希望對想學習Android開發的iOS開發者,或者想兼Android、iOS開發的同學,有所幫助。另,Objc也做過一期Android的專題,講的還可以:objc#Android#





1 語言

從iOS到Android開發,首先遇到的難題就是編程語言的改變,由於在大學時,跟着實驗室老師做項目就是用Java寫J2EE,所以Java的基礎知識還記得,簡單看看代碼基本就上手了。

編程語言的爭論對比由來已久,本文並不想引發月經般的口水戰,沒有全能的語言,只能說在不同語言有不同的適應場景。作爲比Java早生整整13年的Objective-C(Objective-C: 1982, Java: 1995,來源於Wiki),整體上來說,在語言特性方面落後於Java太多,那麼多年才發展到版本2,而Java已然來到了版本9。從iOS到Android,對比Objective-C和Java,更深刻理解Objective-C語言的侷限性:


1.1 泛型

泛型是現代編程語言非常重要而有用的特性,能夠提高代碼複用率,並約束參數類型提高安全性。泛型是一個非常強大特性,以至於有泛型編程這以課題。可惜Obective-C直到前不久的iOS9發佈,才更新對Collection類型支持泛型(官方文檔並沒有太多的說明泛型,自建類也是可以模仿Collection的泛型來實現泛型的支持,但支持得並不太理想);


1.2 枚舉

Objective-C是C的超集,完全兼容C語言,所以其枚舉還一直沿用着C語言的枚舉,但現有的面向對象的高級語言,已經將枚舉從一個基本數據類型升級爲類,這大大增強了枚舉的擴展性。如OC的枚舉只能是整型類型,如果需要獲得枚舉對應的數據(如枚舉的名稱),只能自己添加映射的代碼;但Java的枚舉,可以擴展出字段name,來對應枚舉的名稱;


1.3 抽象abstract

抽象類和抽象方法是OOP中重要的概念,而OC一直沒有支持該特性,這對於面向對象的抽象封裝是非常大的限制。


1.4 方法訪問控制

OC無法使用public/private/protected/final等關鍵字來控制方法的訪問權限。這其實是由OC是動態語言所決定的。從根本上來說,OC是不存在private方法的,因爲所有的方法都可以用performSelector來進行訪問,當然Java也可以通過反射實現類似的功能,所以從安全性上來說是基本一致的,不同的只是模塊封裝。

當然,跟Java相比,OC也有非常多的優勢,如比GC更高效的內存管理,更簡單易用的多線程,更爲明確的語義風格等。但從長遠來看,OC已落後Java一個身位,跟不上當前iOS/OSX系統的發展,而由於設計理念和歷史包袱存在,重新發明一種新的編程語言勢在必行,纔有了Swift的橫空出世、應運而生。Swift確實是新一代的編程語言,吸收了多種面向對象高級編程語言以及腳本語言的優點。隨着Swift 2.0的發佈並開源,該語言日趨穩定,建議iOS開發同學可以開始深入學習了,Swift替換Objective-C,很可能比你想象的要快。

反觀Android這邊,Java方興未艾,而Go作爲Google的明星編程語言,去年開始支持Android NDK的開發,而並沒有取代Java的計劃;以Java現有的基數以及在服務端的佔有率,Go想在要在Android平臺上取代Java,可能需要等到Go在Server端超過Java纔有可能。



2 系統平臺

不管是Windows、iOS、Android還是Blackberry,做應用開發都只能依託於這些系統平臺,能做的不能做的,都由平臺決定。這既是開發者的福利,也是開發者的悲哀。福利是因爲有個完善的平臺,開發者能夠很容易就能夠實現一些複雜的功能,如GPS、陀螺儀、圖片處理等;說是悲哀,是開發者已經限定在這個平臺的圈子內,就像人的生死,平臺已有生死,當一個平臺滅亡時,往往有一大批的開發者要麼一起死亡,要麼面臨轉型。所以,優秀的開發者都不應該禁錮在某個平臺上,多去思考和學習與平臺不相關的技術思想。iOS/Android有一天也會像Smbian一樣死去,但多線程、算法、內存管理、網絡、設計模式這些思想不會死去;也許OpenGL/OpenCV等也會死去,但圖形算法不會;就像今天Objective-C正慢慢被Swift取代,但Cocoa庫還是在傳承。

從iOS到Android,除了語言這一最直觀的差異之外,還有系統平臺上的差異。開發iOS應用 ,和開發Android應用之間,有哪些平臺設計上的異同呢?


2.1 Context

在開發Android應用過程中,你會發現,不管是第三方庫還是系統的API,基本都會有Context做爲初始化的參數,或者是傳遞參數:如public TextView(Context context)、 SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) 等;

Context,故名思議,就是程序的上下文,在Android開發中,主要有Application、Activity、Service、BroadcastReceiver、ContentProvider這幾種Context,類圖如下:

Context

引自http://blog.csdn.net/qinjuning/article/details/73106


具體的相關實現這裏不贅述,很多的API,之所以引用context,主要是爲了取得整個App的上下文。任何繼承Context抽象類的類實例都可以通過getApplicationContext()來獲取應用程序的上下文,用於訪問應用相關資源。查看android.content.Context.java的源代碼,其接口所實現的功能主要是訪問如安裝包、資源包、圖片、字符串、通知等應用相關資源。因此,假如你需要訪問這些資源,要麼繼承ContextWrapper,要麼使用context來進行初始化(參數傳遞)。

在這一方面,iOS採用了去中心化的方式。iOS將訪問資源都進行了模塊劃分及封裝,如使用使用[NSBundle mainBundle]訪問應用程序包資源;可以使用NSSearchPathForDirectoriesInDomains()來查找路徑;如取應用內圖片,Android需要由context取:context.getResources().getDrawable(id),而iOS則是[UIImage imageNamed:@“image_name"]等。兩種方式對比,個人覺得各有優劣:iOS訪問更爲方便,設計上有更大的自由度;而Android則讓訪問比較可控。


2.2 Activity

Activity就相當於iOS的ViewController,用法也基本上大同小異,上一節(Context)也介紹了Activity是繼承自Context。與iOS的ViewController的差異,主要有以下幾點:

1)與iOS的UIViewController需要App內部使用UINavigationController來管理不同,Android自己管理了Activity棧,用戶操作進入某個新的界面,一般會push一個新的Activity到棧頂,而用戶按Android的返回鍵,最頂的Activity會被Pop。具體的棧管理機制,可以查看文檔《Tasks and Back Stack

2)UIViewController可以嵌套多個UIViewController,但Activity一般不能嵌套多個Activity。說一般,是因爲之前Android有個ActivityGroup的組件,可以實現嵌套。但該組件在API level 13 已被廢棄。現在一般使用 Fragment 實現不同界面組合嵌套。


2.3 Intent

Intent,官方文檔的描述: an abstract description of an operation to be performed。是用來向其他App組件請求操作的消息對象。簡單的來說,Intent就是封裝數據和Action的消息體。主要用於:

1)啓動一個Activity: startActivity(Intent intent, Bundle options);

2)發送廣播: sendBroadcast(Intent intent)

3)啓動服務: startService(Intent intent)

在iOS方面,並沒有與Intent相對應的組件,iOS並沒有封裝消息體,一般都是使用Dictionary來傳遞信息,而切換到新的ViewController,一般都是直接通過接口約定好的對象參數來傳遞。

另外,Intent一般使用Extras來傳遞Action所需要的附加信息數據,而Extras中的數據類型只能是基礎數據類型、字符串和序列化(Serializable/Parcelable)數據,而不支持其他對象數據直接傳遞,主要原因是Intent不只是爲用於進程內的傳遞,也支持跨進程傳遞,所以無法直接傳遞對象。如果需要傳遞對象數據,就需要讓對象的類實現(Serializable/Parcelable)序列化接口,由於Serializable序列化性能較低,推薦使用Parcelable。但由於Java是自動支持Serializable,所以實現Serializable非常方便,只需要在類中聲明實現Serializable接口就可以了;而Parcelable就要複雜多了。希望Android能夠改進這一點。


2.4 其他

當然,兩個平臺設計上有較大差異的地方絕對不止上述幾處,本文只簡敘了常用的幾種場景,更多差異對比,等待你深入挖掘體會。



3 架構

所幸的是,我在開發出了iOS版應用之後開發Android版的,所以架構基本上可以直接沿用,只需要針對相應的語言特性做一些調整。現有的移動應用,基本都是從典型的MVC架構上來衍生或者演變,無論在iOS流行的MVVM還是Andorid上流行的MVP,本質上沒有太大的差別,而(MV)VM與(MV)P相比,更傾向於數據綁定而已。

架構,其實就是對軟件整體結構和組件的抽象,最終的目的,都是通過解耦來實現軟件的健壯性、擴展性和可維護性等。雖架構設計是脫離語言的結構抽象,但實現架構設計還是要依賴於平臺,最終落實到語言實現;


3.1 架構範式(architectural pattern):

前面已經說了,無論iOS還是Android,MVC都是這兩個平臺應用的基本架構設計範式,以下兩張圖可以說明一切:

iOS的MVC:

iOS MVC


Android的MVC

Android

上圖略有不同(在於Model與View的交互,標準的MVC中,兩者是有交互的,但實現中,兩者的交互比較少),但基本邏輯是一致的,都可以一一代入。所以,無論是iOS開發工程師轉Android,或者是Android開發工程師轉iOS,只要過了語言關,看幾個示例,基本就理解了一個App的大體架構。


3.2 接口

兩個平臺基本沒有太大的差別,由於Android支持泛型和抽象類,所以Android的接口設計會比較靈活。這種靈活性,只有深入使用體驗纔會有深的體會,這裏不深入講解。但架構設計中,往往會忽略的就是接口的規範性和一致性。將接口進行統一的規範,會讓整個架構實現變得非常一致,團隊的每一個人只要瞭解了一個模塊的架構設計,就基本瞭解了全局架構計。這主要體現在:

  • 命名一致:如,獲取數據的方法,是使用 getXxxx(callBack),還是用 fetchXxxx(callBack)/loadXxxx(callBack)等等,諸如此類的一般性操作;統一命名,甚至於繼承同樣的父接口,能夠讓層與層間交互統一,形成統一的代碼規範。
  • 回調一致:制定統一的回調機制,在回調機制中可以加入線程切換的邏輯。如我們界面經常需要向業務邏輯層發起操作或者獲取數據,一般會在業務邏輯層使用異步線程來處理,完成之後在主線程回調,讓應用在主線程上去更新界面。


3.3 回調

回調其實也屬於接口設計,由於平臺上的差異,iOS的回調多使用委託(delegate)和Block,如:

//delegate
- (void)callBack
{
    if ([self.delegate respondsToSelector:@selector(doSomething)]) {
        [self.delegate doSomething];
    }
}



//block
- (void)callBackWithCompletion:(void (^)(bool isSuccessed))completion
{
    if (nil != completion) {
        completion(YES);
    }
}

而Java由於不支持Block,但支持匿名類(Anonymous class),所以Java的大部分回調也是委託和匿名類(都是代理)。如:

//Anonymous class
public abstract class WQBasicListener<T> {
/*
 * Callback
 */
public abstract void onFinish(T resultObj);

/*
 * Callback
 *
 * @param error        cause of task failure
 */
public abstract void onFailure(WQError error);

/*
 * Callback
 */
public abstract void onCancel();
}

public void callBack(WQBasicListener<String> listener) {
    String str = ...
    if (null != listener) {
        listener.onFinish(str);
    }
}

Block與匿名類,兩者非常相似,同屬於閉包(closures)的概念,都是傳遞代碼塊給被調用者進行回調;區別是:Block更爲簡單易用,而匿名類則作爲類對象來傳遞,可以進行泛化和封裝等,更爲強大。


3.4 多線程

我們爲什麼要用多線程?這是非常簡單的問題,但非常多的開發同學其實都無法正確回答。對於一個應用進程來講,資源其實是限定的,那把任務放在一個線程中串行執行,與切分成幾個任務再一個一個去執行有什麼區別呢?其實,對於限定的資源來說,多線程:一、合理規劃調度任務;簡單的來說,就是可以讓主要的任務先執行,不重要的任務等到比較空閒的時候再執行。就如應用先保證主線程渲染,其他加載數據的等任務等稍後異步再處理;二、支持並行;現在的CPU早已經進入了多核時代,多核就意味着任務可正真並行,而不是單一的流水線切分時間片。

現在的移動開發領域,基本上不存在單線程的應用,在進行架構設計時,筆者認爲多線程設計也是多線程設計中只要的一環,也是區分初級程序員和合格程序員最重要的因素之一。邏輯業務越複雜,就越需要抽象,越需要簡單的多線程設計方案。而由於平臺的不同,iOS與Android的多線程實現方式也是有很大的不同,但基本的概念和設計理念是一樣的:

  • 永遠不要阻塞主線程:iOS和Android都一樣,界面渲染都有個幀率,就是隔多少毫秒刷新一次界面,這樣就能夠保證App在用戶眼睛裏不會存在卡頓和拖影等。永遠不要阻塞主線程,把一切耗時的操作都搬到異步線程中去。寫完代碼,iOS可以用Instruments的Time Profiler + Core Animation跑一下,看看幀率是否正常,主線程的任務佔比;對應Android就是DDMS。

  • 按模塊設計線程:子模塊有自己獨立的線程,可以保證模塊中數據的線程安全,還能夠讓模塊中的任務按照循序執行,避免了死鎖的產生。當然,當涉及到模塊間的交互時,能夠使用異步就不要使用同步;如涉及到多線程訪問的時候,最好使用細粒度的鎖;這些措施都能夠保證死鎖的發生。

  • 根據任務複雜度劃分線程:在進行模塊設計的時候,不可能每個模塊的業務邏輯複雜度都是一樣的,總有一些模塊會比較複雜,或者經常被調用,此時,就需要考慮負載均衡;當該模塊任務是CPU密集型任務,則有兩種方案:一、在劃分細粒度的任務,放到不同的線程中執行;二、使用多線程來支持任務並行。但需要注意的是,這兩種方法都需要關注避免死鎖,以及數據的線程安全。

  • 合理的線程池機制:線程池就是爲了線程的複用,減少創建線程的消耗的同時,讓線程調度更爲合理。這方面兩個平臺都提供了不錯的Api支持,iOS這邊有Operation Queue和GCD,而Android則有Executor。iOS由於有GCD的存在,讓線程池的調用變得非常簡單,所以iOS基本上很少直接創建使用某個線程,而是直接使用GCD;而Executor與Operation Queue的用法基本一致,在Android上,自己創建線程並管理線程週期的邏輯會比較常見。



4 IDE

IDE,作爲開發者必備的工具,其易用性和穩定性實實在在的影響着開發者的效率和心情。截止到2015年6月30日,兩家自家的IDE發展都可圈可點。

  • iOS,Xcode基本是唯一的選擇。說基本是因爲還有AppCode。我是之前看一位大牛同事用才知道的。AppCode,JB出品,確實是非常Cool而高效的工具,如果是之前就使用JetBrains家IDE的同學,基本是上手即用,而且有一堆通用的插件直接使用,這對於使用Android Studio/IntelliJ IDEA開發Android的同學來說也是極大的福音,至少在IDE這一塊不需要太長的時間摸索熟悉。但對於初中級開發者,個人還是會推薦Xcode,原因基本上就等同於現在會推薦你使用Android Studio,而不是IntelliJ IDEA,更不是Eclipse一樣。畢竟是蘋果自家的工具,不僅集成有非常多的關鍵功能特性,如新語言特性支持、Debug輔助等,最主要的是有大量的用戶和WWDC等資源來學習和解決問題,更容易iOS開發中的關鍵功能和特性;當然,Xcode如語法提示弱,版本控制支持渣,經常性無緣無故Crash等諸多問題還是讓人深惡痛絕的。建議有一定經驗的開發者,AppCode與Xcode結合使用。至於Visual Studio?等它發佈了再說。

  • Android家的IDE主要就是Eclipse和Android Studio,由於Eclipse從一開始就是Android官方指定的IDE,知道三天前(2015年6月27日),Google宣佈終止對Eclipse的支持。個人一直知道Android Studio必然會代替Eclipse,這一天來得並不算早。筆者在大學的時候,用過MyEclipse折騰J2EE;到2010年的時,短暫使用Eclipse開發Android兩個月,後續斷斷續續使用了下,對Eclipse一直感覺一般;所以在2014年末重新拾起Android的時候,就拋棄Eclipse,直接使用Android Studio v0.8,現在Android Studio的穩定版本已到1.2,發展迅速。Android Studio是Google和JetBrains合作,以IntelliJ IDEA爲基礎開發的IDE,即整合了IntelliJ IDEA強大的功能,又有Google自家的支持,前景一片大好。2V1,對比Eclipse的優勢,筆者不多說,各位可自己Google下。現在還在使用Eclipse的同學,該轉到Android Studio了。

以Xcode與Android Studio兩者對比,由於Android Studio直接是從IntelliJ IDEA發展而來,在代碼編輯方面會有壓倒性的優勢;而且整合了非常強大的Gradle構建工具,有着強大而易用的依賴管理和多工程構建;而這方面,Xcode就只能掩面了;不僅項目工程依賴管理複雜,而且一直沒有支持整合CocoaPoads來作第三方庫依賴。但Xcode在深入整合的Debug工具,以及強大的Instruments分析工具,較Java的DDMS要更爲強大易用。從發展來看,個人對這兩個IDE都非常有信心,



5總結

iOS到Android,到底有多遠?其實就是要看你在原本的路上走了多遠。作爲某個平臺上的應用開發者,除了深入理解平臺之外,我們儘量多關注平臺無關的基礎知識,這些才能決定你能走多遠。

技術的深度與廣度,一直是程序員矛盾點,不知道該如何取捨。其實走深度,到了某個瓶頸,你會發現需要其他知識來支持;而深入到了一定階段,又會發現拓展到了其他知識體系上。比如深入研究iOS系統,必然會研究到XUN,BSD,然後拓展到UNIX;而研究Android內核,又會拓展到了Linux;在這做JS都有Reat Native這樣怪物的今天,你還覺得。所以,建議初級開發者,一開始選擇一個自己喜歡的平臺,沉下心來研究,慢慢堆砌自己的城牆,希冀着成爲長城的那一天。


ps:研究Android時間並不長,有錯漏的地方還望同學不吝指正。

在iOS開發混了4年之後,又重拾荒廢了4年的Android,感慨時間過得太快,有時間我會回顧下2010當年的iOS/Android平臺的萌芽期歷史;

從重拾摸索,再到上線兩個App,四五個月時間。這段時間的學習和研究,頗多衝擊和體會,所以就有了這篇文章。本文主要從iOS轉Android開發角度,對比兩個平臺應用開發的異同。希望對想學習Android開發的iOS開發者,或者想兼Android、iOS開發的同學,有所幫助。另,Objc也做過一期Android的專題,講的還可以:objc#Android#





1 語言

從iOS到Android開發,首先遇到的難題就是編程語言的改變,由於在大學時,跟着實驗室老師做項目就是用Java寫J2EE,所以Java的基礎知識還記得,簡單看看代碼基本就上手了。

編程語言的爭論對比由來已久,本文並不想引發月經般的口水戰,沒有全能的語言,只能說在不同語言有不同的適應場景。作爲比Java早生整整13年的Objective-C(Objective-C: 1982, Java: 1995,來源於Wiki),整體上來說,在語言特性方面落後於Java太多,那麼多年才發展到版本2,而Java已然來到了版本9。從iOS到Android,對比Objective-C和Java,更深刻理解Objective-C語言的侷限性:


1.1 泛型

泛型是現代編程語言非常重要而有用的特性,能夠提高代碼複用率,並約束參數類型提高安全性。泛型是一個非常強大特性,以至於有泛型編程這以課題。可惜Obective-C直到前不久的iOS9發佈,才更新對Collection類型支持泛型(官方文檔並沒有太多的說明泛型,自建類也是可以模仿Collection的泛型來實現泛型的支持,但支持得並不太理想);


1.2 枚舉

Objective-C是C的超集,完全兼容C語言,所以其枚舉還一直沿用着C語言的枚舉,但現有的面向對象的高級語言,已經將枚舉從一個基本數據類型升級爲類,這大大增強了枚舉的擴展性。如OC的枚舉只能是整型類型,如果需要獲得枚舉對應的數據(如枚舉的名稱),只能自己添加映射的代碼;但Java的枚舉,可以擴展出字段name,來對應枚舉的名稱;


1.3 抽象abstract

抽象類和抽象方法是OOP中重要的概念,而OC一直沒有支持該特性,這對於面向對象的抽象封裝是非常大的限制。


1.4 方法訪問控制

OC無法使用public/private/protected/final等關鍵字來控制方法的訪問權限。這其實是由OC是動態語言所決定的。從根本上來說,OC是不存在private方法的,因爲所有的方法都可以用performSelector來進行訪問,當然Java也可以通過反射實現類似的功能,所以從安全性上來說是基本一致的,不同的只是模塊封裝。

當然,跟Java相比,OC也有非常多的優勢,如比GC更高效的內存管理,更簡單易用的多線程,更爲明確的語義風格等。但從長遠來看,OC已落後Java一個身位,跟不上當前iOS/OSX系統的發展,而由於設計理念和歷史包袱存在,重新發明一種新的編程語言勢在必行,纔有了Swift的橫空出世、應運而生。Swift確實是新一代的編程語言,吸收了多種面向對象高級編程語言以及腳本語言的優點。隨着Swift 2.0的發佈並開源,該語言日趨穩定,建議iOS開發同學可以開始深入學習了,Swift替換Objective-C,很可能比你想象的要快。

反觀Android這邊,Java方興未艾,而Go作爲Google的明星編程語言,去年開始支持Android NDK的開發,而並沒有取代Java的計劃;以Java現有的基數以及在服務端的佔有率,Go想在要在Android平臺上取代Java,可能需要等到Go在Server端超過Java纔有可能。



2 系統平臺

不管是Windows、iOS、Android還是Blackberry,做應用開發都只能依託於這些系統平臺,能做的不能做的,都由平臺決定。這既是開發者的福利,也是開發者的悲哀。福利是因爲有個完善的平臺,開發者能夠很容易就能夠實現一些複雜的功能,如GPS、陀螺儀、圖片處理等;說是悲哀,是開發者已經限定在這個平臺的圈子內,就像人的生死,平臺已有生死,當一個平臺滅亡時,往往有一大批的開發者要麼一起死亡,要麼面臨轉型。所以,優秀的開發者都不應該禁錮在某個平臺上,多去思考和學習與平臺不相關的技術思想。iOS/Android有一天也會像Smbian一樣死去,但多線程、算法、內存管理、網絡、設計模式這些思想不會死去;也許OpenGL/OpenCV等也會死去,但圖形算法不會;就像今天Objective-C正慢慢被Swift取代,但Cocoa庫還是在傳承。

從iOS到Android,除了語言這一最直觀的差異之外,還有系統平臺上的差異。開發iOS應用 ,和開發Android應用之間,有哪些平臺設計上的異同呢?


2.1 Context

在開發Android應用過程中,你會發現,不管是第三方庫還是系統的API,基本都會有Context做爲初始化的參數,或者是傳遞參數:如public TextView(Context context)、 SQLiteOpenHelper(Context context, String name, CursorFactory factory, int version) 等;

Context,故名思議,就是程序的上下文,在Android開發中,主要有Application、Activity、Service、BroadcastReceiver、ContentProvider這幾種Context,類圖如下:

Context

引自http://blog.csdn.net/qinjuning/article/details/73106


具體的相關實現這裏不贅述,很多的API,之所以引用context,主要是爲了取得整個App的上下文。任何繼承Context抽象類的類實例都可以通過getApplicationContext()來獲取應用程序的上下文,用於訪問應用相關資源。查看android.content.Context.java的源代碼,其接口所實現的功能主要是訪問如安裝包、資源包、圖片、字符串、通知等應用相關資源。因此,假如你需要訪問這些資源,要麼繼承ContextWrapper,要麼使用context來進行初始化(參數傳遞)。

在這一方面,iOS採用了去中心化的方式。iOS將訪問資源都進行了模塊劃分及封裝,如使用使用[NSBundle mainBundle]訪問應用程序包資源;可以使用NSSearchPathForDirectoriesInDomains()來查找路徑;如取應用內圖片,Android需要由context取:context.getResources().getDrawable(id),而iOS則是[UIImage imageNamed:@“image_name"]等。兩種方式對比,個人覺得各有優劣:iOS訪問更爲方便,設計上有更大的自由度;而Android則讓訪問比較可控。


2.2 Activity

Activity就相當於iOS的ViewController,用法也基本上大同小異,上一節(Context)也介紹了Activity是繼承自Context。與iOS的ViewController的差異,主要有以下幾點:

1)與iOS的UIViewController需要App內部使用UINavigationController來管理不同,Android自己管理了Activity棧,用戶操作進入某個新的界面,一般會push一個新的Activity到棧頂,而用戶按Android的返回鍵,最頂的Activity會被Pop。具體的棧管理機制,可以查看文檔《Tasks and Back Stack

2)UIViewController可以嵌套多個UIViewController,但Activity一般不能嵌套多個Activity。說一般,是因爲之前Android有個ActivityGroup的組件,可以實現嵌套。但該組件在API level 13 已被廢棄。現在一般使用 Fragment 實現不同界面組合嵌套。


2.3 Intent

Intent,官方文檔的描述: an abstract description of an operation to be performed。是用來向其他App組件請求操作的消息對象。簡單的來說,Intent就是封裝數據和Action的消息體。主要用於:

1)啓動一個Activity: startActivity(Intent intent, Bundle options);

2)發送廣播: sendBroadcast(Intent intent)

3)啓動服務: startService(Intent intent)

在iOS方面,並沒有與Intent相對應的組件,iOS並沒有封裝消息體,一般都是使用Dictionary來傳遞信息,而切換到新的ViewController,一般都是直接通過接口約定好的對象參數來傳遞。

另外,Intent一般使用Extras來傳遞Action所需要的附加信息數據,而Extras中的數據類型只能是基礎數據類型、字符串和序列化(Serializable/Parcelable)數據,而不支持其他對象數據直接傳遞,主要原因是Intent不只是爲用於進程內的傳遞,也支持跨進程傳遞,所以無法直接傳遞對象。如果需要傳遞對象數據,就需要讓對象的類實現(Serializable/Parcelable)序列化接口,由於Serializable序列化性能較低,推薦使用Parcelable。但由於Java是自動支持Serializable,所以實現Serializable非常方便,只需要在類中聲明實現Serializable接口就可以了;而Parcelable就要複雜多了。希望Android能夠改進這一點。


2.4 其他

當然,兩個平臺設計上有較大差異的地方絕對不止上述幾處,本文只簡敘了常用的幾種場景,更多差異對比,等待你深入挖掘體會。



3 架構

所幸的是,我在開發出了iOS版應用之後開發Android版的,所以架構基本上可以直接沿用,只需要針對相應的語言特性做一些調整。現有的移動應用,基本都是從典型的MVC架構上來衍生或者演變,無論在iOS流行的MVVM還是Andorid上流行的MVP,本質上沒有太大的差別,而(MV)VM與(MV)P相比,更傾向於數據綁定而已。

架構,其實就是對軟件整體結構和組件的抽象,最終的目的,都是通過解耦來實現軟件的健壯性、擴展性和可維護性等。雖架構設計是脫離語言的結構抽象,但實現架構設計還是要依賴於平臺,最終落實到語言實現;


3.1 架構範式(architectural pattern):

前面已經說了,無論iOS還是Android,MVC都是這兩個平臺應用的基本架構設計範式,以下兩張圖可以說明一切:

iOS的MVC:

iOS MVC


Android的MVC

Android

上圖略有不同(在於Model與View的交互,標準的MVC中,兩者是有交互的,但實現中,兩者的交互比較少),但基本邏輯是一致的,都可以一一代入。所以,無論是iOS開發工程師轉Android,或者是Android開發工程師轉iOS,只要過了語言關,看幾個示例,基本就理解了一個App的大體架構。


3.2 接口

兩個平臺基本沒有太大的差別,由於Android支持泛型和抽象類,所以Android的接口設計會比較靈活。這種靈活性,只有深入使用體驗纔會有深的體會,這裏不深入講解。但架構設計中,往往會忽略的就是接口的規範性和一致性。將接口進行統一的規範,會讓整個架構實現變得非常一致,團隊的每一個人只要瞭解了一個模塊的架構設計,就基本瞭解了全局架構計。這主要體現在:

  • 命名一致:如,獲取數據的方法,是使用 getXxxx(callBack),還是用 fetchXxxx(callBack)/loadXxxx(callBack)等等,諸如此類的一般性操作;統一命名,甚至於繼承同樣的父接口,能夠讓層與層間交互統一,形成統一的代碼規範。
  • 回調一致:制定統一的回調機制,在回調機制中可以加入線程切換的邏輯。如我們界面經常需要向業務邏輯層發起操作或者獲取數據,一般會在業務邏輯層使用異步線程來處理,完成之後在主線程回調,讓應用在主線程上去更新界面。


3.3 回調

回調其實也屬於接口設計,由於平臺上的差異,iOS的回調多使用委託(delegate)和Block,如:

//delegate
- (void)callBack
{
    if ([self.delegate respondsToSelector:@selector(doSomething)]) {
        [self.delegate doSomething];
    }
}



//block
- (void)callBackWithCompletion:(void (^)(bool isSuccessed))completion
{
    if (nil != completion) {
        completion(YES);
    }
}

而Java由於不支持Block,但支持匿名類(Anonymous class),所以Java的大部分回調也是委託和匿名類(都是代理)。如:

//Anonymous class
public abstract class WQBasicListener<T> {
/*
 * Callback
 */
public abstract void onFinish(T resultObj);

/*
 * Callback
 *
 * @param error        cause of task failure
 */
public abstract void onFailure(WQError error);

/*
 * Callback
 */
public abstract void onCancel();
}

public void callBack(WQBasicListener<String> listener) {
    String str = ...
    if (null != listener) {
        listener.onFinish(str);
    }
}

Block與匿名類,兩者非常相似,同屬於閉包(closures)的概念,都是傳遞代碼塊給被調用者進行回調;區別是:Block更爲簡單易用,而匿名類則作爲類對象來傳遞,可以進行泛化和封裝等,更爲強大。


3.4 多線程

我們爲什麼要用多線程?這是非常簡單的問題,但非常多的開發同學其實都無法正確回答。對於一個應用進程來講,資源其實是限定的,那把任務放在一個線程中串行執行,與切分成幾個任務再一個一個去執行有什麼區別呢?其實,對於限定的資源來說,多線程:一、合理規劃調度任務;簡單的來說,就是可以讓主要的任務先執行,不重要的任務等到比較空閒的時候再執行。就如應用先保證主線程渲染,其他加載數據的等任務等稍後異步再處理;二、支持並行;現在的CPU早已經進入了多核時代,多核就意味着任務可正真並行,而不是單一的流水線切分時間片。

現在的移動開發領域,基本上不存在單線程的應用,在進行架構設計時,筆者認爲多線程設計也是多線程設計中只要的一環,也是區分初級程序員和合格程序員最重要的因素之一。邏輯業務越複雜,就越需要抽象,越需要簡單的多線程設計方案。而由於平臺的不同,iOS與Android的多線程實現方式也是有很大的不同,但基本的概念和設計理念是一樣的:

  • 永遠不要阻塞主線程:iOS和Android都一樣,界面渲染都有個幀率,就是隔多少毫秒刷新一次界面,這樣就能夠保證App在用戶眼睛裏不會存在卡頓和拖影等。永遠不要阻塞主線程,把一切耗時的操作都搬到異步線程中去。寫完代碼,iOS可以用Instruments的Time Profiler + Core Animation跑一下,看看幀率是否正常,主線程的任務佔比;對應Android就是DDMS。

  • 按模塊設計線程:子模塊有自己獨立的線程,可以保證模塊中數據的線程安全,還能夠讓模塊中的任務按照循序執行,避免了死鎖的產生。當然,當涉及到模塊間的交互時,能夠使用異步就不要使用同步;如涉及到多線程訪問的時候,最好使用細粒度的鎖;這些措施都能夠保證死鎖的發生。

  • 根據任務複雜度劃分線程:在進行模塊設計的時候,不可能每個模塊的業務邏輯複雜度都是一樣的,總有一些模塊會比較複雜,或者經常被調用,此時,就需要考慮負載均衡;當該模塊任務是CPU密集型任務,則有兩種方案:一、在劃分細粒度的任務,放到不同的線程中執行;二、使用多線程來支持任務並行。但需要注意的是,這兩種方法都需要關注避免死鎖,以及數據的線程安全。

  • 合理的線程池機制:線程池就是爲了線程的複用,減少創建線程的消耗的同時,讓線程調度更爲合理。這方面兩個平臺都提供了不錯的Api支持,iOS這邊有Operation Queue和GCD,而Android則有Executor。iOS由於有GCD的存在,讓線程池的調用變得非常簡單,所以iOS基本上很少直接創建使用某個線程,而是直接使用GCD;而Executor與Operation Queue的用法基本一致,在Android上,自己創建線程並管理線程週期的邏輯會比較常見。



4 IDE

IDE,作爲開發者必備的工具,其易用性和穩定性實實在在的影響着開發者的效率和心情。截止到2015年6月30日,兩家自家的IDE發展都可圈可點。

  • iOS,Xcode基本是唯一的選擇。說基本是因爲還有AppCode。我是之前看一位大牛同事用才知道的。AppCode,JB出品,確實是非常Cool而高效的工具,如果是之前就使用JetBrains家IDE的同學,基本是上手即用,而且有一堆通用的插件直接使用,這對於使用Android Studio/IntelliJ IDEA開發Android的同學來說也是極大的福音,至少在IDE這一塊不需要太長的時間摸索熟悉。但對於初中級開發者,個人還是會推薦Xcode,原因基本上就等同於現在會推薦你使用Android Studio,而不是IntelliJ IDEA,更不是Eclipse一樣。畢竟是蘋果自家的工具,不僅集成有非常多的關鍵功能特性,如新語言特性支持、Debug輔助等,最主要的是有大量的用戶和WWDC等資源來學習和解決問題,更容易iOS開發中的關鍵功能和特性;當然,Xcode如語法提示弱,版本控制支持渣,經常性無緣無故Crash等諸多問題還是讓人深惡痛絕的。建議有一定經驗的開發者,AppCode與Xcode結合使用。至於Visual Studio?等它發佈了再說。

  • Android家的IDE主要就是Eclipse和Android Studio,由於Eclipse從一開始就是Android官方指定的IDE,知道三天前(2015年6月27日),Google宣佈終止對Eclipse的支持。個人一直知道Android Studio必然會代替Eclipse,這一天來得並不算早。筆者在大學的時候,用過MyEclipse折騰J2EE;到2010年的時,短暫使用Eclipse開發Android兩個月,後續斷斷續續使用了下,對Eclipse一直感覺一般;所以在2014年末重新拾起Android的時候,就拋棄Eclipse,直接使用Android Studio v0.8,現在Android Studio的穩定版本已到1.2,發展迅速。Android Studio是Google和JetBrains合作,以IntelliJ IDEA爲基礎開發的IDE,即整合了IntelliJ IDEA強大的功能,又有Google自家的支持,前景一片大好。2V1,對比Eclipse的優勢,筆者不多說,各位可自己Google下。現在還在使用Eclipse的同學,該轉到Android Studio了。

以Xcode與Android Studio兩者對比,由於Android Studio直接是從IntelliJ IDEA發展而來,在代碼編輯方面會有壓倒性的優勢;而且整合了非常強大的Gradle構建工具,有着強大而易用的依賴管理和多工程構建;而這方面,Xcode就只能掩面了;不僅項目工程依賴管理複雜,而且一直沒有支持整合CocoaPoads來作第三方庫依賴。但Xcode在深入整合的Debug工具,以及強大的Instruments分析工具,較Java的DDMS要更爲強大易用。從發展來看,個人對這兩個IDE都非常有信心,



5總結

iOS到Android,到底有多遠?其實就是要看你在原本的路上走了多遠。作爲某個平臺上的應用開發者,除了深入理解平臺之外,我們儘量多關注平臺無關的基礎知識,這些才能決定你能走多遠。

技術的深度與廣度,一直是程序員矛盾點,不知道該如何取捨。其實走深度,到了某個瓶頸,你會發現需要其他知識來支持;而深入到了一定階段,又會發現拓展到了其他知識體系上。比如深入研究iOS系統,必然會研究到XUN,BSD,然後拓展到UNIX;而研究Android內核,又會拓展到了Linux;在這做JS都有Reat Native這樣怪物的今天,你還覺得。所以,建議初級開發者,一開始選擇一個自己喜歡的平臺,沉下心來研究,慢慢堆砌自己的城牆,希冀着成爲長城的那一天。


ps:研究Android時間並不長,有錯漏的地方還望同學不吝指正。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章