接上期,著重分析主干邏輯橄维,先看第一個綜合頁面尺铣。
五個Tab頁定義可以看MainTab ,雖然enum占用存儲較多争舞,但可讀性的提升也同樣顯而易見凛忿,以下是代碼片段:
public enum MainTab {
NEWS(0, R.string.main_tab_name_news, R.drawable.tab_icon_new,
NewsViewPagerFragment.class),
TWEET(1, R.string.main_tab_name_tweet, R.drawable.tab_icon_tweet,
TweetsViewPagerFragment.class),
QUICK(2, R.string.main_tab_name_quick, R.drawable.tab_icon_new,
null),
EXPLORE(3, R.string.main_tab_name_explore, R.drawable.tab_icon_explore,
ExploreFragment.class),
ME(4, R.string.main_tab_name_my, R.drawable.tab_icon_me,
MyInformationFragment.class);
綜合頁當(dāng)然就是NewsViewPagerFragment了,我們自頂向下逐步分析竞川。
BaseFragment extends Fragment
預(yù)定義了多種狀態(tài)店溢,有可能會在子類中用到:
public static final int STATE_NONE = 0;
public static final int STATE_REFRESH = 1;
public static final int STATE_LOADMORE = 2;
public static final int STATE_NOMORE = 3;
public static final int STATE_PRESSNONE = 4;// 正在下拉但還沒有到刷新的狀態(tài)
public static int mState = STATE_NONE;
主要是調(diào)用Activity,提供ProgressDialog顯隱功能:
protected void hideWaitDialog() {
FragmentActivity activity = getActivity();
if (activity instanceof DialogControl) {
((DialogControl) activity).hideWaitDialog();
}
}
protected ProgressDialog showWaitDialog() {
return showWaitDialog(R.string.loading);
}
BaseViewPagerFragment extends BaseFragment
官方描述:帶有導(dǎo)航條的基類委乌。
這一點從其持有的域也可以看出:
protected PagerSlidingTabStrip mTabStrip;
protected ViewPager mViewPager;
protected ViewPageFragmentAdapter mTabsAdapter;
protected EmptyLayout mErrorLayout;
onCreateView()中加載以下布局:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="fill_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<!-- 導(dǎo)航標(biāo)題欄 -->
<net.oschina.app.widget.PagerSlidingTabStrip
android:id="@+id/pager_tabstrip"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="?attr/windows_bg"
app:allowWidthFull="true"
app:slidingBlock="?attr/sliding_block_bg" >
</net.oschina.app.widget.PagerSlidingTabStrip>
<View
android:id="@+id/view_pager_line"
android:layout_width="match_parent"
android:layout_below="@id/pager_tabstrip"
android:layout_height="1px"
android:background="?attr/lineColor" />
<android.support.v4.view.ViewPager
android:id="@+id/pager"
style="@style/fill_fill"
android:layout_below="@id/view_pager_line">
</android.support.v4.view.ViewPager>
<net.oschina.app.ui.empty.EmptyLayout
android:id="@+id/error_layout"
style="@style/fill_fill"
android:visibility="gone" />
</RelativeLayout>
其中PagerSlidingTabStrip extends HorizontalScrollView床牧,同樣的一個效果,還可以參見Google Contacts源碼中在PeopleActivity使用的ViewPagerTabs extends HorizontalScrollView:
http://androidxref.com/6.0.1_r10/xref/packages/apps/ContactsCommon/src/com/android/contacts/common/list/ViewPagerTabs.java
onViewCreated()中調(diào)用了如下兩行代碼遭贸,不用說戈咳,當(dāng)然是留給子類覆蓋的了:
setScreenPageLimit();
onSetupTabAdapter(mTabsAdapter);
NewsViewPagerFragment extends BaseViewPagerFragment
實現(xiàn)剛才說到的方法:
@Override
protected void onSetupTabAdapter(ViewPageFragmentAdapter adapter) {
String[] title = getResources().getStringArray(
R.array.news_viewpage_arrays);
adapter.addTab(title[0], "news", NewsFragment.class,
getBundle(NewsList.CATALOG_ALL)); // 注一,用Bundle提供信息給Fragment
adapter.addTab(title[1], "news_week", NewsFragment.class,
getBundle(NewsList.CATALOG_WEEK));
adapter.addTab(title[2], "latest_blog", BlogFragment.class,
getBundle(BlogList.CATALOG_LATEST));
adapter.addTab(title[3], "recommend_blog", BlogFragment.class,
getBundle(BlogList.CATALOG_RECOMMEND));
}
private Bundle getBundle(int newType) {
Bundle bundle = new Bundle();
bundle.putInt(BaseListFragment.BUNDLE_KEY_CATALOG, newType);
return bundle;
}
@Override
protected void setScreenPageLimit() {
mViewPager.setOffscreenPageLimit(3);
}
可以看出,資訊和熱點使用的同一個Fragment著蛙,博客和推薦也是同一個删铃。
從mViewPager.setOffscreenPageLimit(3);來看,所有Tab頁保留了下來踏堡。
比較有意思的是猎唁,它還實現(xiàn)了這樣一個接口:
/**
* 當(dāng)tabHost再次被點擊時
* @author FireAnt(http://my.oschina.net/LittleDY)
* @version 創(chuàng)建時間:2014年11月17日 上午11:00:15
*
*/
public interface OnTabReselectListener {
public void onTabReselect();
}
具體來說是看該Fragment中嵌套的Fragment是否有實現(xiàn)此接口然后決定是否調(diào)用:
@Override
public void onTabReselect() {
try {
int currentIndex = mViewPager.getCurrentItem();
Fragment currentFragment = getChildFragmentManager().getFragments()
.get(currentIndex);
if (currentFragment != null
&& currentFragment instanceof OnTabReselectListener) {
OnTabReselectListener listener = (OnTabReselectListener) currentFragment;
listener.onTabReselect();
}
} catch (NullPointerException e) {
}
}
現(xiàn)在,我們來看綜合頁中的NewsFragment顷蟆,同樣是自頂向下胖秒。
BaseListFragment<T extends Entity> extends BaseFragment
這是一個泛型類,Bean包下有大量extends Entity的實體慕的。
關(guān)于泛型可以參考這篇:http://www.reibang.com/p/f258c907019d
使用了可以進(jìn)行下拉刷新的布局,以下為代碼片段:
<!-- google 官方下拉刷新 -->
<android.support.v4.widget.SwipeRefreshLayout
android:id="@+id/swiperefreshlayout"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:visibility="visible" >
<ListView
android:id="@+id/listview"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:divider="?attr/lineColor"
android:listSelector="@color/transparent"
android:dividerHeight="1px"
android:scrollbars="none"
android:scrollingCache="true" />
</android.support.v4.widget.SwipeRefreshLayout>
提供了一個ParserTask extends AsyncTask挤渔,從代碼中可以看到肮街,其doInBackground中有如下調(diào)用:
new SaveCacheTask(getActivity(), data, getCacheKey()).execute();
這并不是一個好的實現(xiàn),因為AsyncTask應(yīng)該在主線程中創(chuàng)建判导,否則其內(nèi)部的靜態(tài)Handler將無法正常工作嫉父,具體可以參考《Android開發(fā)藝術(shù)探索》。
這里該應(yīng)用的事件流中應(yīng)該是ParserTask 本身有確保在主線程加載眼刃。
在onScrollStateChanged中提供滾動事件的特判绕辖,代碼較長就不貼了。
提供上一篇中提到的已讀列表功能:
/**
* 保存已讀的文章列表
*
* @param view
* @param prefFileName
* @param key
*/
protected void saveToReadedList(final View view, final String prefFileName,
final String key) {
// 放入已讀列表
AppContext.putReadedPostList(prefFileName, key, "true");
TextView tvTitle = (TextView) view.findViewById(R.id.tv_title);
if (tvTitle != null) {
tvTitle.setTextColor(AppContext.getInstance().getResources().getColor(ThemeSwitchUtils.getTitleReadedColor()));
}
}
onCreate()中讀取前文注一提供的信息擂红,實際使用當(dāng)然會是在子類中了:
@Override
public void onCreate(android.os.Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle args = getArguments();
if (args != null) {
mCatalog = args.getInt(BUNDLE_KEY_CATALOG, 0); // 注二仪际,子類中會使用此信息
}
}
onResume()中判斷了是否要進(jìn)行定時刷新操作:
@Override
public void onResume() {
super.onResume();
if (onTimeRefresh()) {
onRefresh();
}
}
NewsFragment extends BaseListFragment<News> implements OnTabReselectListener
明顯使用了News這個Bean,取決于具體業(yè)務(wù)情況昵骤,略去不表树碱。
Bean解析,可以看出數(shù)據(jù)使用的是xml格式变秦,這一方法的實際調(diào)用位置在基類的ParserTask doInBackground中:
@Override
protected NewsList parseList(InputStream is) throws Exception {
NewsList list = null;
try {
list = XmlUtils.toBean(NewsList.class, is);
} catch (NullPointerException e) {
list = new NewsList();
}
return list;
}
覆蓋獲取數(shù)據(jù)的方法成榜,使用注二中提供的信息調(diào)用MobileAPI:
@Override
protected void sendRequestData() {
OSChinaApi.getNewsList(mCatalog, mCurrentPage, mHandler);
}
之前提過的OnTabReselectListener有進(jìn)行實現(xiàn),可以看出是提供了一個刷新功能:
@Override
public void onTabReselect() {
onRefresh();
}
而這個onRefresh()的實現(xiàn)是在基類BaseListFragment當(dāng)中蹦玫,也就是設(shè)置狀態(tài)赎婚,ListView回到頂部,然后獲取數(shù)據(jù):
// 下拉刷新數(shù)據(jù)
@Override
public void onRefresh() {
if (mState == STATE_REFRESH) {
return;
}
// 設(shè)置頂部正在刷新
mListView.setSelection(0);
setSwipeRefreshLoadingState();
mCurrentPage = 0;
mState = STATE_REFRESH;
requestData(true);
}
具體獲取數(shù)據(jù)的時候樱溉,視情況看是讀緩存還是發(fā)請求獲取挣输。
緩存的實現(xiàn)是CacheManager,非常純粹的文件讀寫饺窿,略去不表歧焦。
根據(jù)業(yè)務(wù)情況,提供定時刷新的閾值給基類:
@Override
protected long getAutoRefreshTime() {
// 最新資訊兩小時刷新一次
if (mCatalog == NewsList.CATALOG_ALL) {
return 2 * 60 * 60;
}
return super.getAutoRefreshTime();
}
另外三個頁面也是采用完全類似的方式,讀者可以自行分析绢馍。
至此向瓷,綜合頁面分析完畢。下期再見舰涌。