《Android編程權威指南》-讀書筆記(十一) 完善CriminalIntent html
在上篇文章中,咱們跟隨本書做者,使用了單個的Fragment作了最簡單的插入操做。本篇文章將跟隨做者進行更深刻的完善各類功能。java
本章目標:android
使用ListFragment顯示列表 git
若是是挑戰,或者沒有UI我會給出草圖之類的UI。或手畫或Axure原型。每次例子本書都給出了最終UI,因此這步基本均可以省了。本章在例子CriminalIntent中使用ListFragment。以達到以下的效果:編程
資源相關 api
在這個UI中全部的數據都是根據動態數據顯示的,由於沒有用到任何圖片資源或者字符串資源。因此沒有修改的地方。(目前的資源默認的爲按鈕文字,界面上出現的文字等)app
數據相關 ide
如今須要顯示一串數據,書中新增了一個能夠容納多個Crime對象ArrayList類。它定義了2個私有變量函數
private static CrimeLab sCrimeLab;學習
private Context mAppContext;
s開頭的變量是開發的命名約定。它表明了變量sCrimeLab是一個靜態變量。
這個類的代碼現階段以下:
http://git.oschina.net/canglin/CriminalIntent/commit/2f5580a992c804949a14a921dae7535a6097532f
這個類裏面定義了個一個get方法用來傳入一個Context。而在18行sCrimeLab直接調用了構造函數,構造函數的參數倒是getApplicationContext(),這是由於Context多是一個Activity,也多是一另外一個Context對象,如Service。在應用的整個生命週期裏,沒法保證只要CrimeLab須要用到Context,Context就必定會存在。因此才使用getApplicationContext()。至於12行public 的構造函數我寫錯了,我將會在下個版本的Git鏡像中作修正。
將一些Crime對象保存到CrimeLab中去。增長一個Crime的ArrayList列表,並添加Getter()方法。
而後在增長一個查詢操做在CrimeLab中爲getCrime(UUID id)。我更傾向於使用getCrimeById()這種命名法。
完成後的CrimeLab最乾淨版不包含模擬數據代碼以下:
http://git.oschina.net/canglin/CriminalIntent/commit/e4a9e6fac36f7eca76e063b406e194338f3fa778
邏輯相關
下圖是CriminalIntent應用的總體規劃設計
這個應用是在容器視圖中顯示列表。咱們要建立一個ListFragment和一個Activity,還有與ListFragment相匹配的layout。
Fragment
建立CrimeListFragment類擴展自ListFragment。HoneyComb系統版本引入了ListFragment類,相應的,支持庫也引入了該類。
import android.support.v4.app.ListFragment;
ListFragment是經過ListView將列表項展現給用戶。而ListView經過adapter來申請視圖對象。
Adapter負責:
建立必要的視圖對象;
用模型層數據填充視圖對象;
將準備好的視圖對象返回給ListView。
隨意例子中採用了setListAdapter(ListAdapter)來爲CrimeListFragment管理內置ListView設置adapter。(詳情參看後面的代碼連接,如今就能夠打開它對比觀看)
FragmentActivity
因爲每個ActivityFragment都有類似的代碼,因而做者建立了一個SingleFragmentActivity抽象類用來減小之後的代碼輸入。在書中的例子都是在一個FragmentContainer動態添加一個Fragment,因此惟一不一樣的代碼就是在事物添加Fragment以前動態建立的代碼。
修改CrimeActivity擴展自SingleFragmentActivity。
建立CrimeListActivity擴展自SingleFramentActivity。
由於這2個類惟一的區別
都只是在23行而已。採用抽象的方法後,每一個擴展自SingleFragmentActivity的類都必須@Override掉createFragment()。
視圖相關
須要在res/layout/list_item_crime.xml中的以下:
代碼以下:
http://git.oschina.net/canglin/CriminalIntent/commit/05a1da49e017dbdcef2d795d6da07eca41a3a006
在本章中只關注下面的類和layout資源文件。其餘的刪除掉均可以,不會影響應用的正常運行。
對象
Crime 列表子元素的對象
CrimeLab 能夠建立和獲取一個Crime 列表。
Activity
CrimeListActivity 擴展自SingleFragmentActivity 建立CrimeListFragment 事物
SingleFragmentActivity
Fragment
CrimeListFragment 根據list_item_crime.xml 生成相應的View
Res/layout
Activity_fragment.xml 定義了容易視圖
List_item_crime.xml 定義了列表子元素的視圖
因爲默認的Activity 不是CrimeListActivity
<activity android:name=".CrimeListActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
這樣設置後默認的將會是CrimeListActivity。
在例子初期作的很隨意,爲後面幾個目標作準備,我將源代碼作了一些調整,調整後代碼以下:
http://git.oschina.net/canglin/CriminalIntent/commit/05a1da49e017dbdcef2d795d6da07eca41a3a006
使用fragment argment
咱們學習過在Activity中是調用startActivity(Intent)來啓動另一個activity。如今在Fragment中仍是調用startActivity(Intent)來啓動Activity。
在點擊ListFragment將會顯示詳細的信息。詳細信息界面應該是在第8章中完成。
界面設置好後,資源文件的字符串最初是這個樣子。由於增長了幾個字符串,可是尚未在strings.xml中添加,效果以下圖所示:
資源文件填寫完成後
代碼以下:
http://git.oschina.net/canglin/CriminalIntent/commit/918aed3dd490b12f39f00701e4806cada3ad0b63
到如今爲止界面界面基本成型,裏面全部的事件,以及數據處理,還有業務邏輯我都把它精簡到了最低的程度。中間不少地方在本書中是要求加入一些非UI代碼的,我都沒有加入。至於列表的數據那一塊,也只是爲了讓界面邏輯可以完整。
給CrimeFragment填充數據
使用以前學到的方法用Intent傳遞數據,在CrimeFragment的onCreate()中從Intent讀取數據。
首先定義一個id
public static final String EXTRA_CRIME_ID =
"com.example.lijing.criminalintent.crime_id";
…..
而後在onCreate()中
UUID crimeId = (UUID)getActivity().getIntent().getSerializableExtra(EXTRA_CRIME_ID);
mCrime = CrimeLab.get(getActivity()).getCrime(crimeId);
數據在CrimeListFragment中startActivity()之
putExtra(CrimeFragment.EXTRA_CRIME_ID,c.getId());
完成後界面是這個樣子:
代碼發生以下變更:
http://git.oschina.net/canglin/CriminalIntent/commit/657c3d4164e08968dca123c3babec0ee80f97327
界面之間傳遞數據的改進
原先的代碼以下
UUID crimeId = (UUID)getActivity().getIntent().getSerializableExtra(EXTRA_CRIME_ID);
在這段代碼中crimeId是存儲在CrimeActivity中的。如今將它由CrimeActivity的intent內的extra改成arguments bundle。每一個fragment實例均可以附帶一個Bundle對象。該bundle包含有key-value對,咱們能夠如同附加extra到Activity的intent中那樣使用它們。一個key-value對即一個argument。
UUID crimeId = (UUID)getArguments().getSerializable(EXTRA_CRIME_ID);
並給fragment一個newInstance()來建立本身,並在這個靜態方法裏建立arguments。
總的來講就是由之前從Activity中獲取參數,改爲從本身的存儲區裏獲取參數。而本身的存儲區裏的參數是在建立該fragment是寫入的。
這是代碼的改動:
http://git.oschina.net/canglin/CriminalIntent/commit/95d7da1d76c2ac316cdb1f1af823df3cb745e133
使用ViewPager來實現劃屏顯示
爲了實現這個效果,咱們須要建立一個ViewPager的activity,命名爲CrimePagerActivity來取代CrimeActivity。本章採用了以代碼的方式建立視圖它包含如下步驟:
建立獨立資源ID(res/values/ids.xml)
定義獨立資源ID與定義字符串資源ID並無什麼不一樣:在res/values目錄下的XML文件中建立一個項目元素。建立一個名爲res/values/ids.xml的Android XML 資源文件。
以代碼的方式建立內容視圖(CrimePagerActivity.java)
mViewPager = new ViewPager(this);
mViewPager.setId(R.id.viewPager);
setContentView(mViewPager);
而後咱們使用FragmentStatePagerAdaper爲咱們的代理,負責管理與ViewPager的對話並協同工做。
代碼以下:
http://git.oschina.net/canglin/CriminalIntent/commits/master
到這裏在詳細信息界面就實現了拖動。
如今程序有一個Bug就是,當我點擊一個詳細信息的時候,詳細信息界面中顯示的永遠是第一條。如今咱們經過設置setCurrnetItem(index)是當前詳細頁面的信息是選中的選項。
有關ViewPager.OnPageChangeListener
在本書的例子中,當頁面發生改變的時候將標題設置給CrimePagerActivity。在個人代碼中我貌似將顯示標題的位置拿掉了。
這個是官方的api地址
這個方法必須重寫3個抽象的方法,若是如今不知道寫什麼能夠將3個方法複製進去就能夠了。
mViewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
public void onPageScrollStateChanged(int state) {}
public void onPageScrolled (int position, float positionOffset, int positionOffsetPixels) {}
public void onPageSelected (int position) {
Crime crime = mCrimes.get(position);
if (crime.getTitle() != null) {
setTitle(crime.getTitle());
}
}
});
就像這個樣子,可是這段代碼在如今的程序裏,是不會有界面改變的。因此在這裏特別強調一下。
完成後代碼以下:
http://git.oschina.net/canglin/CriminalIntent/commits/master
對話框
在咱們CrimeFragment對應的詳細信息界面裏有一個時間設置按鈕。如今咱們就按照書中的要求完善這個按鈕的對話框。
做者採用將AlertDialog封裝在DialogFragment的方法來顯示對話框,由於有以下優勢:
在屏幕上顯示DialogFragment時,託管activity的FragmentManager會調用onCreateDialog()。在onCreateDialog裏咱們須要返回一個AlertDialog.Builder。
在顯示對話框的時候要注意。要將DialogFragment添加給FragmentManager管理並放置到屏幕上,能夠調用fragment的show方法。
Public void show (FragmentManager manager, String tag)
Public void show(FragmentTransactiong transaction, String tag)
String參數是用來隊列中的DialogFragment。在FragmentManager和FragmentTransaction的選擇上,書中選擇了FragmentManager由於傳入這個參數,事物能夠自動建立提交。
最簡單的界面效果以下:
現階段代碼以下:
http://git.oschina.net/canglin/CriminalIntent/commit/ddf4b0365937ea287d0f64f7b437c1822f8745b0
對話框之間的數據交互,在本章已經簡單介紹過了。書中在這裏是繼續完成了的。本着達到目標最簡單的代碼原則,這些代碼先不提交到Git。
在每一個小段落最後都會有當前階段的Git代碼地址。
小結:
到如今爲止,基本上Android的一些最基本的界面,最基本的業務邏輯,數據邏輯都已經完成了。每一個階段的代碼都是儘可能的刪減到最少,爲了方便在Git中查看修改的過程,避免沒必要要的誤導。