惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Vercel News
Vercel News
Recorded Future
Recorded Future
CTFtime.org: upcoming CTF events
CTFtime.org: upcoming CTF events
The GitHub Blog
The GitHub Blog
Application and Cybersecurity Blog
Application and Cybersecurity Blog
Google DeepMind News
Google DeepMind News
cs.AI updates on arXiv.org
cs.AI updates on arXiv.org
Microsoft Azure Blog
Microsoft Azure Blog
K
KPMG report finds enterprise disconnect between AI and its ROI | CIO
M
MIT News - Artificial intelligence
云风的 BLOG
云风的 BLOG
Y
Y Combinator Blog
N
News | PayPal Newsroom
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Help Net Security
Help Net Security
博客园 - Franky
SecWiki News
SecWiki News
Recent Announcements
Recent Announcements
T
Troy Hunt's Blog
The Register - Security
The Register - Security
The Last Watchdog
The Last Watchdog
Webroot Blog
Webroot Blog
S
Security Affairs
博客园 - 司徒正美
S
Schneier on Security
I
InfoQ
博客园_首页
www.infosecurity-magazine.com
www.infosecurity-magazine.com
T
Threat Research - Cisco Blogs
Forbes - Security
Forbes - Security
腾讯CDC
N
Netflix TechBlog - Medium
N
News and Events Feed by Topic
Cloudbric
Cloudbric
T
The Exploit Database - CXSecurity.com
P
Proofpoint News Feed
A
About on SuperTechFans
Engineering at Meta
Engineering at Meta
Recent Commits to openclaw:main
Recent Commits to openclaw:main
B
Blog
V
Vulnerabilities – Threatpost
C
Check Point Blog
Google DeepMind News
Google DeepMind News
Google Online Security Blog
Google Online Security Blog
C
Cyber Attacks, Cyber Crime and Cyber Security
Hacker News - Newest:
Hacker News - Newest: "LLM"
C
Cisco Blogs
Schneier on Security
Schneier on Security
O
OpenAI News
K
Kaspersky official blog

博客园 - jlxuqiang

左手信仰,右手长剑 Cheat Sheet 《高级语言程序设计》课程指导 第 23 章 深入学习 intent 和任务 (选讲) 第 22 章 Master-Detail 用户界面 第 21 章 隐式 intent 12 信息2班 《基于Android的软件开发》课程成绩 test 13 信息2班 《安卓程序设计基础》课程成绩 第 20 章 相机 II:拍摄并处理照片 第 19 章 相机 I:取景器 第 18 章 上下文菜单与上下文操作模式 第 17 章 存储与加载本地文件 第 16 章 工具栏 第 15 章 应用本地化 第 14 章 fragment 的保留 第 13 章 使用 MediaPlayer 播放音频 第 11 章 使用 ViewPager 第 10 章 使用 fragment argument
第 12 章 对话框
jlxuqiang · 2015-08-24 · via 博客园 - jlxuqiang

请参考教材,全面理解和完成本章节内容... ...

复制工程ch11,将工程目录改名为ch12。

对话框既能引起用户的注意也可接收用户的输入。在提示重要信息或提供用户选项方面,它都非常有用。本章,我们将CriminalIntent(陋习手记)应用添加一个对话框,以供用户改变crime记录日期。点击CrimeFragment上的日期按钮,即可弹出对话框,如图12-1所示。

image

12-1 可供选择crime日期的对话框

图12-1所示的AlertDialog视图封装在DialogFragment(Fragment的子类)实例中。不使用DialogFragment,也可显示AlertDialog视图,但Android开发原则不推荐这种做法。使用FragmentManager管理对话框,可使用更多配置选项来显示对话框。

就CriminalIntent应用来说,我们首先会创建一个名为DatePickeFragment的DialogFragment子类。然后,在DatePickeFragment中,创建并配置一个显示DatePicker组件的AlertDialog实例。DatePickeFragment也将交给CrimePagerActivity来托管。

图12-2展示了以上各对象间的关系。

image

图12-2 两个由CrimePagerActivity托管的fragment对象图解

总结下来,要实现对话框显示,首先应完成以下任务:

  • 创建DatePickeFragment类;
  • 创建AlertDialog;
  • 通过FragmentManager在屏幕上显示对话框。

在本章的后面,我们将配置使用DatePicker,并实现CrimeFragment和DatePickerFragment之间必要数据的传递。

继续学习之前,请参照代码清单12-1添加所需的字符串资源。

代码清单12-1 为对话框标题添加字符串资源(values/strings.xml)

image

12.1 创建 DialogFragment

创建一个名为DatePickerFragment的新类,并设置其DialogFragment超类为支持库中的android.support.v4.app.DialogFragment类。

DialogFragment类有如下方法:

public Dialog onCreateDialog(Bundle savedInstanceState)

在屏幕上显示DialogFragment时,托管activity的FragmentManager会调用onCreateDialog方法。

在DatePickerFragment.java中,添加onCreateDialog( )方法的实现代码,创建一个带标题栏和OK按钮的AlertDialog,如代码清单12-2所示。(DatePicker组件稍后会添加)

注意AlertDialog需要import android.support.v7.app.AlertDialog;

代码清单12-2 创建DialogFragment(DatePickerFragment.java)

image

如代码清单12-2所示,使用AlertDialog.Builder类,以流接口(fluent interface)的方式创建了一个AlertDialog实例。

12.1.1 显示DialogFragment

和其他fragment一样,DialogFragment实例也是由托管activity的FragmentManager管理的。

CrimeFragment中,为DatePickerFragment添加一个tag常量。然后,在onCreateView( )方法中,删除禁用日期按钮的代码。为实现用户点击日期按钮展现DatePickerFragment界面,实现mDateButton按钮的OnClickListener监听器接口,如代码清单12-3所示。

代码清单12-3 显示DialogFragment(CrimeFragment.java)

image

运行CriminalIntent应用。点击日期按钮弹出对话框,单击OK按钮消除对话框,如图12-3所示。

image

12-3 带有标题和OK按钮的AlertDialog

12.1.2 设置对话框的显示内容

接下来,使用下列AlertDialog.BuildersetView(...)方法,添加DatePicker组件到AlertDialog对话框:

public AlertDialog.Builder setView(View view)

该方法配置对话框,实现在标题栏与按钮之间显示传入的View对象。

layout目录下,创建名为dialog_date.xml的布局文件(Layout XML File),注意,将其根元素改为DatePicker。该布局仅包含一个View对象,即我们生成并传给setView(...)方法的DatePicker视图。

参照图12-4,配置好DatePicker的XML布局文件。
image

12-4 DatePicker布局(layout/dialog_date.xml

DatePickerFragment.onCreateDialog( )方法中,生成DatePicker视图并添加到对话框中,如代码清单12-4所示。

代码清单12-4 添加DatePickerAlertDialog(DatePickerFragment.java)

image 

运行应用, 点击日期按钮,确认对话框上是否出现了DatePicker视图,如图12-5所示。

image

12-5 显示DatePickerAlertDialog

至此,将对话框显示在屏幕上的工作就完成了。下一节,我们会将DatePickerCrime的日期关联起来,并支持用户对其进行修改。

12.2 fragment 间的数据传递

前面,我们已经实现了activity之间以及基于fragment的activity之间的数据传递。现在需实现由同一activity托管的两个fragment,即CrimeFragmentDatePickerFragment间的数据传递,如图12-6。

image

12-6 CrimeFragmentDatePickerFragment间的对话

要传递crime的记录日期给DatePickerFragment,需实现一个newInstance(Date)方法,然后将Date作为argument附加给fragment。

为返回新日期给CrimeFragment,并实现模型层以及对应视图的更新,需将日期打包为extra并附加到Intent上,然后调用CrimeFragment.onActivityResult( )方法,并传入准备好的Intent参数,如图12-7所示。

image

12-7 CrimeFragmentDatePickerFragment间的事件流

但接下来,我们并没有选择调用托管activity的Activity.onActivityResult( )方法,而是调用了Fragment.onActivityResult(...)方法,这似乎有点奇怪?事实上,通过调用onActivityResult( )方法将数据从一个fragment返还给另一个fragment,这种做法不仅行得通,而且可以更灵活地展现对话框fragment。

12.2.1 传递数据给DatePickerFragment

要传递crime记录日期给DatePickerFragment,需将记录日期保存在DatePickerFragment的argument bundle中,这样,DatePickerFragment便可直接获取到它。

回顾第10章的内容,我们知道,替代fragment的构造方法,创建和设置fragment argument通常是在一个newInstance()方法中完成的。在DatePickerFragment.java中,添加newInstance(Date)方法,如代码清单12-5所示。

image

代码清单12-5 添加newInstance(Date)方法(DatePickerFragment.java)

image

然后,在CrimeFragment中,用DatePickerFragment.newInstance(Date)方法替换掉DatePickerFragment的构造方法,如代码清单12-6所示。

代码清单12-6 添加newInstance()方法(CrimeFragment.java)

image

DatePickerFragment需使用Date中的信息来初始化DatePicker对象。然而,DatePicker对象的初始化需整数形式的月、日、年。Date就是个时间戳,它无法直接提供整数形式的月、日、年。

要想获得所需的整数数值,必须首先创建一个Calendar对象,然后用Date对象对其进行配置,即可从Calendar对象中取回所需信息。

onCreateDialog(...)方法内,从argument中获取Date对象,然后使用它和Calendar对象完成DatePicker的初始化工作,如代码清单12-7所示。

代码清单12-7 获取Date对象并初始化DatePicker(DatePickerFragment.java)

image

如代码所示,初始化DatePicker对象时,同时也在该对象上设置了OnDateChangedListener监听器。这样,用户改变DatePicker内的日期后,Date对象即可得到同步更新。下一节,我们将把该Date对象回传给CrimeFragment

为防止设备旋转时发生Date数据的丢失,在onDateChanged( )方法的尾部,我们将Date对象回写保存到了fragment argument中。如发生设备旋转,而DatePickerFragment正显示在屏幕上,那么FragmentManager会销毁当前实例并产生一个新的实例。新实例创建后,FragmentManager会调用它的onCreateDialog( )方法,这样新实例便可从argument中获得保存的日期数据。相比以前使用onSaveInstanceState( )方法保存状态,在fragment argument中保存数据应对设备旋转显然更简单。

(如经常使用fragment,可能会困惑为何不直接保存DatePickerFragment?使用保留的fragment处理设备旋转问题(详见第14章)确实是个好办法。但不幸的是,目前DialogFragment类有个bug,会导致保存的实例行为异常,因此,尝试保存DatePickerFragment现在还不是个好的选择。)

现在,CrimeFragment可成功将要显示的日期传递给DatePickerFragment。运行CriminalIntent应用,查看最终效果。

12.2.2 返回数据给 CrimeFragment

为使CrimeFragment接收到DatePickerFragment返回的日期,需以某种方式追踪记录二者间的关系。

对于activity的数据回传,我们调用startActivityForResult( )方法,ActivityManager负责跟踪记录父activity与activity间的关系。当activity回传数据后被销毁了,ActivityManager知道接收返回数据的应为哪一个activity。

设置目标fragment

类似于activity间的关联,可将CrimeFragment设置成DatePickerFragment目标 fragment。要建立这种关联,可调用以下Fragment方法:

public void setTargetFragment(Fragment fragment, int requestCode)

该方法接受目标fragment以及一个类似于传入startActivityForResult( )方法的请求代码作为参数。随后,目标fragment可使用该请求代码通知是哪一个fragment在返回数据信息。

目标fragment以及请求代码由FragmentManager负责跟踪记录,我们可调用fragment(设置目标fragment的fragment)的getTargetFragment()getTargetRequestCode()方法获取它们。

在CrimeFragment.java中,创建一个请求代码常量,然后将CrimeFragment设为DatePickerFragment实例的目标fragment,如代码清单12-8所示。

代码清单12-8 设置目标fragment(CrimeFragment.java)

image

传递数据给目标fragment

建立CrimeFragmentDatePickerFragment间的联系后,需将数据返还给CrimeFragment。返回的日期数据将作为extra附加给Intent

DatePickerFragment类中,新建一个sendResult()私有方法。通过该方法,创建一个intent,将日期数据作为extra附加到intent上。最后调用CrimeFragment.onActivityResult()方法。在onCreateDialog()方法中,取代setPositiveButton()null参数,实现一个DialogInterface.OnClickListener监听器接口。然后在监听器接口的onClick()方法中,调用新建的sendResult()私有方法并传入结果代码,如代码清单12-9所示。

代码清单12-9 回调目标fragment(DatePickerFragment.java)

image

在CrimeFragment中,覆盖onActivityResult(...)方法,从extra中获取日期数据,设置对应Crime的记录日期,然后刷新日期按钮的显示,如代码清单12-10所示。

代码清单12-10 响应DatePicker对话框(CrimeFragment.java)

image

onCreateView()onActivityResult()方法中,设置按钮上显示信息的代码完全一样。因此,为避免代码冗余,将其封装到一个公有的updateDate()方法中,然后分别在两个方法中调用它,如代码清单12-11所示。

代码清单12-11 使用公共的updateDate()方法(CrimeFragment.java)

image

日期数据的双向传递完成了。运行CriminalIntent应用,确保可以控制日期的传递与显示。修改某项Crime的日期,确认CrimeFragment视图显示了新的日期。然后返回crime列表项界面,查看对应Crime的日期,确认模型层数据已得到更新。

还有一个问题, 日期显示的格式是不好看,改成“标准”格式比较耐看,参考代码清单12-12修改updateDate()函数。

代码清单12-12 修改updateDate()方法,显示北京时间(CrimeFragment.java)

image

同样,ListView 的日期显示的格式也是“不好看“,参考代码清单12-13改成“标准”格式

代码清单12-13 ListView 的日期,显示北京时间(CrimeFragment.java)

image