iOS程式設計師必須知道的Android要點

chris發表於2014-05-06

在移動應用飛速發展的今天,APP只針對IOS平臺進行開發已經不夠了,如今Android在移動裝置佔有近80%的市場,如此大量的潛在使用者怎麼能被忽略掉呢。

在這篇文章中,本人會介紹在IOS開發中,怎麼學習一些Android開發的理念,Android和IOS功能上本身有一定的相似之處,但是具體實現的方式各異,所以這篇文章會使用一個專案例子進行對比,說明怎麼在這兩個平臺上分別去實現這個任務。

除了瞭解IOS的開發知識,本文還需要對Java有一定的瞭解,並能夠安裝和使用ADT(Android Development Tools)。此外,如果你是一個Android新手,那麼請試試去看看Android的官方教程—— building your first app,非常有用。

UI設計簡要說明

本文不會深入研究關於IOS和Android兩個平臺之間的使用者體驗或者設計模式之間的差異,不過如果能夠理解Android上的一些優秀的UI範例也很有幫助:ActionBar、Overflow menu、back button share action等等。假如你很想嘗試Android開發,那麼強烈推薦你去Google Play Store上購置一臺Nexus5,然後把它作為你日常使用的裝置使用一週,然後嘗試仔細瞭解這個作業系統的各種功能和擴充套件特性,如果開發者連作業系統的各種使用規則都不瞭解,那麼做出來的產品一定有問題。

程式語言的應用框架

Objective-C和Java之間有很多不同之處,如果把Objective-C的程式設計風格帶到Java裡面的話,很多程式碼也許會和底層的應用框架衝突。簡單地說,就是需要注意一些區別:

  • 去掉Objective-C裡面的類字首,因為Java裡有顯式的名稱空間和包結構,所以就沒必要用類字首了。
  • 例項變數的字首用“m”,不用“_”,在寫程式碼的過程中要多利用JavaDoc文件。這樣能使程式碼更清晰,更適合團隊合作。
  • 注意檢查NULL值,Objective-C對空值檢查做的很好,不過Java沒有。
  • 不直接使用屬性,如果需要settergetter,需要建立一個getVariableName()方法,然後顯式呼叫它。如果直接使用“this.object”不會呼叫自定義的getter方法,你必須使用this.getObject這樣的方法。
  • 同樣的,方法命名時帶有getset字首來標示它是gettersetter方法,Java的方法很喜歡寫成actions或者queries等,比如Java會使用getCell(),而不用cellForRowAtIndexPath

專案結構

Android應用程式主要分為兩部分。第一部分是Java原始碼,以Java包結構排布,也可以根據自己的喜好進行結構排布。最基本的結構就是分為這幾個頂層目錄:activities、fragments、views、adapters和data(models和managers)。

第二部分是res資料夾,就是“resource”的簡稱,res目錄存放的是圖片、xml佈局檔案,還有其它xml值檔案,是非程式碼資源的一部分。在IOS上,圖片只需要匹配兩個尺寸,而在Android上有很多種螢幕尺寸需要考慮,Android上用資料夾來管理管理圖片、字串,還有其它的螢幕配置數值等。res資料夾裡也含有類似IOS中xib檔案的xml檔案,還有儲存字串資源、整數值,以及樣式的xml檔案。

最後,在專案結構上還有一點相似的地方,就是AndroidManifest.xml檔案。這個檔案相當於IOS的Project-Info.plist檔案,它儲存了activities、application還有Intent的資訊,要了解更多關於Intent的資料,可以繼續閱讀這篇文章

Activities

Activities是Android APP最基本的可視單元,就像UIViewControllers是IOS最基本的顯示元件一樣。Android系統使用一個Activity棧來管理Activity,而IOS使用UINavigationController進行管理。當APP啟動的時候,Android系統會把Main Activity壓棧,值得注意的是這是還可以再執行別的APP Activity,然後把它放到Activity棧中。返回鍵預設會從Activity棧進行pop操作,所以如果使用者按下返回鍵,就可以切換執行已執行的App了。

Activities還可以用Intent元件初始化別的Activity,初始化時可攜帶資料。啟動一個新的Activity類似於IOS上建立一個UIViewController。最基本的啟動一個新的Activity的方式就是建立一個帶有data的Intent元件。Android上實現自定義Intent初始化器的最好方法就是寫一個靜態getter方法。在Activity結束的時候也可以返回資料,在Activity結束的時候可以往Intent裡面放置額外的資料。

IOS和Android的一個大的區別是,任何一個在AndroidManifest檔案中註冊的Activity都可以作為程式的入口,為Activity設定一個intent filter屬性比如“media intent”,就可以處理系統的媒體檔案了。最好的例子就是編輯照片Activity。它可以開啟一張照片,然後進行修改,最後在Activity結束時返回修改後的照片。

附加提醒:要想在Activity和Fragment之間傳遞物件,必須要實現Parcelable介面,就像在IOS裡需要遵循協議一樣。還有,Parcelable物件可以存在於Activity或者Fragment的savedInstanceState裡,這樣在它們被銷燬後可以更容易重建它們的狀態。

下面就來看看怎麼在一個Activity中啟動另一個Activity,然後在第二個Activity結束時進行返回。

啟動其它Activity並返回結果

Activity結束時返回資料

Fragments

Fragment的概念在Android上比較獨特,從Android3.0開始引入。Fragment是一個迷你版的控制器,可以顯示在Activity上。它有自己的狀態和邏輯,同時在一個螢幕上支援多個Fragment同時顯示。Activity充當Fragment的控制器,Fragment沒有自己的上下文環境,只能依賴Activity存在。

使用Fragment最好的例子就是在平板上的應用。可以在螢幕左邊放一個fragment列表,然後在螢幕的右邊放fragment的詳細資訊。Fragment可以把螢幕分成可重複利用的小塊,分別控制管理。不過要注意Fragment的生命週期,會有些細微的差別。

multipane_view_tablet

Fragment是實現Android結構化的一種新的方式,就像IOS中的不用UITableview而用UICollectionView實現列表資料結構化。因為只使用Activity而不用Fragment的話,會簡單一些。不過,之後你會遇到麻煩。如果不使用Fragment代替全盤使用Activity的話,在後面需要利用intent和進行多螢幕支援的時候就會遇到困難。

下面看一個UITableViewController的例子和一個ListFragment的地鐵時刻表示例。

表格實現

IMG_0095

List Fragment實現

Screenshot_2014-03-25-11-42-16

下面,我們來分析Android上特有的一些元件。

Android通用元件

ListView和Adapter

ListView和IOS的UITableView最像,也是使用最頻繁的元件之一。類似於UITableView的UITableViewControllerListView也有一個ListActivity,還有ListFragment。這些元件會更好地處理一些佈局問題,也為運算元據介面卡提供了便利,這個接下來會說到。下面這個例子就是使用ListFragment來展示資料,類似TableViewdatasource

關於datasource,Android上沒有datasource和delegate,只有Adapter。Adapter有很多種形式,主要功能其實就是為了把datasource和delegate合在一起。Adapter拿到資料然後填充到Listview中,在ListView中初始化響應的元件並顯示出來,下面是arrayAdapter的使用:

可以看到,adapter裡面有一個很重要的方法叫getView,和IOS的cellForRowAtIndexPath方法一樣。還有一個相似之處就是迴圈利用的策略,和IOS6上的實現很相似。在Android和IOS上迴圈利用View都很重要,事實上它對列表的實現有很大幫助。這個adapter很簡單,使用了一個內建的類ArrayAdapter來存放資料,也解釋了怎麼把資料填入ListView中。

AsyncTask

對於IOS上的Grand Central Dispatch,Android上也有AsyncTask。它是非同步操作工具的又一選擇,用一種很友好的方式實現非同步任務。不過AsyncTask有點超出了本文的範圍,所以本人還是推薦你看看這裡

Activity的生命週期

IOS開發者在寫Android的過程中還要注意的就是Android的生命週期。可以先從Activity的生命週期文件開始:

Android-Activity-Lifecycle

本質上Activity的生命週期很像UIViewController的生命週期,主要區別在於Android上可以任意銷燬Activity,所以保證Activity的資料和狀態很重要,如果在onCreate()中儲存了的話,可以在saved state中恢復Activity的狀態。最好的方法就是使用saveInstanceState來儲存bundled資料,例如下面的TripListActivity是示例工程的一部分,用來儲存當前顯示的資料:

還有一個要注意的地方就是螢幕旋轉:如果螢幕發生旋轉,會改變Activity的生命週期。也就是說,Activity會先被銷燬,然後再重建。如果已經儲存了資料和狀態,Activity可以重建原來的狀態,實現無縫重建。很多APP開發者在遇到APP旋轉時會出現問題,因為Activity沒有處理旋轉的改變。注意不要用鎖定螢幕的方向來解決這個問題,因為這樣會存在一個隱含的生命週期的bug,在某些情況下還是可能發生的。

Fragment生命週期

Fragment的生命週期和Activity的很像,但是有一些區別:

fragment_lifecycle

還有一個問題就是Fragment和Activity通訊的問題。需要注意的是onAttach()方法在onActivityCreated()方法之前被呼叫,這就意味著在fragment建立完成後Activity還不能保證已經存在。如果需要為父Activity設定介面或者代理,則需要在onActivityCreated()方法呼叫之後。

Fragment也有可能會在系統需要的時候被建立和銷燬。如果要儲存它的狀態,那麼也要像Activity一樣進行處理。下面這個是示例專案中的一個小例子,trip列表Fragment會記錄相應的資料,和上面的地鐵時間示例一樣:

還要注意的是,Fragment經常會在onCreate方法中利用bundled引數重建自己的狀態。而自定義的Trip列表模型類相關的setter方法也會把物件新增到bundled引數中。這樣就可以保證在Fragment被銷燬或者重建時,比如螢幕旋轉後,可以利用最新的資料去重建狀態。

關於佈局

和Android上其它部分的開發工作一樣,指定佈局檔案也有自己的優缺點。Android上的佈局檔案都存放在res/layouts資料夾中,以易讀的xml形式儲存。

地鐵列表佈局
Screenshot_2014-03-24-13-12-00

下面這個是IOS上用UITableView和UIButton來製作的類似效果:

iOS_Screen1

iOSConstraints

可以發現,Android的佈局檔案更容易閱讀和理解,而且提供了多種佈局方式,我們只介紹了其中的一小部分。

通常來說,我們接觸的最基本的UI結構就是ViewGroup的子類,RelativeLayout、LinearLayout、FrameLayout是最常用的。這些ViewGroup的子類可以容納別的View,幷包含了一些排布控制元件的屬性。

一個很好的例子就是上面用到的RelativeLayout,在裡面可以使用android:layout_alignParentBottom="true"來把按鈕定位到佈局底部。

最後,如果要在Fragment或者Activity中使用這些控制元件的話,可以在onCreateView()方法中使用佈局的資源ID:

佈局小貼士

  • 請使用dp(density-independent pixels),不直接使用dx(pixels);
  • 不要在視覺化編輯器中移動佈局元件——通常來說視覺化編輯器在你調好高和寬後,會為元件新增一些多餘的畫素,所以最好就是直接操作xml檔案;
  • 如果在佈局的heightwidth看到有用fill_parent這個屬性的話,你會發現在API 8的時候這個屬性就已經被限制了,改用match_parent替換。

如果要了解更多關於這方面的內容可以看看這篇文章——responsive android applications

資料

Android上的資料儲存也和IOS上差不多:

  • SharedPreferences、NSUserDefaults;
  • 記憶體儲存物件;
  • internal、external檔案讀寫document directory檔案讀寫;
  • SQLite資料庫儲存Core Data形式資料庫儲存。

其中最基本的區別就是Core Data。在Android上可以直接訪問sqlite資料庫並可以返回cursor物件得到結果。更詳細的介紹請看這篇文章—— using SQLite on Android

Android課後作業

之前已經討論的東西只是描述了Android的大概 ,要想好好利用Android上的更多的特性,本人建議你看看下面的這些概念:

  • ActionBar,Overflow Menu,還有Menu Button;
  • 跨應用間資料共享;
  • 響應系統actions;
  • 好好學習Java的特性:泛型、抽象方法和抽象類等等;
  • 看看Google的低版本相容庫;
  • 關於Android上的模擬器:可以安裝x86 HAXM plugin來使模擬器更流暢。

最後的工作

以上所有涉及的知識點都在MBTA中實現了(託管在Github上)。這個專案僅僅是為了解釋兩個不同平臺之間的一些基本的概念,比如應用架構、資料處理、介面開發等。

我們可以學到更多的解決問題的技巧和方式。因為兩平臺的實現細節各不相同,也許瞭解Android的工作原理可以對IOS的下一個版本的開發工作有所幫助。系統之間有很多相似的地方,誰知道下個版本的IOS會出現什麼呢?


1.原始碼 Source

2.關於多螢幕支援的google官方文件:http://developer.android.com/guide/practices/screens_support.html

3.關於 Intents 的文件:here

4.關於平板分塊處理的文件資料: multi-pane tablet view

5.感謝 NSHipster

相關文章