zoukankan      html  css  js  c++  java
  • 《Android编程权威指南》-读书笔记(十一) 完善CriminalIntent

    《Android编程权威指南》-读书笔记(十一) 完善CriminalIntent

    在上篇文章中,我们跟随本书作者,使用了单个的Fragment做了最简单的插入操作。本篇文章将跟随作者进行更深入的完善各种功能。

    本章目标:

    • 使用ListFragment显示列表
    • fragment之间传递数据
    • 使用ViewPager来实现划屏显示
    • 对话框

    使用ListFragment显示列表

    如果是挑战,或者没有UI我会给出草图之类的UI。或手画或Axure原型。每次例子本书都给出了最终UI,所以这步基本都可以省了。本章在例子CriminalIntent中使用ListFragment。以达到如下的效果:

    资源相关

    在这个UI中所有的数据都是根据动态数据显示的,因为没有用到任何图片资源或者字符串资源。所以没有修改的地方。(目前的资源默认的为按钮文字,界面上出现的文字等)

    数据相关

    现在需要显示一串数据,书中新增了一个可以容纳多个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中查看修改的过程,避免不必要的误导。

  • 相关阅读:
    OAF_文件系列8_实现OAF处理Excel的JXL包详解
    OAF_文件系列7_实现OAF处理Excel的JXL包介绍(概念)
    OAF_文件系列6_实现OAF导出XML文件javax.xml.parsers/transformer(案例)
    Kafka SSL安装与配置
    如何构建推荐系统
    Flink消费Kafka到HDFS实现及详解
    Kafka网络模型和通信流程剖析
    Kafka日志压缩剖析
    Kafka Eagle安装详情及问题解答
    Kafka幂等性原理及实现剖析
  • 原文地址:https://www.cnblogs.com/canglin/p/4378259.html
Copyright © 2011-2022 走看看