《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中查看修改的过程,避免没必要要的误导。