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。