《Android編程權威指南》-讀書筆記(十一) 完善CriminalIntent

《Android編程權威指南》-讀書筆記(十一) 完善CriminalIntent html

 

在上篇文章中,咱們跟隨本書做者,使用了單個的Fragment作了最簡單的插入操做。本篇文章將跟隨做者進行更深刻的完善各類功能。java

 

本章目標:android

  • 使用ListFragment顯示列表
  • fragment之間傳遞數據
  • 使用ViewPager來實現劃屏顯示
  • 對話框

 

使用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。本章採用了以代碼的方式建立視圖它包含如下步驟:

  • 爲ViewPager建立資源ID;
  • 建立ViewPager實例並賦值給mViewPager;
  • 賦值資源ID給ViewPager,並對其進行配置;
  • 設置ViewPager爲activity的內容視圖。

 

建立獨立資源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。在個人代碼中我貌似將顯示標題的位置拿掉了。

https://developer.android.com/reference/android/support/v4/view/ViewPager.OnPageChangeListener.html#onPageScrollStateChanged(int)

這個是官方的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的方法來顯示對話框,由於有以下優勢:

  • 使用FragmentManager管理對話框,可使用更多配置選項來顯示對話框;
  • 發生旋轉時封裝在fragment中的AlertDialog不會消失

 

在屏幕上顯示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中查看修改的過程,避免沒必要要的誤導。

相關文章
相關標籤/搜索