TabAcitivity繼承自AcitivtyGroup,AcitivityGroup的主要作用是建立一個LocalActivityManger,然後把activity的onCreate等事件傳遞給LocalActivity來處理,作用僅此而已,非常簡單。
TabActivity真正重要的包括三部分,TabHost,TabWidget,LocalActivityManager.
TabHost主要是面向使用者的介面,它的主要作用就是添加tab,用TabSpec來完成一個完整的tab的抽象(包括標籤及其內容),一個string 類型的tag,這個tag用來標識一個tab,比如在退出程式時記錄當前是哪個tab以便在再次進入的時候顯示退出前顯示的tab,它最重要的作用在於當用intent做為一個tab,即要把一個activity作為內容(content)嵌入(即embeded
activity的概念)進去,成為一個tab的內容。
另外一個在TabHost中比較重要的部分就是,它主要運用了策略模式來完成標籤和內容的抽象。
建立一個介面IndicatorStrategy,用一個方法createIndicatorView()來建立view(即在TabWidget上顯示的標籤),根據傳入的參數不同,有LabelIndicatorStrategy,LabelAndIconIndicatorStrategy,ViewIndicatorStrategy三種。從名稱即可以看出標籤可以為一個只含有String,也可以含有String和一張圖片,或者使用者自訂的view等三種形式。
用介面ContentStrategy來抽象內容,有兩個方法,getContentView()用來擷取view,用tabClosed()來完成關閉的操作(比如使用者點擊其他tab,關閉當前的tab),按照內容的不同有ViewIdContentStrategy(給定一個layout id作為內容),FactoryContentStrategy(使用者實現繼承TabContentFactory,用createTabContent()來建立一個view作為內容),IntentContentStrategy(指定一個intent(即將一個activity作為內容))三種方式。內容的rootView是一個framelayout,切換是通過讓選擇的內容visible,讓原來的view
invisible實現的。在剛開始點擊標籤時建立view,在後面的時候直接用。所以將actvity作為內容時,如果建立需要很長時間的話可能會覺得遲鈍(這裡可能可以通過在建立tabhost的時候首先完成費時的操作這一辦法減少遲鈍感),而再後面切換的時候感覺很順暢。
其中把activity內容是通過用LocalActvityManager來啟動activity,並擷取到一個window,再擷取window的decorView來得到view,然後作為內容。代碼如下:
final Window w = mLocalActivityManager.startActivity( mTag, mIntent);
final View wd = w != null ? w.getDecorView() : null;
上節分析了TabHost,這節接著分析TabWidget.
TabWidget比較簡單,它繼承自LinearLayout,用來放標籤。它覆蓋了addView(View child)來實現添加一個標籤。在沒有指定view的LayoutParams時它預設給標籤加上高度充滿TabWidget,寬度上根據標籤個數平分的LayoutParams,這樣,如果在添加標籤時沒有設定LayoutParams的時候就會看到標籤平均分布的情況。然後再根據有沒有dividerDrawable來判斷是否添加,這個dividerDrawable應該是標籤之間的那個圖片。TabWidget規定的較固定,使用起來的時候有可能很不美觀,實際上看到網上有人說用TabActivity還不如用Gallery,這句話有一定道理,如果不需要把一個activity作為一個view嵌入進去的話使用Gallery的確更美觀更炫,但存在就有道理,我想TabActivity真正存在的原因就是為了embeded
activity,即把activity做為一個view加入到另一個actvity中,而又有LocalActivityManger來控制activity的生命週期所以不必操心生命週期問題。由於TabWidget的布局較為固定,所以可能會導致看起來不美觀,有需要根據需求定製自己的TabWidget的需要(比如我自己就在TabWidget中間加入空隙,使它看起來有標籤被分組了的效果),在修改的時候需要注意兩個函數:getChildTabViewAt(int index)和getTabCount(),由於系統本身的view排布要麼全部是標籤,要麼一個dividerDrawable加一個標籤的排布,所以這兩個函數實現較為簡單,如果定製自己的TabWidget的話可能需要修改這兩個函數,會稍微複雜點。
LocalActivityManager的話主要看一個函數startActivity(String id, Intent intent),因為String型的id是用來標識一個activity的,所以在addTab()的時候不能讓tab tag重。因為TabActivity中當點擊內容是activity的標籤時就會調用startActivity()來擷取view,而在啟動的時候根據Intent的Flags處理有所不同,所以設定IntentFlags的時候需要注意,(以下此段來自個人翻譯,英語水平差如又錯誤請見諒)如果在調用startActivty()的時候這個id
下已經有一個activity被啟動了的話,那麼根據不同情況它要麼被destroy然後再重新建立一個然後啟動,要麼就直接使用它。原文和翻譯如下:
/**
* Start a new activity running in the group. Every activity you start
* must have a unique string ID associated with it -- this is used to keep
* track of the activity, so that if you later call startActivity() again
* on it the same activity object will be retained.
*
*啟動一個運行在group的新的activity.每一個啟動的actvity必須擁有
*一個唯一的string ID,它被用來記錄activity的蹤跡,所以如果下次
*再次調用startActivity() 的時候,相同的activity 對象將被保留下來。
*
* <p>When there had previously been an activity started under this id,
* it may either be destroyed and a new one started, or the current
* one re-used, based on these conditions, in order:</p>
*
*如果在這個id下已經有一個activity啟動了的話,那根據不同情況
*它要麼被destroyed掉然後啟動一個新的,要麼當前存在的這個
*被重新使用,按以下順序:
* <ul>
* <li> If the Intent maps to a different activity component than is
* currently running, the current activity is finished and a new one
* started.
*
*如果intent映射到跟當前啟動並執行不同的 activity commponent(包名)
*的話,當前的activity會被結束掉然後一個新的會被啟動。
*
* <li> If the current activity uses a non-multiple launch mode (such
* as singleTop), or the Intent has the
* {@link Intent#FLAG_ACTIVITY_SINGLE_TOP} flag set, then the current
* activity will remain running and its
* {@link Activity#onNewIntent(Intent) Activity.onNewIntent()} method
* called.
*
* 如果當前的activity用了不是多啟動並執行模式(比如 singleTop),
* 或者intent 設定了 FLAG_ACTIVITY_SINGLE_TOP,那麼當前的activity
* 仍舊會繼續運行並且會調用 Activity.onNewIntent().
*
* <li> If the new Intent is the same (excluding extras) as the previous
* one, and the new Intent does not have the
* {@link Intent#FLAG_ACTIVITY_CLEAR_TOP} set, then the current activity
* will remain running as-is.
* <li> Otherwise, the current activity will be finished and a new
* one started.
* </ul>
*
* 如果新的intent(不包括 extras)和以前的完全一樣,並且沒有設定
* FLAG_ACTIVITY_CLEAR_TOP ,那麼當前的 actvity 仍然會繼續運行。
*否則(其他情況下),當前的activity會被結束掉然後啟動一個新的activity。