自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

iOS程序員必須知道的Android要點(diǎn)

移動(dòng)開發(fā) iOS
在這篇文章中,作者會(huì)介紹在iOS開發(fā)中,怎么學(xué)習(xí)一些Android開發(fā)的理念,Android和iOS功能上本身有一定的相似之處,但是具體實(shí)現(xiàn)的方式各異,所以這篇文章會(huì)使用一個(gè)項(xiàng)目例子進(jìn)行對(duì)比,說(shuō)明怎么在這兩個(gè)平臺(tái)上分別去實(shí)現(xiàn)這個(gè)任務(wù)。

在移動(dòng)應(yīng)用飛速發(fā)展的今天,APP只針對(duì)iOS平臺(tái)進(jìn)行開發(fā)已經(jīng)不夠了,如今Android在移動(dòng)設(shè)備占有近80%的市場(chǎng),如此大量的潛在用戶怎么能被忽略掉呢。

在這篇文章中,作者會(huì)介紹在iOS開發(fā)中,怎么學(xué)習(xí)一些Android開發(fā)的理念,Android和iOS功能上本身有一定的相似之處,但是具體實(shí)現(xiàn)的方式各異,所以這篇文章會(huì)使用一個(gè)項(xiàng)目例子進(jìn)行對(duì)比,說(shuō)明怎么在這兩個(gè)平臺(tái)上分別去實(shí)現(xiàn)這個(gè)任務(wù)。

除了了解iOS的開發(fā)知識(shí),本文還需要對(duì)Java有一定的了解,并能夠安裝和使用ADT(Android Development Tools)。此外,如果你是一個(gè)Android新手,那么請(qǐng)?jiān)囋嚾タ纯碅ndroid的官方教程—— building your first app,非常有用。

UI設(shè)計(jì)簡(jiǎn)要說(shuō)明

本文不會(huì)深入研究關(guān)于iOS和Android兩個(gè)平臺(tái)之間的用戶體驗(yàn)或者設(shè)計(jì)模式之間的差異,不過(guò)如果能夠理解Android上的一些優(yōu)秀的UI范 例也很有幫助:ActionBar、Overflow menu、back button share action等等。假如你很想嘗試Android開發(fā),那么強(qiáng)烈推薦你去Google Play Store上購(gòu)置一臺(tái)Nexus5,然后把它作為你日常使用的設(shè)備使用一周,然后嘗試仔細(xì)了解這個(gè)操作系統(tǒng)的各種功能和擴(kuò)展特性,如果開發(fā)者連操作系統(tǒng)的 各種使用規(guī)則都不了解,那么做出來(lái)的產(chǎn)品一定有問(wèn)題。

編程語(yǔ)言的應(yīng)用框架

Objective-C和Java之間有很多不同之處,如果把Objective-C的編程風(fēng)格帶到Java里面的話,很多代碼也許會(huì)和底層的應(yīng)用框架沖突。簡(jiǎn)單地說(shuō),就是需要注意一些區(qū)別:

  • 去掉Objective-C里面的類前綴,因?yàn)镴ava里有顯式的命名空間和包結(jié)構(gòu),所以就沒必要用類前綴了。
  • 實(shí)例變量的前綴用“m”,不用“_”,在寫代碼的過(guò)程中要多利用JavaDoc文檔。這樣能使代碼更清晰,更適合團(tuán)隊(duì)合作。
  • 注意檢查NULL值,Objective-C對(duì)空值檢查做的很好,不過(guò)Java沒有。
  • 不直接使用屬性,如果需要setter和getter,需要?jiǎng)?chuàng)建一個(gè)getVariableName()方法,然后顯式調(diào)用它。如果直接使用“this.object”不會(huì)調(diào)用自定義的getter方法,你必須使用this.getObject這樣的方法。
  • 同樣的,方法命名時(shí)帶有g(shù)et和set前綴來(lái)標(biāo)示它是getter和setter方法,Java的方法很喜歡寫成actions或者queries等,比如Java會(huì)使用getCell(),而不用cellForRowAtIndexPath。

項(xiàng)目結(jié)構(gòu)

Android應(yīng)用程序主要分為兩部分。***部分是Java源代碼,以Java包結(jié)構(gòu)排布,也可以根據(jù)自己的喜好進(jìn)行結(jié)構(gòu)排布。最基本的結(jié)構(gòu)就是分 為這幾個(gè)頂層目錄:activities、fragments、views、adapters和data(models和managers)。

第二部分是res文件夾,就是“resource”的簡(jiǎn)稱,res目錄存放的是圖片、xml布局文件,還有其它xml值文件,是非代碼資源的一部分。在iOS上,圖片只需要匹配兩個(gè)尺寸,而在Android上有很多種屏幕尺寸需要考慮,Android上用文件夾來(lái)管理管理圖片、字符串,還有其它的屏幕配置數(shù)值等。res文件夾里也含有類似iOS中xib文件的xml文件,還有存儲(chǔ)字符串資源、整數(shù)值,以及樣式的xml文件。

***,在項(xiàng)目結(jié)構(gòu)上還有一點(diǎn)相似的地方,就是AndroidManifest.xml文件。這個(gè)文件相當(dāng)于iOS的Project-Info.plist文件,它存儲(chǔ)了activities、application還有Intent的信息,要了解更多關(guān)于Intent的資料,可以繼續(xù)閱讀這篇文章。

Activities

Activities是Android APP最基本的可視單元,就像UIViewControllers是iOS最基本的顯示組件一樣。Android系統(tǒng)使用一個(gè)Activity棧來(lái)管理Activity,而iOS使用UINavigationController進(jìn)行管理。當(dāng)APP啟動(dòng)的時(shí)候,Android系統(tǒng)會(huì)把Main Activity壓棧,值得注意的是這是還可以再運(yùn)行別的APP Activity,然后把它放到Activity棧中。返回鍵默認(rèn)會(huì)從Activity棧進(jìn)行pop操作,所以如果用戶按下返回鍵,就可以切換運(yùn)行已運(yùn)行的App了。

Activities還可以用Intent組件初始化別的Activity,初始化時(shí)可攜帶數(shù)據(jù)。啟動(dòng)一個(gè)新的Activity類似于iOS上創(chuàng)建一個(gè)UIViewController。最基本的啟動(dòng)一個(gè)新的Activity的方式就是創(chuàng)建一個(gè)帶有data的Intent組件。Android上實(shí)現(xiàn)自定義Intent初始化器的***方法就是寫一個(gè)靜態(tài)getter方法。在Activity結(jié)束的時(shí)候也可以返回?cái)?shù)據(jù),在Activity結(jié)束的時(shí)候可以往Intent里面放置額外的數(shù)據(jù)。

iOS和Android的一個(gè)大的區(qū)別是,任何一個(gè)在AndroidManifest文件中注冊(cè)的Activity都可以作為程序的入口,為Activity設(shè)置一個(gè)intent filter屬性比如“media intent”,就可以處理系統(tǒng)的媒體文件了。***的例子就是編輯照片Activity。它可以打開一張照片,然后進(jìn)行修改,***在Activity結(jié)束時(shí)返回修改后的照片。

附加提醒:要想在Activity和Fragment之間傳遞對(duì)象,必須要實(shí)現(xiàn)Parcelable接口,就像在iOS里需要遵循協(xié)議一樣。還有,Parcelable對(duì)象可以存在于Activity或者Fragment的savedInstanceState里,這樣在它們被銷毀后可以更容易重建它們的狀態(tài)。

下面就來(lái)看看怎么在一個(gè)Activity中啟動(dòng)另一個(gè)Activity,然后在第二個(gè)Activity結(jié)束時(shí)進(jìn)行返回。

啟動(dòng)其它Activity并返回結(jié)果

  1. // A request code is a unique value for returning activities 
  2. private static final int REQUEST_CODE_NEXT_ACTIVITY = 1234
  3.   
  4. protected void startNextActivity() { 
  5.     // Intents need a context, so give this current activity as the context 
  6.     Intent nextActivityIntent = new Intent(this, NextActivity.class); 
  7.        startActivityForResult(nextActivityResult, REQUEST_CODE_NEXT_ACTIVITY); 
  8.   
  9. @Override 
  10. protected void onActivityResult(int requestCode, int resultCode, Intent data) { 
  11.     switch (requestCode) { 
  12.     case REQUEST_CODE_NEXT_ACTIVITY: 
  13.         if (resultCode == RESULT_OK) { 
  14.             // This means our Activity returned successfully. For now, Toast this text.  
  15.             // This just creates a simple pop-up message on the screen. 
  16.                 Toast.makeText(this"Result OK!", Toast.LENGTH_SHORT).show(); 
  17.             } 
  18.             return
  19.         }    
  20.         super.onActivityResult(requestCode, resultCode, data); 

Activity結(jié)束時(shí)返回?cái)?shù)據(jù)

  1. public static final String activityResultString = "activityResultString"
  2.   
  3. /* 
  4.  * On completion, place the object ID in the intent and finish with OK. 
  5.  * @param returnObject that was processed 
  6.  */ 
  7. private void onActivityResult(Object returnObject) { 
  8.         Intent data = new Intent(); 
  9.         if (returnObject != null) { 
  10.             data.putExtra(activityResultString, returnObject.uniqueId); 
  11.         } 
  12.       
  13.         setResult(RESULT_OK, data); 
  14.         finish();        

Fragments

Fragment的概念在Android上比較獨(dú)特,從Android3.0開始引入。Fragment是一個(gè)迷你版的控制器,可以顯示在 Activity上。它有自己的狀態(tài)和邏輯,同時(shí)在一個(gè)屏幕上支持多個(gè)Fragment同時(shí)顯示。Activity充當(dāng)Fragment的控制 器,F(xiàn)ragment沒有自己的上下文環(huán)境,只能依賴Activity存在。

使用Fragment***的例子就是在平板上的應(yīng)用??梢栽谄聊蛔筮叿乓粋€(gè)fragment列表,然后在屏幕的右邊放fragment的詳細(xì)信息。Fragment可以把屏幕分成可重復(fù)利用的小塊,分別控制管理。不過(guò)要注意Fragment的生命周期,會(huì)有些細(xì)微的差別。

multipane_view_tablet

Fragment是實(shí)現(xiàn)Android結(jié)構(gòu)化的一種新的方式,就像iOS中的不用UITableview而用UICollectionView實(shí)現(xiàn)列表數(shù)據(jù)結(jié)構(gòu)化。因?yàn)橹皇褂肁ctivity而不用Fragment的話,會(huì)簡(jiǎn)單一些。不過(guò),之后你會(huì)遇到麻煩。如果不使用Fragment代替全盤使用Activity的話,在后面需要利用intent和進(jìn)行多屏幕支持的時(shí)候就會(huì)遇到困難。

下面看一個(gè)UITableViewController的例子和一個(gè)ListFragment的地鐵時(shí)刻表示例。

表格實(shí)現(xiàn)

IMG_0095

  1. @interface MBTASubwayTripTableTableViewController () 
  2.   
  3. @property (assign, nonatomic) MBTATrip *trip; 
  4.   
  5. @end 
  6.   
  7. @implementation MBTASubwayTripTableTableViewController 
  8.   
  9. -(instancetype)initWithTrip:(MBTATrip *)trip 
  10.     self = [super initWithStyle:UITableViewStylePlain]; 
  11.     if (self) { 
  12.         _trip = trip; 
  13.         [self setTitle:trip.destination]; 
  14.     } 
  15.     return self; 
  16.   
  17. -(void)viewDidLoad 
  18.     [super viewDidLoad]; 
  19.       
  20.     [self.tableView registerClass:[MBTAPredictionCell class] forCellReuseIdentifier:[MBTAPredictionCell reuseId]]; 
  21.     [self.tableView registerNib:[UINib nibWithNibName:NSStringFromClass([MBTATripHeaderView class]) bundle:nil] forHeaderFooterViewReuseIdentifier:[MBTATripHeaderView reuseId]]; 
  22.   
  23. #pragma mark - UITableViewDataSource 
  24.   
  25. -(NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 
  26.     return 1; 
  27.   
  28. -(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 
  29.     return [self.trip.predictions count]; 
  30.   
  31. #pragma mark - UITableViewDelegate 
  32.   
  33. -(CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section 
  34.     return [MBTATripHeaderView heightWithTrip:self.trip]; 
  35.   
  36. -(UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section 
  37.     MBTATripHeaderView *headerView = [self.tableView dequeueReusableHeaderFooterViewWithIdentifier:[MBTATripHeaderView reuseId]]; 
  38.     [headerView setFromTrip:self.trip]; 
  39.     return headerView; 
  40.   
  41. -(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 
  42.     UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:[MBTAPredictionCell reuseId] forIndexPath:indexPath]; 
  43.       
  44.     MBTAPrediction *prediction = [self.trip.predictions objectAtIndex:indexPath.row]; 
  45.     [(MBTAPredictionCell *)cell setFromPrediction:prediction]; 
  46.       
  47.     return cell; 
  48.   
  49. -(BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath 
  50.     return NO; 
  51.   
  52. - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 
  53.     [tableView deselectRowAtIndexPath:indexPath animated:YES]; 
  54.   
  55. @end 

List Fragment實(shí)現(xiàn)

Screenshot_2014-03-25-11-42-16

  1. public class TripDetailFragment extends ListFragment { 
  2.   
  3.     /** 
  4.      * The configuration flags for the Trip Detail Fragment. 
  5.      */ 
  6.     public static final class TripDetailFragmentState { 
  7.         public static final String KEY_FRAGMENT_TRIP_DETAIL = "KEY_FRAGMENT_TRIP_DETAIL"
  8.     } 
  9.   
  10.     protected Trip mTrip; 
  11.   
  12.     /** 
  13.      * Use this factory method to create a new instance of 
  14.      * this fragment using the provided parameters. 
  15.      * 
  16.      * @param trip the trip to show details 
  17.      * @return A new instance of fragment TripDetailFragment. 
  18.      */ 
  19.     public static TripDetailFragment newInstance(Trip trip) { 
  20.         TripDetailFragment fragment = new TripDetailFragment(); 
  21.         Bundle args = new Bundle(); 
  22.         args.putParcelable(TripDetailFragmentState.KEY_FRAGMENT_TRIP_DETAIL, trip); 
  23.         fragment.setArguments(args); 
  24.         return fragment; 
  25.     } 
  26.   
  27.     public TripDetailFragment() { } 
  28.   
  29.     @Override 
  30.     public View onCreateView(LayoutInflater inflater, ViewGroup container, 
  31.                              Bundle savedInstanceState) { 
  32.         Prediction[] predictions= mTrip.predictions.toArray(new Prediction[mTrip.predictions.size()]); 
  33.         PredictionArrayAdapter predictionArrayAdapter = new PredictionArrayAdapter(getActivity(), predictions); 
  34.         setListAdapter(predictionArrayAdapter); 
  35.         return super.onCreateView(inflater,container, savedInstanceState); 
  36.     } 
  37.   
  38.     @Override 
  39.     public void onViewCreated(View view, Bundle savedInstanceState) { 
  40.         super.onViewCreated(view, savedInstanceState); 
  41.         TripDetailsView headerView = new TripDetailsView(getActivity()); 
  42.         headerView.updateFromTripObject(mTrip); 
  43.         getListView().addHeaderView(headerView); 
  44.     } 

下面,我們來(lái)分析Android上特有的一些組件。

Android通用組件

ListView和Adapter

ListView和iOS的UITableView最像,也是使用最頻繁的組件之一。類似于UITableView的UITableViewController,ListView也有一個(gè)ListActivity,還有ListFragment。這些組件會(huì)更好地處理一些布局問(wèn)題,也為操作數(shù)據(jù)適配器提供了便利,這個(gè)接下來(lái)會(huì)說(shuō)到。下面這個(gè)例子就是使用ListFragment來(lái)展示數(shù)據(jù),類似TableView的datasource。

關(guān)于datasource,Android上沒有datasource和delegate,只有Adapter。Adapter有很多種形式,主要 功能其實(shí)就是為了把datasource和delegate合在一起。Adapter拿到數(shù)據(jù)然后填充到Listview中,在ListView中初始化 響應(yīng)的組件并顯示出來(lái),下面是arrayAdapter的使用:

  1. public class PredictionArrayAdapter extends ArrayAdapter<Prediction> { 
  2.   
  3.     int LAYOUT_RESOURCE_ID = R.layout.view_three_item_list_view; 
  4.   
  5.     public PredictionArrayAdapter(Context context) { 
  6.         super(context, R.layout.view_three_item_list_view); 
  7.     } 
  8.   
  9.     public PredictionArrayAdapter(Context context, Prediction[] objects) { 
  10.         super(context, R.layout.view_three_item_list_view, objects); 
  11.     } 
  12.   
  13.     @Override 
  14.     public View getView(int position, View convertView, ViewGroup parent) 
  15.     { 
  16.         Prediction prediction = this.getItem(position); 
  17.         View inflatedView = convertView; 
  18.         if(convertView==null
  19.         { 
  20.             LayoutInflater inflater = (LayoutInflater)getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
  21.             inflatedView = inflater.inflate(LAYOUT_RESOURCE_ID, parent, false); 
  22.         } 
  23.   
  24.         TextView stopNameTextView = (TextView)inflatedView.findViewById(R.id.view_three_item_list_view_left_text_view); 
  25.         TextView middleTextView = (TextView)inflatedView.findViewById(R.id.view_three_item_list_view_middle_text_view); 
  26.         TextView stopSecondsTextView = (TextView)inflatedView.findViewById(R.id.view_three_item_list_view_right_text_view); 
  27.   
  28.         stopNameTextView.setText(prediction.stopName); 
  29.         middleTextView.setText(""); 
  30.         stopSecondsTextView.setText(prediction.stopSeconds.toString()); 
  31.   
  32.         return inflatedView; 
  33.     } 

可以看到,adapter里面有一個(gè)很重要的方法叫g(shù)etView,和iOS的cellForRowAtIndexPath方法一樣。還有一個(gè)相似之處就是循環(huán)利用的策略,和iOS6上的實(shí)現(xiàn)很相似。在Android和iOS上循環(huán)利用View都很重要,事實(shí)上它對(duì)列表的實(shí)現(xiàn)有很大幫助。這個(gè)adapter很簡(jiǎn)單,使用了一個(gè)內(nèi)建的類ArrayAdapter來(lái)存放數(shù)據(jù),也解釋了怎么把數(shù)據(jù)填入ListView中。

AsyncTask

對(duì)于iOS上的Grand Central Dispatch,Android上也有AsyncTask。它是異步操作工具的又一選擇,用一種很友好的方式實(shí)現(xiàn)異步任務(wù)。不過(guò)AsyncTask有點(diǎn)超出了本文的范圍,所以本人還是推薦你看看這里

Activity的生命周期

iOS開發(fā)者在寫Android的過(guò)程中還要注意的就是Android的生命周期??梢韵葟腁ctivity的生命周期文檔開始:

Android-Activity-Lifecycle

本質(zhì)上Activity的生命周期很像UIViewController的生命周期,主要區(qū)別在于Android上可以任意銷毀Activity,所以保證Activity的數(shù)據(jù)和狀態(tài)很重要,如果在onCreate()中保存了的話,可以在saved state中恢復(fù)Activity的狀態(tài)。***的方法就是使用saveInstanceState來(lái)存儲(chǔ)bundled數(shù)據(jù),例如下面的TripListActivity是示例工程的一部分,用來(lái)保存當(dāng)前顯示的數(shù)據(jù):

  1. public static Intent getTripListActivityIntent(Context context, TripList.LineType lineType) { 
  2.     Intent intent = new Intent(context, TripListActivity.class); 
  3.     intent.putExtra(TripListActivityState.KEY_ACTIVITY_TRIP_LIST_LINE_TYPE, lineType.getLineName()); 
  4.     return intent; 
  5.   
  6. public static final class TripListActivityState { 
  7.     public static final String KEY_ACTIVITY_TRIP_LIST_LINE_TYPE = "KEY_ACTIVITY_TRIP_LIST_LINE_TYPE"
  8.       
  9. TripList.LineType mLineType;    
  10.       
  11. @Override 
  12. protected void onCreate(Bundle savedInstanceState) { 
  13.    super.onCreate(savedInstanceState); 
  14.    mLineType = TripList.LineType.getLineType(getIntent().getStringExtra(TripListActivityState.KEY_ACTIVITY_TRIP_LIST_LINE_TYPE)); 
  15. }     

還有一個(gè)要注意的地方就是屏幕旋轉(zhuǎn):如果屏幕發(fā)生旋轉(zhuǎn),會(huì)改變Activity的生命周期。也就是說(shuō),Activity會(huì)先被銷毀,然后再重建。如 果已經(jīng)保存了數(shù)據(jù)和狀態(tài),Activity可以重建原來(lái)的狀態(tài),實(shí)現(xiàn)無(wú)縫重建。很多APP開發(fā)者在遇到APP旋轉(zhuǎn)時(shí)會(huì)出現(xiàn)問(wèn)題,因?yàn)锳ctivity沒有 處理旋轉(zhuǎn)的改變。注意不要用鎖定屏幕的方向來(lái)解決這個(gè)問(wèn)題,因?yàn)檫@樣會(huì)存在一個(gè)隱含的生命周期的bug,在某些情況下還是可能發(fā)生的。

Fragment生命周期

Fragment的生命周期和Activity的很像,但是有一些區(qū)別:

fragment_lifecycle

還有一個(gè)問(wèn)題就是Fragment和Activity通信的問(wèn)題。需要注意的是onAttach()方法在onActivityCreated()方法之前被調(diào)用,這就意味著在fragment創(chuàng)建完成后Activity還不能保證已經(jīng)存在。如果需要為父Activity設(shè)置接口或者代理,則需要在onActivityCreated()方法調(diào)用之后。

Fragment也有可能會(huì)在系統(tǒng)需要的時(shí)候被創(chuàng)建和銷毀。如果要保存它的狀態(tài),那么也要像Activity一樣進(jìn)行處理。下面這個(gè)是示例項(xiàng)目中的一個(gè)小例子,trip列表Fragment會(huì)記錄相應(yīng)的數(shù)據(jù),和上面的地鐵時(shí)間示例一樣:

  1. /** 
  2.  * The configuration flags for the Trip List Fragment. 
  3.  */ 
  4. public static final class TripListFragmentState { 
  5.     public static final String KEY_FRAGMENT_TRIP_LIST_LINE_TYPE = "KEY_FRAGMENT_TRIP_LIST_LINE_TYPE"
  6.     public static final String KEY_FRAGMENT_TRIP_LIST_DATA = "KEY_FRAGMENT_TRIP_LIST_DATA"
  7.   
  8. /** 
  9.  * Use this factory method to create a new instance of 
  10.  * this fragment using the provided parameters. 
  11.  * 
  12.  * @param lineType the subway line to show trips for. 
  13.  * @return A new instance of fragment TripListFragment. 
  14.  */ 
  15. public static TripListFragment newInstance(TripList.LineType lineType) { 
  16.     TripListFragment fragment = new TripListFragment(); 
  17.     Bundle args = new Bundle(); 
  18.     args.putString(TripListFragmentState.KEY_FRAGMENT_TRIP_LIST_LINE_TYPE, lineType.getLineName()); 
  19.     fragment.setArguments(args); 
  20.     return fragment; 
  21.   
  22. protected TripList mTripList; 
  23. protected void setTripList(TripList tripList) { 
  24.     Bundle arguments = this.getArguments(); 
  25.     arguments.putParcelable(TripListFragmentState.KEY_FRAGMENT_TRIP_LIST_DATA, tripList); 
  26.     mTripList = tripList; 
  27.     if (mTripArrayAdapter != null) { 
  28.         mTripArrayAdapter.clear(); 
  29.         mTripArrayAdapter.addAll(mTripList.trips); 
  30.     } 
  31.   
  32. @Override 
  33. public void onCreate(Bundle savedInstanceState) { 
  34.     super.onCreate(savedInstanceState); 
  35.     if (getArguments() != null) { 
  36.         mLineType = TripList.LineType.getLineType(getArguments().getString(TripListFragmentState.KEY_FRAGMENT_TRIP_LIST_LINE_TYPE)); 
  37.         mTripList = getArguments().getParcelable(TripListFragmentState.KEY_FRAGMENT_TRIP_LIST_DATA); 
  38.     } 
  39. }     

還要注意的是,F(xiàn)ragment經(jīng)常會(huì)在onCreate方法中利用bundled參數(shù)重建自己的狀態(tài)。而自定義的Trip列表模型類相關(guān)的setter方法也會(huì)把對(duì)象添加到bundled參數(shù)中。這樣就可以保證在Fragment被銷毀或者重建時(shí),比如屏幕旋轉(zhuǎn)后,可以利用***的數(shù)據(jù)去重建狀態(tài)。

關(guān)于布局

和Android上其它部分的開發(fā)工作一樣,指定布局文件也有自己的優(yōu)缺點(diǎn)。Android上的布局文件都存放在res/layouts文件夾中,以易讀的xml形式存儲(chǔ)。

地鐵列表布局

Screenshot_2014-03-24-13-12-00 

  1. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
  2.     xmlns:tools="http://schemas.android.com/tools" 
  3.     android:layout_width="match_parent" 
  4.     android:layout_height="match_parent" 
  5.     tools:context="com.example.androidforiOS.app.activities.MainActivity$PlaceholderFragment"
  6.   
  7.     <ListView 
  8.         android:id="@+id/fragment_subway_list_listview" 
  9.         android:layout_width="match_parent" 
  10.         android:layout_height="match_parent" 
  11.         android:paddingBottom="@dimen/Button.Default.Height"/> 
  12.   
  13.     <Button 
  14.         android:id="@+id/fragment_subway_list_Button" 
  15.         android:layout_width="match_parent" 
  16.         android:layout_height="@dimen/Button.Default.Height" 
  17.         android:minHeight="@dimen/Button.Default.Height" 
  18.         android:background="@drawable/button_red_selector" 
  19.         android:text="@string/hello_world" 
  20.         android:textColor="@color/Button.Text" 
  21.         android:layout_alignParentBottom="true" 
  22.         android:gravity="center"/> 
  23.   
  24. </RelativeLayout> 

下面這個(gè)是iOS上用UITableView和UIButton來(lái)制作的類似效果:

iOS_Screen1

iOSConstraints

可以發(fā)現(xiàn),Android的布局文件更容易閱讀和理解,而且提供了多種布局方式,我們只介紹了其中的一小部分。

通常來(lái)說(shuō),我們接觸的最基本的UI結(jié)構(gòu)就是ViewGroup的子類,RelativeLayout、LinearLayout、FrameLayout是最常用的。這些ViewGroup的子類可以容納別的View,并包含了一些排布控件的屬性。

一個(gè)很好的例子就是上面用到的RelativeLayout,在里面可以使用android:layout_alignParentBottom="true"來(lái)把按鈕定位到布局底部。

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

  1. @Override 
  2. public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
  3.     return inflater.inflate(R.layout.fragment_subway_listview, container, false); 

布局小貼士

  • 請(qǐng)使用dp(density-independent pixels),不直接使用dx(pixels);
  • 不要在可視化編輯器中移動(dòng)布局組件——通常來(lái)說(shuō)可視化編輯器在你調(diào)好高和寬后,會(huì)為組件添加一些多余的像素,所以***就是直接操作xml文件;
  • 如果在布局的height和width看到有用fill_parent這個(gè)屬性的話,你會(huì)發(fā)現(xiàn)在API 8的時(shí)候這個(gè)屬性就已經(jīng)被限制了,改用match_parent替換。

如果要了解更多關(guān)于這方面的內(nèi)容可以看看這篇文章——responsive android applications。

數(shù)據(jù)

Android上的數(shù)據(jù)存儲(chǔ)也和iOS上差不多:

  • SharedPreferences、NSUserDefaults;
  • 內(nèi)存存儲(chǔ)對(duì)象;
  • internal、external文件讀寫document directory文件讀寫;
  • SQLite數(shù)據(jù)庫(kù)存儲(chǔ)Core Data形式數(shù)據(jù)庫(kù)存儲(chǔ)。

其中最基本的區(qū)別就是Core Data。在Android上可以直接訪問(wèn)sqlite數(shù)據(jù)庫(kù)并可以返回cursor對(duì)象得到結(jié)果。更詳細(xì)的介紹請(qǐng)看這篇文章—— using SQLite on Android

Android課后作業(yè)

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

  • ActionBar,Overflow Menu,還有Menu Button;
  • 跨應(yīng)用間數(shù)據(jù)共享;
  • 響應(yīng)系統(tǒng)actions;
  • 好好學(xué)習(xí)Java的特性:泛型、抽象方法和抽象類等等;
  • 看看Google的低版本兼容庫(kù);
  • 關(guān)于Android上的模擬器:可以安裝x86 HAXM plugin來(lái)使模擬器更流暢。

***的工作

以上所有涉及的知識(shí)點(diǎn)都在MBTA中實(shí)現(xiàn)了(托管在Github上)。這個(gè)項(xiàng)目?jī)H僅是為了解釋兩個(gè)不同平臺(tái)之間的一些基本的概念,比如應(yīng)用架構(gòu)、數(shù)據(jù)處理、界面開發(fā)等。

我們可以學(xué)到更多的解決問(wèn)題的技巧和方式。因?yàn)閮善脚_(tái)的實(shí)現(xiàn)細(xì)節(jié)各不相同,也許了解Android的工作原理可以對(duì)iOS的下一個(gè)版本的開發(fā)工作有所幫助。系統(tǒng)之間有很多相似的地方,誰(shuí)知道下個(gè)版本的iOS會(huì)出現(xiàn)什么呢?


1.源代碼 Source

2.關(guān)于多屏幕支持的google官方文檔:http://developer.android.com/guide/practices/screens_support.html

3.關(guān)于 Intents 的文檔:here

4.關(guān)于平板分塊處理的文檔資料: multi-pane tablet view

5.感謝 NSHipster

原文鏈接: objc

譯文鏈接: http://blog.jobbole.com/67098/

責(zé)任編輯:閆佳明 來(lái)源: blog.jobbole
相關(guān)推薦

2014-07-15 15:38:41

Android

2022-01-21 08:21:02

Web 安全前端程序員

2013-12-16 09:36:49

程序員編程語(yǔ)言

2011-08-18 16:34:28

程序員必須知道

2023-11-01 08:01:48

數(shù)據(jù)結(jié)構(gòu)軟件工程

2014-06-20 16:16:32

程序員算法

2020-04-28 10:03:12

前端開發(fā)Mac

2015-03-06 10:10:18

程序員基礎(chǔ)實(shí)用算法講解

2020-04-02 15:37:58

數(shù)據(jù)結(jié)構(gòu)存儲(chǔ)

2020-03-04 11:10:14

數(shù)據(jù)結(jié)構(gòu)程序員編譯器

2010-07-16 09:00:00

.NET

2013-07-09 15:26:29

程序員算法

2024-09-03 13:24:12

2014-09-02 10:29:24

程序員必備英語(yǔ)詞匯

2020-03-22 15:54:14

全棧開發(fā)框架庫(kù)

2023-01-10 08:12:52

Java程序員負(fù)載均衡

2015-03-20 13:15:40

Java程序員JVM命令令行標(biāo)志

2023-02-06 16:46:59

JavaScript程序員技巧

2018-08-20 09:58:01

數(shù)據(jù)結(jié)構(gòu)程序員面試數(shù)據(jù)

2013-12-23 12:24:59

IT技術(shù)周刊
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)