《Android编程权威指南(第3版)》要点摘录

  1. 第1章 Android 开发初体验
  2. 第2章 Android 与 MVC 设计模式
  3. 第3章 activity 的生命周期
  4. 第4章 Android 应用的调试
  5. 第5章 第二个 activity
  6. 第6章 Android SDK 版本与兼容
  7. 第7章 UI fragment 与 fragment 管理器
  8. 第8章 使用 RecyclerView 显示列表
  9. 第9章 使用布局与控件创建用户界面
  10. 第10章 使用 fragment argument
  11. 第11章 使用 ViewPager
  12. 第12章 对话框
  13. 第13章 工具栏
  14. 第14章 SQLite 数据库
  15. 第15章 隐式 intent
  16. 第16章 使用 intent 拍照
  17. 第17章 双版面主从用户界面
  18. 第18章 应用本地化
  19. 第19章 Android 辅助功能
  20. 第20章 数据绑定与 MVVM
  21. 第21章 音频播放与单元测试

第1章 Android 开发初体验

  1. 布局定义了一系列用户界面对象以及它们显示在屏幕上的位置。每个定义用来创建屏幕上的一个对象。(2页)
  2. “DNS反转”约定:将企业组织或公司的域名反转后,在尾部附加上应用名称。遵循此约定可以保证包名称的唯一性。(4页)
  3. 布局的命名规则是:颠倒 activity 子类名的单词顺序并全部转小写,然后在单词间添加下划线。(6页)
  4. 控件是用户界面的构造模块,控件可以显示文字或图像,与用户交互,甚至布置屏幕上的其他控件。每一个控件都是 View 类或其子类(如 TextView 或 Button)的一个具体实例。(7页)
  5. 各元素均有一组 XML 属性,属性可以看作如何配置控件的指令。(7页)
  6. 控件包含在视图(View)对象的层级结构中,这种结构又称作视图层级结构(view hierarchy)。(10页)
  7. LinearLayout 控件继承自 ViewGroup 控件(也是 View 子类)。ViewGroup 控件是包含并配置其他控件的特殊控件。想要以一列或一排的样式布置控件,就可以使用 LinearLayout 控件。其他 ViewGroup 子类还有 FrameLayout、TableLayout 和 RelativeLayout。(10页)
  8. 若某个控件包含在一个 ViewGroup 中,该控件与 ViewGroup 即构成父子关系。(10页)
  9. 在垂直的 LinearLayout 中,第一个定义的子控件出现在屏幕的最上端;而在水平的 LinearLayout 中,第一个定义的子控件出现在屏幕的最左端。(11页)
  10. android:text 属性值不是字符串值,而是对字符串资源(string resource)的引用。(11页)
  11. 项目的 app/java 目录是项目全部 Java 源代码的存放处。(13页)
  12. 布局是一种资源,资源是应用非代码形式的内容,项目的所有资源文件都存放在目录 app/res 的子目录下。布局资源文件存放在 res/layout/ 目录下,字符串资源文件存放在 res/values/ 目录下。(13页)
  13. 可以使用资源 ID 在代码中获取相应的资源,要为控件生成资源 ID,请在定义控件时为其添加 android:id 属性。(15页)
  14. 在 activity 中,可以调用以下 Activity 方法引用已生成的控件:
    public View findViewById(int id),该方法以控件的资源 ID 作为参数,返回一个视图对象。(17页)
  15. Android 应用属于典型的事件驱动类型。应用等待某个特定事件的发生,也可以说是应用正在“监听”特定事件。为响应某个事件而创建的对象叫作监听器(listener),监听器会实现特定事件的监听器接口(listener interface)。(17页)
  16. 监听器以匿名内部类来实现有两大好处:(18页)
  • 使用匿名内部类,可以相对集中地实现监听器方法,一眼可见;
  • 事件监听器一般只在一个地方使用,使用匿名内部类,就不用去创建繁琐的命名类了。
  1. Android 的 toast 是用来通知用户的简短弹出消息。(19页)
  2. 调用 Toast 类的以下方法可以创建 toast:
    public static Toast makeText(Context context,int resId,int duration)。该方法的 Context 参数通常是 Activity 的一个实例(Activity 本身就是 Context 的子类)。第二个参数是 toast 要显示字符串消息的资源 ID,Toast 类必须借助 Context 才能找到并使用字符串资源 ID。第三个参数通常是两个 Toast 常量中的一个,用来指定 toast 消息的停留时间。创建 toast 后,可调用 Toast.show() 方法在屏幕上显示 toast 消息。(20页)

第2章 Android 与 MVC 设计模式

  1. Android 应用基于模型-视图-控制器(Model-View-Controller,MVC)的架构模式进行设计。MVC 设计模式表明,应用的任何对象,归根结底都属于模型对象、视图对象以及控制器对象中的一种。(29页)
  2. 模型对象存储着应用的数据和业务逻辑。模型类通常用来映射与应用相关的一些事物。模型对象不关心用户界面,它为存储和管理应用数据而生。Android 应用里,模型类通常就是我们创建的定制类。应用的全部模型对象组成了模型层。(30页)
  3. 视图对象知道如何在屏幕上绘制自己,以及如何响应用户的输入。凡是能够在屏幕上看见的对象,就是视图对象。应用的全部视图对象组成了视图层。(30页)
  4. 控制器对象含有应用的逻辑单元,是视图对象与模型对象的联系纽带。控制器对象响应视图对象触发的各类事件,此外还管理着模型对象与视图层间的数据流动。在 Android 的世界里,控制器通常是 Activity、Fragment 或 Service 的子类。(30页)
  5. 模型对象与视图对象不直接交互。控制器作为它们之间的联系纽带,接收对象发送的消息,然后向其他对象发送操作指令。(30页)
  6. MVC 设计模式还便于复用类。相比功能多而全的类,功能单一的专用类更有利于代码复用。(31页)
  7. 在 Android 的世界里,视图对象通常由 XML 布局文件生成。(31页)
  8. 在为不同设备准备适配图片的同时,应用安装包容量也随之增大。(39页)
  9. 如果应用不包含设备对应的屏幕像素密度文件,在运行时,Android 系统会自动找到可用的图片资源,针对该设备进行缩放适配。(39页)
  10. 任何添加到 res/drawable 目录中,后缀名为 .png.jpg 或者 .gif 的文件都会自动获得资源 ID。(注意,文件名必须是小写字母且不能有任何空格符号)(40页)
  11. 在 XML 资源文件中,通过资源类型和资源名称,可引用其他资源。(41页)
  12. ImageButton 控件继承自 ImageView,Button 控件继承自 TextView。(43页)

第3章 activity 的生命周期

  1. 每个 Activity 实例都有其生命周期,在其生命周期内,activity 在运行、暂停、停止和不存在这四种状态间转换。每次状态转换时,都有相应的 Activity 方法发消息通知 activity。(45页)
  2. 用户可以与当前运行状态下的 activity 交互。设备上有很多应用,但是任何时候只能有一个 activity 处于用户能交互的运行状态。(46页)
  3. 千万不要自己去调用 onCreate(Bundle) 方法或任何其他 activity 生命周期方法。为通知 activity 状态变化,只需在 Activity 子类里覆盖这些方法,Android 会适时调用它们。(46页)
  4. 在回调覆盖实现方法里,超类实现方法总在第一行调用。也就是说,应首先调用超类实现方法,然后再调用其他方法。(48页)
  5. 停止的 activity 能够存在多久,谁也无法保证。系统需要回收内存时,它将首先销毁那些停止的 activity。(50页)
  6. 旋转设备会改变设备配置(device configuration)。设备配置实际是一系列特征组合,用来描述设备当前状态。(52页)
  7. 在运行时配置变更(runtime configuration change)发生时,可能会有更合适的资源来匹配新的设备配置。(53页)
  8. 按后退键就是告诉 Android,activity 用完了。随后,该 activity 就完全从内存中被抹掉。(56页)
  9. Bundle 是存储字符串键与限定类型值之间映射关系(键-值对)的一种结构。(56页)
  10. 在 Bundle 中存储和恢复的数据类型只能是基本类型(primitive type)以及可以实现 Serializable 或 Parcelable 接口的对象。(58页)
  11. 低内存状态下,Android 直接从内存清除整个应用进程,连带应用的所有activity。目前,Android 还做不到只销毁单个 activity。(59页)

第4章 Android 应用的调试

碰到运行异常时,记得在 LogCat 中寻找最后一个异常及其栈跟踪的第一行(对应着源代码)。这里是问题发生的地方,也是寻找解决方案的最佳起点。(64页)

第5章 第二个 activity

  1. manifest 配置文件是一个包含元数据的 XML 文件,用来向 Android 操作系统描述应用。应用的所有 activity 都必须在 manifest 配置文件中声明,这样操作系统才能够找到它们。(78页)
  2. 一个 activity 启动另一个 activity 最简单的方法是使用 startActivity 方法:
    public void startActivity(Intent intent)。(81页)
  3. activity 调用 startActivity(Intent) 方法时,调用请求发送给了操作系统的 ActivityManger。ActivityManger 负责创建 Activity 实例并调用其 onCreate(Bundle) 方法。(81页)
  4. intent 对象是组件用来与操作系统通信的一种媒介工具。(81页)
  5. intent 用来告诉 ActivityManger 该启动哪个 activity,使用以下构造方法:
    public Intent(Context packageContext,Class<?> cls)。传入该方法的 Class 类型参数告诉 ActivityManger 应该启动哪个 activity;Context 参数告诉 ActivityManger 在哪里可以找到它。(82页)
  6. 在启动 activity 前,ActivityManger 会确认指定的 Class 是否已在 manifest 配置文件中声明。(82页)
  7. 通过指定 Context 与 Class 对象,然后调用 intent 的构造方法来创建 Intent,则创建的是显示 intent。在同一应用中,使用显示 intent 来启动 activity。(82页)
  8. 一个应用的 activity 如需启动另一个应用的 activity,可通过创建隐式 intent 来处理。(82页)
  9. extra 信息可以是任意数据,它包含在 Intent 中,由启动方 activity 发送出去。接收方 activity 接收到操作系统转发的 intent 后,访问并获取其中的 extra 数据信息。(83页)
  10. 要将 extra 数据信息添加给 intent,需要调用 Intent.putExtra() 方法。Intent.putExtra() 方法形式多变,不变的是它总有两个参数。一个参数是固定为 String 类型的键,另一个参数是键值,可以是多种数据类型。(84页)
  11. 要从 extra 获取数据,会用到如下方法:
    public boolean getBooleanExtra(String name,boolean defaultValue)。第一个参数是 extra 的名字,第二个参数是指定默认值,它在无法获得有效键值时使用。(85页)
  12. Activity.getIntent() 方法返回了由 startActivity(Intent) 方法转发的 Intent 对象。(85页)
  13. 需要从子 activity 获取返回信息时,可调用以下 Activity 方法:
    public void startActivityForResult(Intent intent,int requestCode)。该方法的第二个参数是请求代码。请求代码是先发送给子 activity,然后再返回给父 activity 的整数值,由用户定义。在一个 activity 启动多个不同类型的子 activity,且需要判断消息回馈方时,就会用到该请求代码。(86页)
  14. 实现子 activity 发送返回消息给父 activity,有以下两种方法可用:
    public final void setResult(int resultCode)
    public final void setResult(int resultCode,Intent data)
    参数 resultCode 可以是以下任意一个预定义常量:Activity.RESULT_OK 或 Activity.RESULT_CANCELED。在没有调用 setResult() 方法的情况下,如果用户按了后退按钮,父 activity 则会收到 Activity.RESULT_CANCELED 的结果代码。(87页)
  15. ActivityManger 维护着一个非特定应用独享的回退栈。所有应用的 activity 都共享该回退栈。(93页)

第6章 Android SDK 版本与兼容

  1. 以最低版本设置值为标准,操作系统会拒绝将应用安装在系统版本低于标准的设备上。(96页)
  2. 大多数情况下,目标版本即最新发布的 Android 版本。(97页)
  3. Android 的特色功能是通过 SDK 中的类和方法展现的。(97页)
  4. Build.VERSION.SDK_INT 常量代表了 Android 设备的版本号。(99页)
  5. Android 开发者文档是优秀而丰富的信息来源。文档主页是 http://developer.android.com/。文档分为三大部分,即设计、开发和发布。设计部分的文档包括应用 UI 设计的模式和原则。开发部分包括 SDK 文档和培训资料。发布部分讲述如何在 Google Play 商店里或以开放发布模式准备并发布应用。(100页)

第7章 UI fragment 与 fragment 管理器

  1. fragment 是一种控制器对象,activity 可委派它执行任务。这些任务通常就是管理用户界面。受管的用户界面可以是一整屏或是整屏的一部分。(104页)
  2. 管理用户界面的 fragment 又称为 UI fragment。它自己也有产生于布局文件的视图。fragment 视图包含了用户可以交互的可视化 UI元素。(104页)
  3. activity 视图能预留位置供 fragment 视图插入。如果有多个 fragment 要插入,activity 视图就提供多个位置。(104页)
  4. fragment 本身没有在屏幕上显示视图的能力。因此,只有将它的视图放置在 activity 的视图层级结构中,fragment 视图才能显示在屏幕上。(106页)
  5. Google 有两个版本的 fragment 实现可供选择:原生版本和支持库版本。原生版本的 fragment 实现内置在设备系统中;支持库版本的 fragment 在类库里,发布时,会打包在应用里。使用支持库 fragment 的应用,无论在哪台设备上运行,都会有相同的表现。(108页)
  6. 每个项目都有两个 build.gradle 文件。一个用于整个项目,另一个用于应用模块。(109页)
  7. Gradle 允许设置未复制到项目中的依赖项。应用编译时,Gradle会找到并下载依赖包,并将其自动导入到项目中。(109页)
  8. Maven 是一个依赖包管理工具,Maven 坐标模式:groupId:artifactId:version。groupId 通常是类库的基础包名,能唯一标识 Maven 仓库中的依赖库;artifactId 是包中的特定库名;version 是指类库的版本号。(110页)
  9. fragment 的生命周期与 activity 的生命周期的一个关键区别就在于,fragment 的生命周期方法由托管它的 activity 调用,而不是由操作系统调用。fragment 的使用是 activity 内部的事情。(112页)
  10. activity 托管 UI fragment 有两种方式:(113页)
  • 在 activity 布局中添加 fragment;
  • 在 activity 代码中添加 fragment。
  1. Fragment.onCreate(Bundle) 是公共方法,而 Activity.onCreate(Bundle) 是受保护方法。Fragment.onCreate(Bundle) 方法及其他 Fragment 生命周期方法必须是公共方法,因为托管 fragment 的 activity 要调用它们。(118页
  2. Activity.findViewById(int) 方法能够在后台自动调用 View.findViewById(int) 方法,而 Fragment 类必须手动调用 fragment 视图的 View.findViewById(int) 方法。(120页)
  3. FragmentManager 类负责管理 fragment 并将它们的视图添加到 activity 的视图层级结构中。(122页)
  4. 要以代码的方式将 fragment 添加给 activity,需要直接调用 activity 的 FragmentManager。(122页)
  5. FragmentManager.beginTransaction() 方法创建并返回 FragmentTransaction 实例。FragmentTransaction 类支持流接口(fluent interface)的链式方法调用,以此配置 FragmentTransaction 再返回它。(123页)
  6. 容器视图资源 ID 的作用有:(124页)
  • 告诉 FragmentManager,fragment 视图应该出现在 activity 视图的什么位置;
  • 唯一标识 FragmentManager 队列中的 fragment。
  1. YAGNI 原则的意思是“你不会需要它(You Aren’t Gonna Need It)”,该原则鼓励大家不要去实现那些有可能需要的东西。(126页)
  2. AUF(Always Use Fragments)原则,即“总是使用 fragment”。(127页)
  3. 要使用支持库版 fragment,应用的 activity 必须继承 FragmentActivity。(127页)

第8章 使用 RecyclerView 显示列表

  1. 单例是特殊的 Java 类,在创建实例时,一个单例类仅允许创建一个实例。(130页)
  2. 应用能在内存里活多久,单例就能活多久。Android 从内存里清除应用时,单例对象也会随之消失。(130页)
  3. 要创建单例,需创建一个带有私有构造方法及 get() 方法的类。(131页)
  4. List 是一个泛型类,支持存放特定数据类型的有序列表对象,拥有获取、新增和删除列表元素的方法。符号 <> 告诉编译器,List 中的元素类型可以基于变量声明传入的抽象参数来确定。(132页)
  5. RecyclerView 是 ViewGroup 的子类,每一个列表项都是作为一个 View 子对象显示的。(137页)
  6. RecyclerView 的任务仅限于回收和定位屏幕上的 View。(138页)
  7. ViewHolder 为 itemView 而生:它引用着传给 super(view) 的整个 View 视图。(139页)
  8. RecyclerView 自身不会创建视图,它创建的是 ViewHolder,而 ViewHolder 引用着 itemView。(139页)
  9. RecyclerView 自己不创建 ViewHolder,这个任务实际是由 Adapter 来完成的。Adapter 是一个控制器对象,从模型层获取数据,然后提供给 RecyclerView 显示,是沟通的桥梁。(139页)
  10. Adapter 负责:创建必要的 ViewHolder 和绑定 ViewHolder 至模型层数据。(140页)
  11. 要创建 Adapter,首先要定义 RecyclerView.Adapter 子类。(140页)
  12. 所谓绑定,就是使用模型数据填充视图。(140页)
  13. 一旦有了够用的 ViewHolder,RecyclerView 就会停止调用 onCreateViewHolder(…) 方法。随后,它会回收利用旧的 ViewHolder 以节约时间和内存。(140页)
  14. RecyclerView 类来自于 Google 支持库。要使用它,首先要添加 RecyclerView 依赖库。(141页)
  15. 没有 LayoutManager 的支持,不仅 RecyclerView 无法工作,还会导致应用崩溃。所以,RecyclerView 视图创建完成后,就立即转交给了 LayoutManager 对象。(142页)
  16. RecyclerView 类不会亲自摆放屏幕上的列表项。实际上,摆放的任务被委托给了 LayoutManager。除了在屏幕上摆放列表项,LayoutManager 还负责定义屏幕滚动行为。(142页)
  17. 所谓绑定,实际就是让 Java 代码和控件关联起来。每一次视图实例化都是绑定。(145页)
  18. Android 操作系统核心库包含 ListView、GridView 和 Adapter 这 3 个类。(148页)
  19. Android 开发常用到单例的一大原因是,它们比 fragment 或 activity 活得久。(148页)

第9章 使用布局与控件创建用户界面

  1. 图形布局工具界面的中间区域是布局的界面预览窗口。右边紧挨着的是蓝图(blueprint)视图。蓝图和预览视图有点像,但它能显示各个控件视图的轮廓。预览让你看到视图长什么样,而从蓝图可以看出各个控件视图的大小比例。(151页)
  2. 图形布局工具界面的左下是控件树,控件树表明控件是如何在布局中组织的。图形布局工具界面的右边是属性视图。在此视图中,可以查看并编辑控件树中已选中的控件属性。(151页)
  3. 想要在 ConstraintLayout 里布置视图,不用再麻烦地拖来拖去,给它们添加上约束就可以了。(152页)
  4. 凡是以 layout 开头的属性都属于布局参数(layout parameter)。控件的布局参数是用来向父控件做指示的,即用于告诉父布局如何安排自己。(159页)
  5. 文字大小(text size)指定设备上显示的文字像素高度;边距(margin)指定视图控件间的距离;内边距(padding)指定视图外边框与其内容间的距离。(164页)
  6. px 是英文 pixel 的缩写,即像素。无论屏幕密度多少,一个像素单位对应一个屏幕像素单位。(164页)
  7. dp 或 dip 是英文 density-independent pixel 的缩写,即密度无关像素。在设置边距、内边距或任何不打算按像素值指定尺寸的情况下,通常都使用 dp 这种单位。如果屏幕密度较高,密度无关像素会相应扩展至整个屏幕。1 dp 在设备屏幕上总是等于 1/160 英寸。使用 dp 的好处是,无论屏幕密度如何,总能获得同样的尺寸。(164页)
  8. sp 是英文 scale-independent pixel 的缩写,即缩放无关像素。它是一种与密度无关的像素,这种像素会受用户字体偏好设置的影响。通常使用 sp 来设置屏幕上的字体大小。(164页)
  9. 边距属性是布局参数,决定了控件间的距离。内边距不是布局参数。属性 android:padding 告诉控件:在绘制控件自身时,要比所含内容大多少。(165页)
  10. 样式(style)是 XML 资源文件,含有用来描述控件行为和外观的属性定义。(166页)
  11. 主题是各种样式的集合。从结构上来说,主题本身也是一种样式资源,只不过它的属性指向了其他样式资源。(166页)
    使用主题属性引用,可将预定义的应用主题样式添加给指定控件。(166页)
  12. 所有 Android 主题都包括名为 listSeparatorTextViewStyle 的属性。(166页)

第10章 使用 fragment argument

  1. 从 fragment 中启动 activity 类似于从 activity 中启动 activity。调用 Fragment.startActivity(Intent) 方法,由它在后台再调用对应的 Activity 方法。(168页)
  2. 每个 fragment 实例都可附带一个 Bundle 对象,该 bundle 包含键-值对,一个键-值对即一个 argument。(172页)
  3. 要创建 fragment argument,首先需要创建 Bundle 对象。然后,使用 Bundle 限定类型的 put 方法将 argument 添加到 bundle 中。(172页)
  4. 要附加 argument bundle 给 fragment,需调用 Fragment.setArguments(Bundle) 方法,而且还必须在 fragment 创建后,添加给 activity 之前完成。(173页)
  5. activity 和 fragment 不需要也无法同时相互保持独立。托管 activity 应该知道 fragment 的内部细节,以便托管 fragment;但 fragment 不一定需要知道其托管 activity 的细节问题,至少在需要保持 fragment 通用独立的时候如此。(174页)
  6. fragment 需要获取它的 argument 时,会先调用 Fragment 类的 getArguments() 方法,再调用 Bundle 限定类型的 get 方法。(174页)
  7. 模型层保存的数据若有变化(或可能有变),应通知 RecyclerView 的 Adapter,以便其及时获取最新数据并刷新显示列表项。(174页)
  8. 一般来说,要保证 fragment 视图得到刷新,在 onResume() 方法内更新代码是最安全的选择。(176页)
  9. fragment 能够从 activity 中接收返回结果,但其自身无法持有返回结果,只有 activity 拥有返回结果。尽管 Fragment 有自己的 startActivityForResult(…) 方法和 onActivityResult(…) 方法,但没有 setResult(…) 方法。(177页)

第11章 使用 ViewPager

  1. ViewPager 仅存在于支持库,ViewPager 需要 PagerAdapter 的支持才能显示视图。(181页)
  2. ViewPager 默认加载当前屏幕上的列表项,以及左右相邻页面的数据,因此响应迅速。(183页)
  3. ViewPager 默认只显示 PagerAdapter 中的第一个列表项。要显示选中的列表项,可设置 ViewPager 当前要显示的列表项为数组中指定位置的列表项。(184页)
  4. FragmentStatePagerAdapter 会销毁不需要的 fragment。事务提交后,activity 的 FragmentManager 中的 fragment 会被彻底移除。FragmentStatePagerAdapter 类名中的 “state” 表明:在销毁 fragment 时,可在 onSaveInstanceState(Bundle) 方法中保存 fragment 的 Bundle 信息。用户切换回来时,保存的实例状态可用来生成新的 fragment。(184页)
  5. 对于不再需要的 fragment,FragmentPagerAdapter 会选择调用事务的 detach(Fragment) 方法来处理它,而非 remove(Fragment) 方法。FragmentPagerAdapter 只是销毁了 fragment 的视图,而 fragment 实例还保留在 FragmentManager 中。FragmentPagerAdapter 创建的 fragment 永远不会被销毁。(184页)
  6. 通常来说,使用 FragmentStatePagerAdapter 更节省内存。(185页)
  7. 需要 ViewPager 托管非 fragment 视图时(如图片这样的常见 View 对象),就需要实现原生 PagerAdapter 接口。(186页)
  8. 以代码的方式创建视图很简单:调用视图类的构造方法,并传入 Context 参数。不创建任何布局文件,用代码就能创建完整的视图层级结构。(187页)
  9. 使用布局文件的好处:(187页)
  • 布局文件能很好的分离控制器层和视图层对象,视图定义在 XML 布局文件中,控制器层对象定义在 Java 代码中。这样,假设控制器层有代码修改的话,代码变更管理相对容易很多;反之亦然。
  • 使用布局文件,还能使用 Android 的资源适配系统,实现按设备属性自动调用合适的布局文件。
  1. ViewPager 的布局参数是不支持边距设置的。(188页)

第12章 对话框

  1. 如果旋转设备,单独使用的 AlertDialog 会消失,而封装在 fragment 中的 AlertDialog 则不会有此问题(旋转后,对话框会被重建恢复)。(190页)
  2. Android 有 3 种可用于对话框的按钮:positive 按钮、negative 按钮以及 neutral 按钮。用户点击 positive 按钮接受对话框展现信息。如果同一对话框上放置有多个按钮,按钮的类型与命名决定着它们在对话框上显示的位置。(192页)
  3. 要将 DialogFragment 添加给 FragmentManager 管理并放置到屏幕上,可调用 fragment 实例的以下方法:(193页)
    public void show(FragmentManager manager,String tag) 或 public void show(FragmentTransaction transaction,String tag)。
    String 参数可唯一识别 FragmentManager 队列中的 DialogFragment。如果传入 FragmentTransaction 参数,自己负责创建并提交事务;如果传入 FragmentManager 参数,系统会自动创建并提交事务。
  4. 设备配置改变时,具有 ID 属性的视图可以保存运行状态。(196页)
  5. 创建和设置 fragment argument 通常是在 newInstance() 方法中完成的。(197页)
  6. 编写需要用户大量输入以及要求更多空间显示输入的应用,并且要让应用同时支持手机和平板设备时,使用 onActivityResult(…) 方法返回数据给目标 fragment 是比较方便的。(203页)

第13章 工具栏

  1. Android 5.0(Lollipop)引入了工具栏这个新增组件。在 Lollipop 之前,应用中用于导航或提供菜单操作的是操作栏。(207页)
  2. 要整合使用 AppCompat 库,需要:(208页)
  • 添加 AppCompat 依赖项;
  • 使用一种 AppCompat 主题;
  • 确保所有 activity 都是 AppCompatActivity 子类。
  1. AppCompat 库自带以下三种主题:(208页)
  • Theme.AppCompat:黑色主题
  • Theme.AppCompat.Light:浅色主题
  • Theme.AppCompat.Light.DarkActionBar:带黑色工具栏的浅色主题
  1. 应用级别的主题设置在 AndroidManifest.xml 文件中进行。主题也可按 activity 配置。(208页)
  2. AppTheme 定义在 res/values/styles.xml 文件中。(208页)
  3. 工具栏菜单由菜单项(又称操作项)组成,它占据着工具栏的右上方区域。菜单项的操作应用于当前屏幕,甚至整个应用。(209页)
  4. 菜单是一种类似于布局的资源。创建菜单定义文件并将其放置在 res/menu 目录下,Android 会自动生成相应的资源 ID。(210页)
  5. showAsAction 属性用于指定菜单项是显示在工具栏上,还是隐藏于溢出菜单(overflow menu)。(210页)
  6. 为了避免用户界面混乱,工具栏上只应放置常用菜单项。(211页)
  7. 应用使用的图标有两种:系统图标和项目资源图标。系统图标(system icon)是 Android 操作系统内置的图标。(211页)
  8. 需要选项菜单时,Android 会调用 Activity 的 onCreateOptionsMenu(Menu) 方法。(214页)
  9. onOptionsItemSelected(MenuItem) 方法返回的是布尔值。一旦完成菜单项事件处理,该方法应返回 true 值以表明任务已完成。默认 case 表达式中,如果菜单项 ID 不存在,超类版本方法会被调用。(218页)
  10. 后退键导航又称为临时性导航。只能返回到上一次浏览过的用户界面;而层级式导航(hierarchical navigation,有时又称为 ancestral navigation)可在应用内逐级向上导航。(218页)

第14章 SQLite 数据库

  1. Android 设备上的应用都有一个沙盒目录。将文件保存在沙盒中,可阻止其他应用甚至是设备用户的访问和窥探。(226页)
  2. 应用的沙盒目录是 /data/data/[应用的包名称]。(226页)
  3. 需要保存大量数据时,大多数应用都不会使用类似 txt 这样的普通文件。(226页)
  4. SQLite 是类似于 MySQL 和 PostgreSQL 的开源关系型数据库。SQLite 使用单个文件存储数据,读写数据时使用 SQLite 库。(226页)
  5. openOrCreateDatabase(…) 和 databaseList() 是 Android 提供的 Context 底层方法,用来打开数据库文件并将其转换为 SQLiteDatabase 实例。(227页)
  6. onCreate(SQLiteDatabase) 方法负责创建初始化数据库;onUpgrade(SQLiteDatabase,int,int) 方法负责与升级相关的工作。(229页)
  7. 直接从设备上删除应用是删除数据库文件最便捷的方法。(231页)
  8. 负责处理数据库写入和更新操作的辅助类是 ContentValues。它是一个键值存储类,只能用于处理 SQlite 数据。(233页)
  9. 读取数据需要用到 SQLiteDatabase.query(…) 方法。(235页)
  10. Cursor 是个神奇的表数据处理工具,其功能就是封装数据表中的原始字段值。(236页)
  11. 创建 Cursor 子类最简单的方式是使用 CursorWrapper。(237页)
  12. 别忘了调用 Cursor 的close() 方法关闭它,否则会出错:轻则应用报错,重则应用崩溃。(239页)
  13. 只要有 activity 在,Android 肯定也创建了 application 对象。用户在应用的不同界面间导航时,各个 activity 时而存在时而消亡,但 application 对象不会受任何影响。可以说,它的生命周期要比任何 activity 都长。(242页)

第15章 隐式 intent

  1. 在 Android 系统中,可利用隐式 intent 启动其他应用的 activity。在显式 intent 中,指定要启动的 activity 类,操作系统会负责启动它。在隐式 intent 中,只要描述要完成的任务,操作系统就会找到合适的应用,并在其中启动相应的 activity。(243页)
  2. 隐式 intent 的主要组成部分:要执行的操作(通常以 Intent 类中的常量来表示)、待访问数据的位置、操作涉及的数据类型、可选类别。(248页)
  3. 一个查看某个网址的简单隐式 intent 会包括一个 Intent.ACTION_VIEW 操作,以及某个具体 URL 网址的 Uri 数据。通过设置配置文件中的 intent 过滤器,activity 会对外宣称自己是适合处理 ACTION_VIEW 的 activity。(248页)
  4. action 元素告诉操作系统,activity 能够胜任指定任务。DEFAULT 类别告诉操作系统(问谁可以做时),activity 愿意处理某项任务。(249页)
  5. 有时可能看不到候选 activity 列表。出现这种情况通常有两个原因:要么是针对某个隐式 intent 设置了默认响应应用,要么是设备上仅有一个 activity 可以响应隐式 intent。(250页)
  6. 联系人应用有使用联系人数据库的全部权限。联系人应用返回包含在 intent 中的 URI 数据给父 activity 时,会添加一个 Intent.FLAG_GRANT_READ_URI_PERMISSION 标志。该标志告诉 Android,父 activity 可以使用联系人数据一次。(254页)
  7. Android 设备上安装了哪些组件以及包括哪些 activity,PackageManager 类全都知道。调用 resolveActivity(Intent,int) 方法,可以找到匹配给定 Intent 任务的 activity。(255页)
  8. 与打电话相关的 Intent 操作有两种:Intent.ACTION_DIAL 和 Intent.ACTION_CALL。ACTION_CALL 直接调出手机应用并拨打来自 intent 的电话号码;而 ACTION_DIAL 则拨好电话号码,然后等用户发起通话。(257页)

第16章 使用 intent 拍照

  1. Context 类提供的基本文件和目录处理方法如下:(260页)
    (1)File getFilesDir():获取 /data/data/<包名>/files 目录。
    (2)FileInputStream openFileInput(String name):打开现有文件进行读取。
    (3)FileOutputStream openFileOutput(String name,int mode):打开文件进行写入,如果不存在就创建它。
    (4)File getDir(String name,int mode):获取 /data/data/<包名>/目录的子目录(如果不存在就先创建它)。
    (5)String[] fileList():获取主文件目录下的文件列表。
    (6)File getCacheDir():获取 /data/data/<包名>/cache 目录。
  2. 如果想共享文件给其他应用,或是接收其他应用的文件,可以通过 ContentProvider 把要共享的文件暴露出来。ContentProvider 允许你暴露内容 URI 给其他应用。(261页)
  3. 把 FileProvider 和你指定的位置关联起来,就相当于你给发出请求的其他应用一个目标地。(261页)
  4. 相机 intent 定义在 MediaStore 里,这个类负责处理所有与多媒体相关的任务。发送一个带 MediaStore.ACTION_IMAGE_CAPTURE 操作的 intent,Android 会启动相机 activity 拍照。(263页)
  5. 要确认是否有可用的相机应用,可找 PackageManager 确认是否有响应相机隐式 intent 的 activity。(264页)
  6. 调用 FileProvider.getUriForFile(…) 会把本地文件路径转换为相机能看见的 Uri 形式。(265页)
  7. 加载照片到大小合适的 Bitmap 对象中,要从文件生成 Bitmap 对象,需要 BitmapFactory 类。(265页)
  8. Bitmap 是个简单对象,它只存储实际像素数据。即使原始照片已压缩过,但存入 Bitmap 对象时,文件并不会同样压缩。(266页)
  9. 手动缩放位图照片的具体做法:首先确认文件到底有多大,然后考虑按照给定区域大小合理缩放文件。最后,重新读取缩放后的文件,创建 Bitmap 对象。(266页)
  10. 为了声明应用要使用相机,在 AndroidManifest.xml 中加入 标签。(268页)
  11. 默认情况下,声明要使用某个设备功能后,应用就无法支持那些无此功能的设备了。(268页)

第17章 双版面主从用户界面

  1. 方法使用 @LayoutRes 注解,即告诉 Android Studio,任何时候,该实现方法都应该返回有效的布局资源 ID。(272页)
  2. 别名资源是一种指向其他资源的特殊资源,它存放在 res/values/ 目录下,并按照约定定义在 refs.xml 文件中。(274页)
  3. 别名的 type 属性决定资源 ID 属于什么内部类。即使别名资源自身在 res/values/ 目录中,它的资源 ID 依然属于 R.layout 内部类。(275页)
  4. Android 只提供一部分的资源适配机制。配置修饰符 -sw600dp 的作用是:如果设备尺寸大于某个指定值,就使用对应的资源文件。sw 是 smallest width(最小宽度)的缩写。虽然字面上是宽度的含义,但它实际指的是屏幕的最小尺寸(dimension),因而 sw 与设备的当前方向无关。(276页)
  5. 在确定可选资源时,-sw600dp 配置修饰符表明:对任何最小尺寸为 600dp 或更高 dp 的设备,都使用该资源。对于指定平板的屏幕尺寸规格来说,这是一种非常好的做法。(276页)
  6. 设备尺寸小于 -sw600dp 配置修饰符的指定值,就使用默认的资源文件。(276页)
  7. 为了让 fragment 独立,可以在 fragment 中定义回调接口,委托托管 activity 来完成那些不应由 fragment 处理的任务。(277页)
  8. 要委托工作任务给托管 activity,通常的做法是由 fragment 定义名为 Callbacks 的回调接口。回调接口定义了 fragment 委托给托管 activity 处理的工作任务。任何打算托管目标 fragment 的 activity 必须实现它。(277页)
  9. sw 指定了屏幕的最小规格尺寸。设备的方向会变,因此 sw 可以是最小宽度,也可以是最小高度。(285页)

第18章 应用本地化

  1. 本地化是一个基于设备语言设置,为应用提供合适资源的过程。(286页)
  2. 语言配置修饰符来自于 ISO 639-1 标准代码,每个修饰符都由两个字符组成。中文的修饰符为 -zh。(287页)
  3. 提供默认资源非常重要。没有配置修饰符的资源就是 Android 的默认资源。如果无法找到匹配当前配置的资源,Android 就会使用默认资源。默认资源至少能保证应用正常运行。(291页)
  4. 不要在 res/drawable/ 目录下放置默认的 drawable 资源。(291页)
  5. 在项目工具窗口,右键点击某个语言版本的 strings.xml,选择 Open Translations Editor 菜单项就可以打开资源翻译编辑器,这个便利工具能集中化查看资源翻译完成情况。(291页)
  6. 修饰资源目录也可以使用语言加区域修饰符,这样可以让资源使用更有针对性。(292页)
  7. 配置修饰符对大小写不敏感。但最好遵守 Android 命名约定:语言代码小写,区域代码大写,但前面加个小写的 r。(292页)
  8. 区域本身不能单独用作修饰符。(292页)
  9. 如果一个资源修饰符同时包含 locale 和区域,那么它有两次机会匹配用户的 locale。(292页)
  10. 资源应尽可能通用,最好是使用仅限语言的修饰目录,尽量少用区域修饰。(293页)
  11. 字符串备选资源都是基于每一个字符串提供,因此,字符串资源相同时,无需再复制一份。(296页)
  12. 可以在同一资源目录上使用多个配置修饰符。这需要各配置修饰符按照优先级别顺序排列。在新建资源文件对话框中,工具会自动配置正确的目录名。(296页)
  13. 如果有任何以 MCC 为修饰符的资源目录,那么所有不带 MCC 修饰符的都会被排除。(298页)
  14. DateFormat 类有个日期格式化工具,支持按 locale 做日期格式化。(298页)

第19章 Android 辅助功能

  1. TalkBack 是 Google 开发的 Android 屏幕阅读器。基于用户的操作,它能读出屏幕上的内容。TalkBack 实际是一个辅助服务,这个特别的部件能读取应用屏幕上的信息(无论哪种应用都可以)。(299页)
  2. 要使用 TalkBack,首先要有一台 Android 设备(虚拟设备不支持 TalkBack),确保手机没有静音。(299页)
  3. 要添加组件内容描述,可以在组件的布局 XML 文件里,添加 android:contentDescription 属性。(304页)
  4. 设置 android:focusable 属性值为 true 或使用 监听器都可以让组件可聚焦。(305页)
  5. 如果某个组件提供不了任何有意义的说明,应该把它的内容描述设置为 null。(305页)

第20章 数据绑定与 MVVM

  1. MVVM 架构很好地把控制器里的臃肿代码抽到布局文件里,让开发人员很容易看出哪些是动态界面。同时,它也抽出部分动态控制器代码放入 ViewModel 类,这大大方便了开发测试和验证。(314页)
  2. 大多数游戏使用 assets 加载大量图片和声音资源。(319页)
  3. 在实践中的任何场景下,所有 Context 中的 AssetManager 都管理着同一套 assets 资源。(322页)
  4. AssetManager.list(String) 方法能列出指定目录下的所有文件名。(322页)
  5. 责任单一性原则:每个类应该只负责一件事情。(326页)
  6. MVC 架构中的责任单一性原则:模型表示应用是如何工作的;控制器决定如何显示应用;视图显示你想看到的结果。(326页)
  7. 在 MVVM 架构中,控制器对象(activity 或 fragment)负责初始化布局绑定类和视图模型对象,同时也是它们之间的联系纽带。(327页)
  8. assets 可以看作随应用打包的微型文件系统,支持任意层次的文件目录结构。assets 常用来加载图片和声音资源。(334页)

第21章 音频播放与单元测试

  1. MVVM 架构极大方便了一项关键编程工作:单元测试。单元测试是指编写小程序去验证应用各个单元的独立行为。(335页)
  2. SoundPool 能加载一批声音资源到内存中,并能控制同时播放的音频文件的个数。(335页)
  3. Android 有很多不同的音频流,它们都有各自独立的音量控制选项。这就是调低音乐音量,闹钟音乐却不受影响的原因。STREAM_MUSIC 是音乐和游戏常用的音量控制常量。(336页)
  4. Mockito 是一个方便创建虚拟对象的 Java 框架。(338页)
  5. Hamcrest 是个规则匹配器工具库。匹配器可以方便地在代码里模拟匹配条件。如果不能按预期匹配条件定义,测试就通不过。(338页)
  6. testCompile 作用范围表示,依赖项只需包括在应用的测试编译里。这样就能避免在 APK 包里捎带上无用代码库。(339页)
  7. 写单元测试最方便的方式是使用测试框架。使用测试框架可以集中编写和运行测试案例,并支持在 Android Studio 中看到测试结果。(339页)

持续更新中…