00 分钟
Mar 30, 2023 11:03 AM

Platform Architecture(平台架构)

open source(开源)、Linux-based software stack(基于Linux的软件堆栈)、created for a wide of array of devices and form factors(为各种设备及其形状因素创建)

System Apps(系统应用程序)

  • email、SMS messaging、calendars、browser、contacts…
  • no special status(用户选择安装的应用程序中没有特殊状态)
  • third-party app can become the user’s default web browser、SMS messager or even the default keyboard(第三方app也可以成为用户的默认应用程序,如默认浏览器,短信,甚至是键盘)
  • system apps function both as apps for users and to provide key capabilities that developeds can access from their own app(系统应用程序既可以作为用户的应用程序,也提供开发者可以从自己应用程序中访问的关键功能)

Java API Framework(Java API 框架)

The entire feature-set of the Android OS is available to you through APIs written in the Java language. These APIs form the building blocks you need to create Android apps by simplifying the reuse of core, modular system components and services(可以通过Java语言编写的API,使用安卓系统的整个功能集,这些API通过简化核心、模块化系统组件和服务的重用,构成了创建安卓应用程序所需的模块)
  • a rich and extensible View System,build an app’s UI.lists,grids,text boxes,buttons,embeddable web browser(丰富可扩展的视图系统,可构建一个应用程序的UI,包括列表、网格、文本框、按钮、嵌入式web浏览器)
  • a Resource Manager,providing accdess to non-code resources such as localized strings,graphics and layout files(资源管理器,提供对非代码资源的访问,比如本地化的字符串、图形和布局文件)
  • a Notification Manager that enables all apps to display custom alerts in the status bar(通知管理器,允许所有应用程序在状态栏中显示自定义警报)
  • a Activity Manager manages the lifecycle of apps and provides a common navigation back stack(一个活动管理器,管理应用程序的生命周期,提供一个通用的导航后栈)
  • Content Providers,enable apps to access data from other apps(内容提供商,允许应用程序访问来自其他应用程序的数据)
Developers have full access to the same framwork APIs that Android System apps use(开发人员可以完全访问与安卓系统应用程序使用的相同的框架API)

Native C/C++ Libraries(本地C/C++库)

Many core Android system components and services, such as Android Runtime (ART) and Hardware Abstraction Layer (HAL), are built from native code that require native libraries written in C and C++.The Android platform provides Java framework APIs to expose the functionality of some of these native libraries to apps(许多核心系统Android组件和服务,如Android运行时(ART)和硬件抽象层(HAL),都是由需要用C和C++编写的原生代码构建的。Android平台提供了Java框架api,以向应用程序公开这些本机库的功能。)
eg:access OpenGL ES through the Android framework’s Java OpenGL API

Android Runtime—ART(Android运行时)

for devices running Android version 5.0(API level 21) or higher,each app runs in its own process and with its own instance of of the ART(对于运行Android5.0版本(API级别21)或更高版本的设备,每个应用程序都运行自己的进程,并使用自己的Android运行时(ART)实例)

Hardware Abstarction Layer—HAL(硬件抽象层)

privides standard interfaces that expose device hardware capabilities to the higher-level Java API framwork.HAL consists of multiple library modules ,each of which implements an interface for a specific type of hardware component(HAL提供了标准接口,将设备硬件功能公开给高级JavaAPI框架。HAL由多个库模块组成,每个库模块都为特定类型的硬件组件实现了一个接口)

Linux Kernel(Linux内核)

the foundation of the Android platform is the Linux kernel.ART relies on the Linux kernel for underlying functionalities(安卓平台的基础是Linux内核。ART依赖于Linux内核来实现底层功能)

Uses of API Level in Android(在Android中的API级别的使用)

The API Level identifier serves a key role in ensuring the best possible experience for users and application developers. Each Android platform version stores its API Level identifier internally, in the Android system itself. Applications can use API levels to describe the minimum or maximum Android platform versions under which they are able to run, as well as the preferred API Level that they are designed to support or compiled against.(API级别标识符在确保用户和应用程序开发人员的最佳体验方面起着关键作用。每个Android平台版本都将其API级别标识符存储在安卓系统本身中。应用程序可以使用API级别来描述它们能够运行的最小或最大的Android平台版本,以及它们被设计用来支持或编译的首选API级别)
  • minSdkVersion(最小的SDK版本).It specifies the minimun API Level on which the application is able to run(minSdkVersion指定了应用程序能够运行的最低API级别)
  • targetSdkVersion.It specifies the API Level on which the application is designed to run.(targetSdkVersion指定了应用程序被设计为要运行的API级别。如果平台的API Level高于你的应用程序中的targetSdkVersion属性指定的值,系统会开启兼容行为来确保你的应用程序继续你期望的形式来运行。如果平台的API Level低于你的应用程序中的targetSdkVersion属性指定的值时, 系统会开启兼容行为来确保你的应用程序能正常运行,这时一些在targetSdkVersion上的特性就没有了。)
  • compileSdkVersion(SDK编译版本).It specifies the Android API Level Gradle should use to compile the app.This means the app can use the API features included in this API level and lower.(compileSdkVersion指定了Gradle应该使用的Android API级别来编译该应用程序。这意味着该应用程序可以使用包含在这个API级别和更低级别中的API特性。修改 compileSdkVersion 不会改变运行时的行为)
  • maxSdkVersion.It specifies the applications the maximum API Level on which the application is able to run.(maxSdkVersion指定了应用程序能够在上面运行的最大API级别。在安装应用或系统升级时,系统会检查这个值。在这两种情况下,如果应用设置的maxSdkVersion 值低于系统本身使用的API Level,系统将不会允许安装该应用。在系统升级后,新系统会重新校验这个值,如果新系统的API Level高于这个值,新系统会删除你的应用)——已不推荐使用
minSdkVersion (lowest possible) <= targetSdkVersion == compileSdkVersion (latest SDK)
用较低的 minSdkVersion 来覆盖最大的人群,用最新的 SDK 设置 targetSdkVersion 和 compileVersion 来获得最好的外观和行为。

An Overview of Layouts(布局概述)

1.Views and ViewGroups(视图和视图组)

a layout defines the structure for a user interface in your app,All elements in the layout are built using a hierarchy of View and ViewGroup objects.(布局定义了应用程序中的用户界面的结构,布局中的所有元素都是使用视图和视图组对象的层次结构来构建的)
a View usually draws something the user can see and interact with.(一个视图通常会绘制一些用户可以看到并与之交互的东西)
a ViewGroup is an invisible contanier that defines the layout structure for View and other ViewGroup objects.(视图组是一个不可见的容器,它定义了视图和其他视图组对象的布局结构)
The View objects are usually called “widgets” and can be one of many subclasses, such as Button or TextView. The ViewGroup objects are usually called “layouts” can be one of many types that provide a different layout structure, such as LinearLayout or ConstraintLayout(视图对象通常被称为“小部件”,并且可以是许多子类中的一个,如按钮或文本视图。视图组对象通常被称为“布局”,它可以是提供不同布局结构的许多类型中的一种,例如线性布局约束布局)
declare a layout in two ways:(通过两种方式来声明一个布局)
  • Declare UI elements in XML(在XML中声明UI元素)
  • Instantiate layout elements at runtime(在运行时实例化布局元素,即通过编程方式创建视图和视图组对象并操作它们的属性)
Declaring your UI in XML allows you to separate the presentation of your app from the code that controls its behavior. Using XML files also makes it easy to provide different layouts for different screen sizes and orientations(在XML中声明UI可以让您将应用程序的表示与控制其行为的代码分开。使用XML文件还可以很容易地为不同的屏幕大小和方向提供不同的布局)
The Android framework gives you the flexibility to use either or both of these methods to build your app’s UI. For example, you can declare your app’s default layouts in XML, and then modify the layout at runtime(Android框架允许您灵活地使用这两种方法来构建应用程序的UI。例如,您可以用XML声明应用程序的默认布局,然后在运行时修改该布局)

2.Dimension Values(尺寸值)

A dimension value defined in XML. A dimension is a floating-point number specified with a number followed by a unit of measure(在XML中定义的维度值。维度是一个浮点数,后面用一个度量单位指定的数字)
  • px:Corresponds to actual pixels on the screen. (对应于屏幕上的实际像素.不建议使用这种度量单位,因为实际的表示可以是不同的设备)
  • dp:An abstract unit that is based on the physical density of the screen.making the view dimensions in your layout resize properly for different screen densities. In short, it provides consistency for the real-world sizes of your UI elements across different devices.(基于屏幕物理密度的抽象单元。可以使布局中的视图尺寸根据不同的屏幕密度适当地调整大小。简而言之,它为跨不同设备的UI元素的真实大小提供了一致性。)
  • sp:scaled pixels based on preferred font size, It is recommended you use this unit when specifying font sizes(基于首选字体大小的缩放像素,建议在指定字体大小时使用此单元)
  • in:based on the physical size of the screen(基于屏幕的物理尺寸)
  • mm:based on the physical size of the screen(基于屏幕的物理尺寸)
  • pt:Points - 1/72 of an inch based on the physical size of the screen.(点-1/72英寸,基于屏幕的物理大小)
  • 从dp单位到屏幕像素的转换很简单:px = dp * (dpi / 160)

3.String Resources(字符串资源)

The hardcoded string is not recommended during the development of an Android app. You should use @string resource.(在开发安卓应用程序时,不建议使用硬编码的字符串。您应该使用@string资源。)
A string resource provides text strings for your application with optional text styling and formatting. A single string that can be referenced from the application or from other resource files (such as an XML layout).(字符串资源为具有可选文本样式和格式的应用程序提供了文本字符串。可以从应用程序或其他(例如XML布局)中引入的单个字符串)


A layout that arranges other views either horizontally or vertically.set a value for android:orientation(一种水平或垂直排列其他视图的布局,设置一个值—android:orientation)
To control how linear layout aligns all the views it contains, set a value for android:gravity(要控制线性布局如何对齐它所包含的所有视图,设置一个值—android:gravity)
Some constant values of this attribute are “top”, “bottom”, “center”, “end”, “left”, “right” and “start”. And, must be one or more (separated by ‘|’) of its constant values.(该属性的一些常量值分别是“上”、“下”、“中”、“结束”、“左”、“右”和“开始”。并且,必须是其常量值中的一个或多个(用“|”分隔)。)


TextView is a user interface element that displays text to the user.(TextView是一个向用户显示文本的用户界面元素)
notion image
android:textText to display
android:textSizeSize of the text.Recommended dimension type for text is “sp”.Available units are: px, dp, sp, in, and mm .
android:textColorText color.May be a reference to another resource, in the form “@[+][package:]type/name” or a theme attribute in the form “?[package:]type/name”. May be a color value, in the form of “#rgb” (such as “#00FF7F” and “#FF4500”)
android:textStyleStyle for the text.Must be one or more (separated by ‘|’) of the following constant values: bold, italic, normal (such as normal, bold, italic and bold | italic).


A user interface element the user can tap or click to perform an action.The Button extends the TextView class(用户可以点击或单击来执行操作。Button类扩展了TextView类)
notion image

7.Layout Parameters(布局参数)

XML layout attributes named layout_something define layout parameters for the View that are appropriate for the ViewGroup in which it resides.(命名为layout_something的XML布局属性为视图定义适合于视图所在视图组的布局参数)
You can specify width and height with exact measurements,though you probably won’t want to do this often.More often,you will use ont of thehe constants to set the width or height:(可以用精确的测量来指定宽度和高度,通常情况下使用其中一个常量来设置宽度或高度)
  • warp_content tells your view to size itself to the dimensions required by its content.(warp_content告诉视图调整大小至其内容所需的尺寸)
  • match_parent tells your view to become as big as its parent view group will allow.(match_parent告诉视图调整大小至其父视图组所允许的最大值)
In general,specifying a layout width and height using absolute units such as pixels is not recommended.Instead,using relative measurements such as (dp),wrap_content or match_parent is a better approach,because it helps ensure that your app will display properly across a variety of device screen sizes.(通常不建议使用像素等绝对单位来指定布局的宽度和高度。相反,使用相对测量,如密度无关的像素单位(dp)、wrap_contentmatch_content是一个更好的方法,因为它有助于确保你的应用程序在各种设备屏幕大小上正确显示)

Introduction to Activities(活动介绍)

The Activity class is a crucial component of an Android app,and the way activities are launched and put together is a fundamental part of the platform’s application.Unlike programming paradigms in which apps are launched with a main() method,the Android system initiates code in an Activity instance by invoking specific callback methods that correspond to specific stages of its lifecycle.(活动类是安卓应用程序的关键组成部分,活动的启动和组合方式是该平台应用程序模型的基本组成部分。与使用main()方法启动应用程序的编程范式不同,安卓系统通过调用对应于其生命周期的特定阶段的特定回调方法来在活动实例中启动代码)

1.The concept of activities(活动的概念)

The mobile-app experience differs from its desktop counterpart in that a user’s interaction with the app doesn’t always begin in the same place.Instead,the user journey often begins non-deterministically.(移动应用程序的体验与桌面应用的不同在于,用户与应用程序的互动并不总是从同一个地方开始。相反,通常都是非确定性的)
The Activities class is designed to facilitate this paradigm.Most apps contain multiply screens,which means the comprise multiple activities.Typically,one activity in an app is specified as the main activity,which is the first screen to appear when the user launches the app.(活动类的设计目的是为了促进这种范例。大多数应用程序包含多个屏幕,这意味着它们包含多个活动。通常,一个应用程序中的一个活动被指定为主要活动,这是当用户启动该应用程序时出现的第一个屏幕)

2.Understand the Activity Lifecycle(了解活动的生命周期)

notion image
As a user nacigates through,out of,and back to your app,the Activity instances in your app transition through different states in their lifecycle.The activity class provides a number of callbacks that allow the activity to know that a state has changed(当用户导航、退出和返回你的应用程序时,应用程序中的活动实例将在其生命周期中的不同状态中进行转换。活动类提供了很多回调,允许活动知道状态已经改变)
To navigate transitions between stages of the activity lifecycle,the Activity class provides a set of callback methods:onCreate(Bundle),onStart(),onResume(),onPause(),onStop(),onRestart() and onDestroy().The system incokes each of these callbacks as an activity enters a new state.(要在活动生命周期的各个阶段之间导航转换,活动类提供了一组回调方法:onCreate(Bundle),onStart(),onResume(),onPause(),onStop(),onRestart() and onDestroy()。当活动进入新状态时,系统会调用这些回调)

2.1 Activity state and ejection from memory(活动状态和从内存中排出)

The system kills processes when it needs to free up RAM;the likelihood of the system killing a given process depends on the state of the process at the time.Process state,in turn,depends on the state of the activity running in the process.Table 1 shows the correlation among process state,activity state,and likelihood of the system’s killing the process.(当系统需要释放RAM时,系统会杀死进程。系统杀死给定进程的可能性取决于该进程当时的状态。进程状态又反过来取决于进程中运行的活动的状态。表1显示了进程状态、活动状态和系统杀死进程的可能性之间的相关性)
notion image
The system never kills an activity directly to free up memory.Instead,it kills the process in which the activity runs,destroying not only the activity but everything else running in the process,as well.(系统永远不会直接杀死一个活动来释放内存,相反,它杀死了活动运行的进程,不仅破坏了活动,还破坏了进程中进行的其他所有内容)

2.2 Three key loops(三个关键循环)

notion image
  • The entire lifetime of an activity happens between the first call to onCreate(Bundle) through to a single final call to onDestroy().An activity will do all setup of “global” state in onCreate(Bundle),and release all remaining resources in onDestroy().(活动的整个生命周期发生在第一次调用onCreate(Bundle)onDestroy()的最后调用之间。一个活动将在onCreate(Bundle)中设置所有“global”状态,并在onDestroy()中释放所有剩余的资源)
  • The visible lifetime of an activity happens between a call to onStart() until a corresponding cal to onStop().During this the user can see the activity on-screen,through it may not be in the foreground and interacting with the user.Between these two methods you can maintain resources that are needed to show the activity to the user.(活动的可见生命周期发生在对onStart()的调用到对onStop()的相应调用之间。在这段时间内,用户可以在屏幕上看到活动,尽管它可能不在前景中,并与用户交互。在这两种方法之间,你可以维护向用户显示活动所需的资源)
  • The foreground lifetime of an activity happens between a call to onResume() until a corresponding call to onPause().During this time the activity is visible,active and interacting with the user.An activity can frequently go between the resumed and paused states.(活动的前景生命周期发生‘在对onResume()的调用到对onPause()的相应调用之间。在此期间,活动是可见的、活动的,并与用户交互。一个活动经常可以在恢复状态和暂停状态之间进行)


An Intent is a messaging object you can use to request an action from another app component.Although intents facilitate communication between components in several ways,there are three fundamental use cases:Starting an activity,Starting a service and Delivering a broadcast.(Intent是一个消息传递对象,你可以用来从另一个应用程序组件请求操作。尽管Intent通过多种方式促进了组件之间的通信,但仍有三个基本的用例:启动活动、启动服务和交付广播)
An Activity represents a single screen in an app.You can start a new instance of an Activity by passing an Intent to startActivity().The Intent describes the activity to start and carries any necessary data.(一个活动表示一个应用程序中的单个屏幕。你可以通过将Intent传递到startActivity()来启动活动的新实例。Intent描述了启动活动并携带任何必要的数据)

1.Intent types(Intent类型)

  • Explicit intents specify which application will satisfy the intent,by supplying either the target app’s package name or a fully-qualified component class name.(Explicit intents通过提供目标应用程序的包名或一个完全限定的组件类名来指定哪个应用程序满足该Intent)
    • 例如,您可以在应用程序中启动一个新的活动,以响应用户的操作,或者启动一个服务,以在后台下载一个文件。
  • Implicit intents do not name a specific component,but instead declare a general action to perform,which allow a component from another app to handle it.(Implicit intents不命名特定的组件,而是声明要执行的通用操作,这允许来自另外一个应用程序的组件处理它)
When the Intent object names a specific activity component explicitly,the system immediately starts that component(当意图对象显式地命名特定地活动组件时,系统会立即启动该组件)
When you use an implicit intent,the Android system finds the appropriate component to start by comparing the contents of the intent to the intent filters declared in the manifest file of other apps on the device.If the intent matches an intent filter,the system starts that component and delivers it the Intent object.If multiple intent filters are compatible,the system displays a dialog so the user can pick which app to use.(当你使用隐式意图时,Android系统会通过将意图地内容与设备上其他应用程序地清单文件中声明的意图过滤器进行比较来找到适当地组件。如果意图与意图筛选器相匹配,则系统将启动该组件并将其交付给意图对象。如果多个意图过滤器兼容,系统将显示一个对话框,以便用户可以选择使用哪个应用程序)
notion image
More specifically,how an implicit intent is delivered through the system to start anther activity:(更具体地说,一个隐式的意图是如何通过系统传递来启动另一个活动的:)
  1. Activity A creates an Intent with an action description and passes it to startActivity().(Activity A创建一个带有动作描述的意图,并将其传递给startActivity())
  1. The Android System searches all apps for an intent filter that matches the intent.(安卓系统会搜索所有应用程序,寻找与意图相匹配的意图过滤器)
  1. When a match is found,the system starts the matching activity(Activity B) by invoking its onCreate() method and passing it the Intent.(当找到匹配项时,系统通过调用它的onCreate()方法并将其传递给意图来启动匹配的活动(Activity B))
An intent filter is an expression in an app’s manifest file that specifies the type of intents that the component would like to receive.For instance,by declaring an intent filter for an activity,you make it possible for other apps to directly start you activity with a certain kind of intent.Likewise,if you do not declare any intent filters for an activity,then it can be started only with an explicit intent.(意图筛选器是应用程序清单文件中的一个表达式,它指定了组件想要接收的意图的类型。例如,通过声明一个活动的意图过滤器,你可以让其他应用程序以某种意图直接启动你的活动。同样地,如果你没有为一个活动声明任何意图过滤器,那么就只能以明确的意图(即Explicit intents)启动它)

2.Building an intent(建立一个意图)

An Intent object carries information that the Android system uses to determine which component to start,plus information that the recipient component uses in order to properly perform the action.(意图对象携带Android系统用来确定要启动哪个组件的信息,以及接受方组件为正确执行操作而使用的信息)
The primary information contained in an Intent can be classified into two kinds:(意图中包含的主要信息有两种)
  • To define characteristics of an intent.By reading them,the Android system is able to resolve which app component it should start.such as ComponentName,Action,Data and Category(来定义一个意图的特征,安卓系统可以以此来解决它应该启动哪一个应用程序组件,例如组件名称,操作,数据和类别)
  • To carry additional information that does not affect how the Android system is resolved to an app component.such as Extras and Flags.(携带不影响安卓系统如何解析到应用程序组件的附加信息,例如额外的东西和旗帜)
“Action”,“Data”,“Category” are commonly used to build implicit intents.(“动作”、“数据”和“类别”通常用来构建隐式意图)
If there’s only one app that can handle the implicit intent,that app opens immediately and is given the intent.If multiple activities accept the intent,the system displays a dialog,so the user can pick which app to use and make that app the default choice for the action.(如果只有一个应用程序可以处理隐式意图,该应用程序会立即打开并给到意图。如果多个活动接收该意图,系统会显示一个对话框,以便用户可以使用选择哪个应用程序,并使该应用程序成为该操作的默认选择)

2.1 Action(操作)

Action is a string that specifies the generic action to perform.The action largely detemines how the rest of the intent is structured—particularly the information that is contained in the data and extras.(操作是一个指定要执行的通用操作的字符串。操作很大程度上决定了其意图的结构—特别是数据和额外内容中包含的信息)
    • Use this action in an intent with startActivity() when you have some information that an activity can show to the user(当你有一些活动可以向用户显示的信息,请在startActivity()中使用此操作)
    • Also known as the share intent,you can use this in an intent with startActivity() when you have some data that the user can share through another app(也被称为分享意图,当你有一些数据,用户可以通过其他应用来分享时,请在startActivity()中使用此操作)
    • This action dials a number as specified by the data.This shows a UI with the number being dialed,allowing the user to explicitly initiate the call.(此操作拨号由数据指定的数字。这显示了一个包含所拨号码的UI,允许用户显式地发起呼叫)
    • This action indicates an activity as the main entry point of an app.It does not expect to receive data.(此操作表示一个活动作为应用程序的主要入口点,它并不期望接收到数据)
notion image

Understand Tasks and Back Stack(理解任务和后台堆栈)

A task is a collection of activities that users interact with when performing a certain job.(任务是用户在执行某个作业时所交互的活动的集合)

1.An Overview of how Back Stack works(关于后台堆栈是如何工作的概述)

The activities are arranged in a stack—the Back Stack—in the order in which each activity is opened.For example,an email app might have one activity to show a list of new messages.When the user selects a message,a new activity opens to view that message.This new activity is added to the Back Stack.If the user presses the Back button,that new acvitivy is finished and popped off the stack.(活动按照每个活动打开的顺序排列在一个栈—后堆栈中。例如,一个电子邮件应用程序可能有一个活动来显示一个新消息的列表。当用户选择一个消息时,将打开一个新的活动以查看该消息,此新的活动将被添加到后堆栈中。如果用户按“后退”按钮,新活动完成并从堆栈中弹出。如下图所示)
notion image
The device Home screen is the starting place for most tasks.When the user touches an icon in the app launcher,that app’s task comes to the foreground.If no task exists for the app,then a new task is created and the “main” activity for that app opens as the root activity in the stack.(设备主屏幕时大多数任务的起点。当用户触摸到应用程序启动器中的一个图标时,该应用程序的任务就会进入前台。如果应用程序不存在任务,则创建一个新任务,该应用程序的“主”活动作为堆栈中的根活动打开)
Activities in the stack are never rearranged,only pushed and popped from the stack—pushed onto the stack when started by the current activity and popped off when the user leaves it using the Back button.As such,the Back Stack operates as a “last in,first out” object structure.(堆栈中的活动永远不会重新排列,只会从堆栈中推入和弹出—当当前活动启动时推送到堆栈上,当用户使用“后退”按钮时弹出。因此,后堆栈作为“后入先出”的对象结构操作)
notion image
A task is a cohesive unit that can move to the “background” when users begin a new task or go to the Home screen,via the Home button.While in the background,all the activities in the task are stopped,but the Back Stack for the task remains intact—the task has simply lost focus while another task takes place.(任务是一个有凝聚力的单元,当用户开始执行新任务或通过“主页”按钮进入主屏幕时,它可以移动到“后台”。在后台,任务中的所有活动都停止了,但任务的后堆栈保持完整—当另一个任务发生时,当任务只是失去了焦点)
notion image

2.Managing Tasks(管理任务)

2.1 Defining launch modes(定义启动模式)

Launch modes allows you to define how a new instance of an activity is associated with the current task.You can define different launch modes in two ways:Using the manifest file(when you declare an activity in your manifest file) and Using Intent flags(when you call startActivity(),you can include a flag in the Intent)(启动模式允许你定义活动的新实例如何与当前任务相关联。你可以通过两种方式定义不同的启动模式:使用清单文件(当你在清单文件中声明一个活动时)和使用意图表示(当你调用startActivity()时,你可以在意图中包含一个标志))

2.1.1 Using the manifest file(使用清单文件)

When declaring an activity in your manifest file,you can specify how the activity should associate with a task using the <activity> element’s launchMode attribute.The launchMode attribute specifies an instruction on how the activity should be launched into a task.There are four different launch modes you can assign to the launchMode attribute:“standard”,“singleTop”,“singleTask”,“singleInstance
  • “standard”(the default mode)(标准模式,默认模式)
    • The system creates a new instance of the activity in the task from which it was started and routes the intent to it.The activity can be instantiated multiple times,each instance can belong to different tasks,and one task can have multiple instances.(系统在任务中创建一个活动的新实例,并将意图路由到它。活动可以多次实例化,每个实例属于不同的任务)
      notion image
  • singleTop(栈顶复用模式)
    • If an instance of the activity already exists at the top of the current task,the system routes the intent to that instance through a call to its onNewIntent() method,rather than creating a new instance of the activity.(如果该活动的实例已经存在于当前任务的顶部,那么系统将通过调用其onNewIntent()方法,将该意图路由到该实例)
      notion image
  • singleTask(栈内复用模式)
    • If an instance of the activity doesn’t exist,the system creates a new task and instantiates the activity at the root of the new task.(如果该活动的实例不存在,则系统将创建一个新任务,并在新任务的根处实例化该活动)
      However,if an instance of the activity already exists in a separate task,the system routes the intent to the existing instance through a call to its onNewIntent() method,rather than creating a new instance.Only one instance of the activity can exist at a time.(但是,如果活动的实例以及那个存在于单独的任务中,系统通过调用其onNewIntent()方法将意图路由到现有实例,而不是创建一个新实例。依次只能存在一个活动)
      notion image
  • singleInstance(单实例模式)
    • Same as “sinigleTask”,except that the system doesn’t launch any other activities into the task holding the instance.The activity is always the single and only member of its task;any activities started by this one open in a separate task.(与“singleTask”相同,只是系统不会向持有该实例的任务中启动任何其他活动。该活动总是其任务的唯一成员;由此活动启动的任何活动都会在单独的任务中打开)


A dialog is a small window that prompts the user to make a decision or enter additional information.A dialog does not fill the screen and is normally used for the events that require users to take an action before they can proceed.(对话框是一个小窗口,它会提示用户做出决定或输入其他信息。对话框不会填充屏幕,通常用于需要用户在继续操作之前采取操作的事件)
The Dialog class is the base class for dialogs,but you should avoid instantiating Dialog directly.Instead,use one of the following subclasses:(对话框类是对话框的基类,但你应该避免直接实例化对话框,相反,请使用以下子类)
  • AlertDialog:
    • A dialog that can show a title
    • up to three buttons
    • a message,a list of selectable items,or a custom layout
  • DatePickerDialog:
    • A dialog with a pre-defined UI that allows the user to select a date
  • TimePickerDialog:
    • A dialog with a pre-defined UI that allows the user to select a date

1.Build an Alert Dialog(生成对话框)

notion image
Figure 9
The AlertDialog class allows you to build a variety of dialog designs and is often the only dialog class you’ll need.As shown in Figure 9,there are three regions of an alert dialog:(AlertDialog类允许你构建各种对话框设计,并且通常是你唯一需要的对话框类,如图9所示,一个警报对话框有三个区域:)
​ ① Title.This is optional and should be used only when the content area is occupied by a detailed message,a list,or custom layout.If you need to state a simple message or question,you don’t need a title.(标题。这是可选的,仅在内容区域被详细消息、列表或自定义布局占据时使用。如果你需要陈述一个简单的信息或问题,你就不需要一个标题)
​ ② Content area.This can display a message,a list,or other custom layout.(内容区域。这可以显示消息、列表或其他自定义布局)
​ ③ Action buttons.There should be no more than three action buttons in a dialog.(操作按钮。在一个对话框内不应超过三个操作按钮)
The AlertDialog.Builder class provides APIs that allow you to create an AlertDialog with these kinds of content.(AlertDialog.Builder类提供了API,允许你创建这些类型的AlertDialog)

To build an AlertDialog:(构建对话框)

The following topics show how to define various dialog attributes using the AlertDialog.Builder class.(以下的部分展示了如何使用AlertDialog.Builder类来定义各种对话框属性)

Add buttons(添加按钮)

To add action buttons like these codes.
The set…Button() methods require a title for the button and a DialogInterface.OnClickListener that defines the action to take when the user presses the button.(set…Button()方法需要一个按钮的标题和一个监听器DialogInterface.OnClickListener定义用户按下按钮时要采取的操作)
There are three different action buttons you can add:
  • Positive.You can use this to accept and continue with the action(the “OK” action)(肯定。你可以使用它来接受并继续执行该操作)
  • Negative.You can use this to cancel the action(否定。你可以使用此操作来取消该操作)
  • Neutral.You can use this when the user may not want to proceed with the action,but doesn’t necessarily want to cancel.For example,the action might be “Remind me later”(中立。当用户可能不希望继续执行操作,但不一定想要取消时,可以使用此操作,类似”稍后提醒我“的动作)
You can add only one of each button type to an AlertDialog.That is,you cannot have more than one “positive” button(你只能将每种按钮类型中的一种添加到警报对话框中。也就是说,你不能有一个以上的“positive”按钮)

Add a list(添加列表)

There are three kinds of lists avaiable with the AlertDialog APIs:
  • A traditional single-choice list(一种传统的单项选择列表)
  • A persistent single-choice list(radio buttons)(一种持久的单项选择列表(单选按钮))
  • A persistent multiple-choice list(checkboxes)(一种持久的多项选择列表(复选框))

Drawable Resources(可绘制资源)

ImageView can be user to display drawable resources.The example in Figure 15 is a common example of using an ImageView to sdisplay an image resource.(ImageView可用于显示可提取的资源。图15的示例是使用ImageView来显示图像资源的一个常见示例)
notion image
Figure 15
android:srcSets a drawable as the content of this ImageView.(设置一个可绘制资源为ImageView的内容)
android:contentDescriptionDefines text that briefly describes content of the view.(定义了简要描述视图内容的文本)

1.Drawable Overview(概述)

A drawable resource is a general concept for a graphic that can be drawn to the screen and which you can retrieve with APIs such as getDrawable(int) or apply to another XML resource with attributes such as android:drawable and android:icon.There are several different types of drawables,for example Bitmap File(可绘制资源是图形的一般概念,你可以使用getDrawable(int)等API检索图形,或者使用android:drawableandroid:icon等XML资源的属性。有几种不同类型的可绘制对象,例如位图文件即(Bitmap File))
Bitmap File
Android supports bitmap fiiles in three formats:.png(preferred),.jpg(acceptable),.gif(discouraged).You can reference a bitmap directly,using the filename as the resource ID.(Android支持三种格式的Bitmap File:.png(首选)、.jpg(可接受)、.gif(不鼓励)。你可以使用文件名作为资源ID,直接引用位图文件)
Android creates a Drawable resource for any of these files when you save them in the res/drawable/ directory.(当你将这些文件保存在res/drawable目录中时,Android将为这些文件创建可绘制资源)
  • File location:
    • res/drawable/filename.png(.png,.jpg or .gif) The filename is used as the resource ID
  • Resource reference:
    • In Java:R.drawable.filename
      • In XML:@[package:]drawable/filename
        • android:src=“@drawable/image01”

    Permission Overview(权限概述)

    The purpose of a permission is to protect rhe privacy of an Android user.Android apps must request permission to access sensitive user data.Depending on the feature,the system might grant the permission automatically or might prompt the user to approve the request.(权限的目的时为了保护安卓用户的隐私。安卓应用程序必须申请权限才能访问敏感的用户数据。根据功能的不同,系统可能会自动授予该权限,或者提示用户批准该请求)

    1.Permission approval(权限批准)

    An app must publicize the permissions it requires by including <user-permission> tags in the app manifest.This tag specifies a system permission that the user must grant in order for the app to operate correctly.For example,an app that needs to send SMS messages would have this line in the manifest.(应用程序必须通过在应用程序清单中包含<user-permission>标签来公开它所需的权限,此标记指定用户必须授予的系统权限,以确保应用程序的正确运行。例如,一个需要发送短信的应用程序在清单中会有如下这一行)
    If your app lists normal permissions in its manifest,the system automantically grants those permissions to your app.If your app lists dangerous permission in its manifest,such as the SEND_SMS permission above,the user must explicitly agree to grant those permission.(如果你的应用程序在其清单中列出了正常权限,系统会自动将这些权限授予你的应用程序。如果你的应用程序在其清单中列出了危险的权限,例如上面的SEND_SMS权限,用户必须明确同意授予这些权限)

    2.Protection levels(保护级别)

    Permissions are divided into several protection levels.The protection level affects wherher runtim permission requests are required.This section introduces two important protection levels.(权限可分为几个保护级别,保护级别会影响是否需要执行运行时权限请求。本节介绍了两个重要的保护级别)
    • Normal permissions.They cover areas where your app needs to access data or resources outside the app’s sandbox,but where there’s very little risk to the user’s privacy or operation of other apps.Foe example.permission to set the time zone is a normal permission.(Normal permission.正常权限覆盖了你的应用程序需要访问应用程序沙箱之外的数据或资源的区域,但对用户的隐私或其他应用程序的操作风险很小的区域。例如,设置时区的权限是一个正常的权限)
      • If an app declare in its manifest that it needs a normal permission:(如果一个应用程序在清单中声明它需要一个正常的权限)
      • The system automatically grants the app that permission.(系统会自动授予该应用程序该权限)
      • The system doesn’t prompt the user to grant normal permission.(系统不会提示用户授予正常权限)
      • Users cannot revoke these permission.(用户不饿能撤销这些权限)
    • Dangerous permissions.Dangerous permissions cover areas where the app wants data or resources that involve the user’s private information,or could potentially affect the user’s stored data or the operation of other apps.For example,the ability to read the user’s contacts is a dangerous permission.(Dangerous permissions.危险权限包括应用程序需要涉及用户私人信息的数据或资源的区域,或可能影响用户存储的数据或其他应用程序的操作。例如,读取用户联系人的能力就是一种危险的权限)
      • If an app declares that it needs a dangerous permission:(如果一个应用程序在清单中声明它需要一个危险的权限)
      • The user has to explicitly grant the permission to the app.(用户必须明确地授予应用程序该权限)
      • Until the user approves,your app cannot provide functionality that depends on that permission.(在用户批准该权限之前,你的应用程序不能提供依赖于该权限的功能)
      • To use a dangerous permission,your app must prompt the user to grant permission.(要使用危险的权限,你的应用程序必须提示用户授予权限)

    3.Request prompts for dangerous permissions(请求危险权限)

    Only dangerous permissions require user agreement.The way Android asks the user to grant dangerous permissions depends on the version of Android running on the user’s device,and the system version targeted by your app.(只有危险的权限才需要用户同意。安卓系统要求用户授予危险权限的方式取决于在用户的设备上运行的安卓系统的版本,以及你的应用程序所针对的系统版本)

    Runtime requests(Android 6.0 and higher)(运行时请求)

    If the device is running Android 6.0(API level 23) or higher,and the app’s targetSdkVersion is 23 or higher,the user isn’t notified of any app permissions at install time.When your app requests permission,the user sees a system dialog(as shown in Figure 1) telling the user which permission group your app is trying to access.The dialog includes a Deny and Allow button.(如果设备运行的是Android 6.0(API级别23)或更高,并且应用程序的targetSdkVersion是23或更高,用户在安装时不会被通知任何应用程序权限。当你的应用程序请求权限时,用户会看到一个系统对话框(如图1所示),告诉用户你的应用程序正视图访问哪个权限组,该对话框包括一个”拒绝“和”允许“按钮)
    If the user denies the permission request,the next time your app requests the permission,the dialog contains a checkbox that,when checked,indicates the user doesn’t want to be prompted for the permission again(as shown in Figure 2)(如果用户拒绝请求,下次应用程序请求权限时,对话框包括一个复选框,选中时该复选框表示用户不希望再次被提示获得权限(如图2所示))
    You should always check for and request permissions at runtime to guard against runtime errors(SecurityException)(你应该始终在运行时检查并请求权限,以防止运行时出现错误(安全异常))
    notion image
    Figure 1 Figure 2

    Install-time requests(Android 5.1.1 and below)(安装时请求)

    If the device is running Android 5.1.1(API level 22) or lower,or the app’s targetSdkVersion is 22 or lower while running on any version of Android,the system automatically asks the user to grant all dangerous permissions for your app at install-time(see Figure 3)(如果设备运行的是Android5.1.1(API级别22)或更低,或者应用程序的targetSdkVersion为22或更低,系统会自动要求用户在安装时为你的应用程序授予所有危险权限)
    If the user clicks Accept,all permissions the app requests are granted.If the user denies the permissions request,the system cancels the installation of the app.(如果用户单击”接受“,则将授予应用程序其请求的所有程序。如果用户拒绝了权限请求,则系统将取消该应用程序的安装)
    notion image
    Figure 3

    Tenets of working with Android permissions(使用安卓系统权限的工作原则)

    Google recommends following these tenets when working with Android permissions:(谷歌建议在使用安卓权限时遵循以下原则:)
    • Only use the permissions necessary for your app to work without relying on access to sensitive information.(只使用应用程序工作所需的权限,而不依赖于对敏感信息的访问)
    • Pay attention to permissions required by libraries.(请注意库所需的权限)
    • Be transparent.When you make a permissions request,be clear about what you’re accessing,and why,so users can make informed decisions.Make this information available alongside the permission request including install,runtime,or update permission dialogues.(透明。当你提出权限请求时,请清楚你正在访问的内容和原因,以便用户可以做出明智的决定。将这些信息与权限请求一起可用,包括安装、运行时或更新权限对话框)
    • Make system accesses explicit.Providing continuous indications when you access sensitive capabilities(使系统访问显式。当访问敏感功能时,提供连续的指示)

    Toasts Overview(吐司(提示)概览)

    A toast provides simple feedback about an operation in a small popup.It only fills the amount of space required for the message and the current activity remains visible and interactive.Toasts automatically disappear after a timeout.For example,as can be seen from Figure 7,clicking Send on an email triggers a “Sending message…” toast,as shown in the following screen capture.(吐司在一个小弹出窗口中提供关于操作的简单反馈。它只填充消息所需的空间,当前活动保持可见和交互。吐司会在超时后自动消失。例如,从图7中可以看到,单击电子邮件上的发送将除法一个”Sending message…“吐司,如下屏幕截图所示)
    notion image
    Figure 7

    1.The Basics(基础知识)

    First,instantiate a Toast object with one of the makeText() methods.This method takes three parameters:(首先,使用makeText()方法之一实例化一个Toast对象,该方法采用以下三个参数:)
    • The application Context
    • The text message
    • The duration for the toast
      • It returns a properly initialized Toast object.You can display the toast notification with show(),as shown in the following example:(它返回一个正确初始化的Toast对象,你可以使用show()显示吐司通知)
        notion image
        example toast

    2.Positioning your Toast(定位你的吐司)

    A standard toast notification appears near the bottom of the screen,centered horizontally.You can change this position with the setGravity(int,int,int) method.This accepts three parameters:(一个标准的吐司通知出现在屏幕底部附近,水平居中,你可以使用setGravity(int,int,int)方法更改此位置,这个方法接收以下三个参数:)
    • a Gravity constant
    • an x-position offset
    • a y-position offset
      • For example,if you decide that the toast should appear in the bottom-left cornet,you can set the gravity like this(例如,如果你决定吐司应该出现在左下角,则可以这样设置)
        notion image


    Android apps can send or receive broadcast messages from the Android system and other Android apps,similar to the publish-subscribe design pattern.For example,the Android system sends broadcasts when various system events occur,such as when the system boots up or the device starts charging.Apps can also send custom broadcasts,for example,to notify other apps of something that they might be interested in (for example,some new data has been downloaded)(安卓应用程序可以发送或接收来自安卓系统和其他安卓应用程序的广播信息,类似于发布-订阅的设计模式。例如,当各种系统事件发生时,安卓系统会发送广播,例如当系统启动或设备开始充电时。应用程序还可以发送自定义广播,例如,通知其他应用程序它们可能感兴趣的东西,(例如,一些新数据已经下载))
    Apps can register to receive specific broadcasts.When a broadcast is sent,the system automatically routes broadcasts to apps that have subscribed to receive that particular type of broadcast.(应用程序可以注册以接收特定的广播,当发送广播时,系统会自动将广播路由到已订阅以接收该特定类型广播的应用程序)

    1.About system broadcasts(关于系统广播)

    The system automatically sends broadcasts when various system events occur.System broadcasts are sent to all apps that are subscribed to receive the event.(当各种系统事件发生时,系统自动发送广播。系统广播被发送到所有已订阅以接收该事件的应用程序)
    The broadcast message itself is wrapped in an Intent object whose action string identifies the event that occurred(广播消息本身被包装在一个意图对象中,该对象的操作字符串标识所发生的事件)

    2.Receiving broadcasts(接收广播)

    Apps can receive broadcasts in two ways:through manifest-declared receivers and context-registered receivers.(应用程序可以通过两种方式接收广播:通过manifest-declared receivers(清单声明的接收器)和context-registered receivers(上下文注册的接收器))
    1. Manifest-declared receivers(清单声明的接收器)
      1. If you declare a broadcast receiver in your manifest,the system launches your app(if the app is not already running) when the broadcast is sent.(如果你在清单中声明了一个广播接收器,系统将在广播发送时启动你的应用程序(如果应用程序还没运行))
        Note:If your app targets Android 8 (API level 26) or higher,you cannot use the manifest to declare a receiver for implicit broadcasts(broadcasts that do not target your app specifically),except for a few implicit broadcasts that are exempted from that restricition.(如果你的应用程序的目标是Android8(API级别26)或更高,你不能使用清单声明隐式广播(不专门针对你的应用程序的广播),除了一些不受该限制的隐式广播)
    1. Context-registered receivers(上下文注册的接收器)
      1. To register a receiver with a context,preform the following steps:(若要在上下文中注册接收器,请执行以下步骤:)
        Step 1.Create an instance of BroadcastReceiver.(创建一个广播接收器的实例)
        Step 2.Create an IntentFilter and register the receiver by calling registerReceiver(BroadcastReceiver,IntentFilter):(创建目标过滤器,并通过调用registerReceiver(BroadcastReceiver,IntentFilter)来注册接收器)
        To register for local broadcasts,call LocalBroadcastManager.registerReceiver(BroadcastReceiver,IntentFilter) instead.Context-register receivers receive broadcasts as long as the activity is not destroyed.If you register with the Application context,you receive broadcasts as long as the app is running.(要注册本地广播,请调用LocalBroadcastManager.registerReceiver(BroadcastReceiver,IntentFilter)。只要他们的注册上下文是有效的,上下文注册的接收器就可以接收广播。例如,如果你在活动上下文中注册,那么只要活动没有被销毁,你就能接收广播。如果你在应用程序上下文注册,那么只要应用程序正在运行,你就能接收广播)
        Step 3.To stop receiving broadcasts,call unregisterReceiver(android.content.BroadcastReceiver). Be sure to unregister the receiver when you no longer need it or the context is no longer valid.(要停止接收广播,请调用unregisterReceiver(android.content.BroadcastReceiver)。当你不再需要接收器或上下文不再有效时,请确保取消注册它)
        Be mindful of where you register and unregister the receiver.for example:(要注意你在哪里注册和注销接收器,例如:)
        • If you register a receiver in onCreate(Bundle) using the activity’s context,you should unregister it in onDestroy() to prevent leaking the receiver out of the activity context.(如果你使用活动的上下文在onCreate(Bundle)中注册了一个接收器,则应该在onDestroy()中注销它,以防止将接收器从活动上下文泄露出来)
        • If you register a receiver in onResume(),you should unregister it in onPause() to prevent registering it multiple times(If you don’t want to receive broadcasts when paused,and this can cut down on unnecessary system overhead)(如果你在onResume()中注册接收器,你应该在onPause()中注销它,以防止多次注册(如果你不想在暂停时接收广播,这可以减少不必要的系统开销))
        • Do not unregister in onSaveInstanceState(Bundle),because this isn’t called if the user moves back in the history stack.(不要在onSaveInstanceState(Bundle)中注销,因为如果用户移动回到历史记录堆栈中,则不会调用此操作)

    3.Sending broadcasts(发送广播)

    Android provides three ways for apps to send broadcasts:
    • Ordered Broadcast:The sendOrderedBroadcast(Intent,String) method sends broadcasts to one receiver at a time.As each receiver executes in turn,it can propagate a result to the next receiver,or it can completely abort the broadcast so that it won’t be passed to other receivers.The order receivers run in can be controlled with the android:priority attribute of the matching intent-filter;receivers with the same priority will be run in an arbitray order.(有序广播:sendOrderedBroadcast(Intent,String)方法依次向一个接收器发送广播。当每个接收器依次执行时,它可以将一个结果传播到下一个接收器,或者它可以完全中止广播,使它不会被传递给其他接收器。运行的顺序接收器可以通过匹配意图的过滤器android:priority属性进行控制;具有相同优先级的接收器将以任意顺序运行)
    • Normal Broadcast:The sendBroadcast(Intent) method sends broadcasts to all receivers in an underfined order.This is called a Normal Broadcast.This is more efficient,but means that receivers cannot read result from other receivers,propagate data received from rhe broadcast,or abort the broadcast.(标准广播:sendBroadcast(Intent)方法以未定义的顺序向所有接收器发送广播,这叫标准广播。这更有效,但这意味着接收器不能从其他接收器读取结果,不能传播从广播接收到的数据或不能中止广播)
    • Local Broadcast:The LocalBroadcastManager.sendBroadcast method sends broadcasts to receivers that are in the same app as the sender.If you don’t need to send broadcasts across apps,use local broadcasts.The implementation is much more efficient(no interproocess communication needed) and you don’t need to worry about any security issues related to other apps being able to receive or send your broadcasts.(本地广播:LocalBroadcastManager.sendBroadcast方法向与发送器在同一应用程序中的接收器发送广播,如果你不需要跨应用程序发送广播,请使用本地广播。该实现效率更高(不需要进程间通信),而且你不需要担心与其他应用程序能够接收或发送广播相关的任何安全问题)

    Create a List with RecyclerView(使用RecycleView创建一个列表)

    If your app needs to display a scrolling list of elements based on large data sets(or data that frequently changes),you can use RecyclerView.(如果你的应用程序需要显示一个基于大数据集(或经常变化的数据)的滚动元素列表,你可以使用RecyclerView)

    1.RecyclerView Overview(RecyclerView概述)

    The RecyclerView widget is a more advanced and flexible version of ListView(RecycleView组件是一个更高级和灵活的版本的ListView组件)
    In the RecyclerView model,several different components work together to display your data.The RecyclerView FILLS itself with views provided by a layout manager that you provide.You can use one of the standard layout managers(such as LinearLayoutManager or GridLayoutManager),or implement your own.(在RecyclerView模型中,几个不同的组件一起显示数据。RecycleView填充了你提供的布局管理器提供的视图。你可以使用其中一个标准的布局管理器(如LinearLayoutManager(线性布局管理器)或GridLayoutManager(网格布局管理器))或实现你自己的布局管理器)
    The views in the list are represented by view holder objects.These objects are instances of a class you defined by extending RecyclerView.ViewHolder.Each view holder is in charge of displaying a single item with a view.As the user scrolls through the list,the RecyclerView takes the off-screen views and rebinds them to the data which is scrolling onto the screen.(列表中的视图由view holder对象表示。这些对象是你通过继承RecyclerView.ViewHolder来定义的类的实例。每个view holder负责用一个视图显示单个项目。当用户滚动浏览该列表时,RecyclerView会获取屏幕外的视图,并将它们重新绑定到正在滚动到屏幕上的数据中)

    2.Change,insert,remove and move items(更改,插入,删除和移动项目)

    There are two different classes of data change events,item changes and structural changes:(有两种不同类型的数据更改事件,项目更改和结构更改)
    • Item changes are when a single item has its data changed but no positional changes have occurred.(项目更改指的是单个项目更改了其数据,但没有发生位置更改)
    • Structural changes are when items are inserted,removed or moved within the data set.(结构性更改是指在数据集中插入、删除或移动项目)
      • You can notify any registered observers that the items has changed in the recyclerview(e.g. when the recyclerview needs an update),by calling the methods like notifyItemChanged(),notifyItemInserted(),notifyItemRemoved(),notifyItemMoved(),and notifyDataSetChanged())(当recyclerview发生改变时,你可以通过调用方法来更新其中的项目(当recyclerview需要更新时,调用方法notifyItemChanged(),notifyItemInserted(),notifyItemRemoved(),notifyItemMoved(),和 notifyDataSetChanged()))
        1. To change an item in the recyclerview(对于更改)
          1. notifyItemChanged(int position):Notify any registered observers that the item at position has changed.(通知视图该位置的项目已发生更改)
            notion image
            Figure 4
        1. To insert an item into the recyclerview(对于插入)
          1. notifyItemInserted(int position):Notify any registered observers that the item reflected at position has been newly inserted.(通知视图该位置已新插入项目)
            notion image
            Figure 6
        1. To remove an item from the recyclerview(对于删除)
          1. notifyItemRemoved(int position):Notify any registered observers that the item previously located at position has been removed from the data set.(通知视图先前位于该位置的项目已经从数据集中删除)
            notion image
            Figure 8
            The item previously located at and after position may now be found at oldPosition-1(以前位于该位置之后的项目现在在旧位置-1的位置)
            This is a structural change event.Representations of other existing items in the data set anr still considered up to date and will not be rebound,though their positions may be altered.(这是一个结构性变化的事件。数据集中其他现有项目的表示仍然被认为是最新的,并且不会反弹,尽管它们的位置已经改变)
        1. To move an item from one position to another(对于移动)
          1. notifyItemMoved(int fromPosition,int toPosition):Notify any registered observers that the item reflected at fromPosition has been moved to toPosition.(通知视图fromPosition的项目已移动到toPosition)
            This is a structural change event.Representations of other existing items in the data set anr still considered up to date and will not be rebound,though their positions may be altered.(这是一个结构性变化的事件。数据集中其他现有项目的表示仍然被认为是最新的,并且不会反弹,尽管它们的位置已经改变)
        1. Furthermore,notifyDataSetChanged() can be user to notify any register observers that the data set has changed(此外,可以使用notifyDataSetChanged()方法通知任意视图该数据集已更改)

    3.Customize your RecyclerView(自定义RecyclerView)

    You can customize the RecyclerView objects to meet your specific needs.The standard classed provide all the functionality that most developers will need;in many cases,the only customization you need to do is design the view for each view holder and write the code to update those views with the appropriate data.(你可以自定义RecyclerView对象,以满足你的特定需求。标准类提供了大多数开发人员所需的所有功能;在许多情况下,你需要做的唯一定制就是为每个view holder设计视图,并编写代码来使用适当的数据更新这些视图)

    App data and files(App数据和文件)

    1.Data and File storage Overview(数据和文件存储概述)

    Android uses a file system that’s similar to disk-based file systems on other platforms.The system provides several options for you to save your app data:
    • App-specific storage:Store files that are meant for your app’s use only,either in dedicated directories within an internal storage volume or different dedicated directoryes within external storage.Use the directories within internal storage to save sensitive information that other apps shouldn’t access.(应用专属存储:存储仅供应用程序使用的文件,可以存储在内部存储卷中的专用目录或外部存储中的不同专用目录中。使用内部存储器中的目录来保存其他应用程序不应该访问的敏感信息)
    • Shared storage:Store files that your app intends to share with other apps,including media,documents,and other files.(共享存储:存储应用打算与其他应用共享的文件,包括媒体、文档和其他文件)
    • App Preferences:Store private,primitive data in key-value pairs.(应用程序首选项(偏好设置):以键值对存储私有的原始数据)
    • Databases:Store structured data in a private database using the Room persistence library.(数据库:使用Room持久性库将结构化数据存储在专用数据库中)

    App Preferences(Shared Preferences)(偏好设置)

    1.Save key-value data

    If you have a relatively small collection of key-values that you’d like to save,you can use the SharedPreferences APIs.A SharedPreferences object points to a file containing key-value pairs and provides simple methods to read and write them.(如果你有一个想要保存的相对较小的键值对集合,那么你可以使用SharedPreferences API。它指向一个包含键值对的文件,并提供读写它们的简单方法)

    1.1 Get a handle to shared preferences(获取偏好设置的句柄)

    You can create a new shared preference file or access an existing one by calling one of these methods:
    • getSharedPreferences(String name.int mode)—Use this if you need multiple shared preference files identified by name,which you specify with the first parameter.You can call this from any Conrext in your app.(如果需要多个由名称表示的共享首选项文件,请使用该方法并使用第一个参数指定,你可以从你应用中的任何上下文中调用它)
      • name:Desired preferences file(所需的首选项文件)
      • mode:Operating mode.Value is either 0 or MODE_PRIVATE
      • If the preferences directory does not already exist,it will be created when this method is called.(如果首选项目录不存在,则调用该方法会创建该目录)
    • getPreferences(int mode)—Use this from an Activity if you need to use only one shared preference file for the activity.Because this retrieves a default shared preference file that belongs to the activity,you dont’t need to supply a name.(如果只需要为活动使用一个共享首选项文件,请在活动上使用该方法,此方法不需要提供名称)
      • mode:Operating mode.Value is either 0 or MODE_PRIVATE

    1.2 Write to shared preferences(写入偏好设置)

    To write to a shared preferences file,create a SharedPreferences.Editor by calling edit() on your SharedPreferences.(如果要写入一个共享首选项文件,请创建一个SharedPreferences.Editor,并调用其edit()方法)
    Pass the keys and values you want to write with methods such as putInt() and putString().Then call apply() or commit() to save the changes.For example:(使用putInt()putString()方法传递要写入的键和值,然后调用apply()commit()来保存更改)
    • apply() changes the in-memory SharedPreferences object immediately but writes the updates to disk asynchronously.When two editors are modifying preferences at the same time,the last one to call apply() win.(apply()会立即更改内存中的SharedPreferences对象,但会异步写入磁盘。当两个编辑器同时修改时,最后一个调用的应用程序会修改成功)
    • Alternatively, you can use commit() to write the data to disk synchronously. But because commit() is synchronous, you should avoid calling it from your main thread because it could pause your UI rendering.(或者你也可以用commit()方法将数据同步写入磁盘。但因为commit()时同步的,你应该避免从你的主线程调用它,它坑你会暂停你的UI呈现)

    1.3 Read from shared preferences(读取偏好设置)

    To retrieve values from a shared preferences file,call methods such as getInt() and getString(),providing the key for the value you want,and optionally a default value to return if the key isn’t present.For example:(要从共享首选项文件中检索值,请调用getInt()getString()方法,为你想要的值提供键,如果键不存在,还可以选择返回一个默认值。例如:)
    As can be seen from Figure 1, it shows an exampple about how to read from and write to the default shared preference file and the shared preference file identified by name(从图1可以看出,它显示了一个关于如何读取和写到默认的共享首选项文件和由名称表示的共享首选项文件的示例)
    notion image
    Figure 1

    2.JavaBeans Components(JavaBean组件)

    All you have to do is make your class look like a bean.A bean is a Java class with method names that follow the JavaBeans guidelines.(你要做的就是让你的类看起来像一个豆子。bean是一个Java类,其方法名遵循JavaBean指南)

    3.Save data in a local database(在本地数据库中保存数据)

    Room provides an abstraction layer over SQLite to allow fluent database access while harnessing the full power of SQLite.(Room在SQLite上提供了一个抽象层,允许流畅地访问数据库,同时充分利用SQLite地全部功能)

    3.1 Room Overview(Room概述)

    notion image
    Figure 2
    There are 3 major components in Room:Databaes,Entities and DAOs.As can be seen from Figure 2,it shows the relationship among the different components of Room.More specifcily:(Room中有3个主要组成部分:Database、EntitiesDAOs。从图2可以看出,它显示了Room中不同组件之间的关系。更具体地说:)
    • Database:Contains the database holder and serves as the main access point for the underlying connection to your app’s persisted,relational data.(包含数据库持有者,并作为与应用程序持久的关系数据的基础链接的主要访问点)
      • The class that’s annotated with @Database should satisfy the following conditions:
      • Be an abstract class that extends RoomDatabase.(是一个继承于RoomDatabase类的抽象类)
      • Include the list of entities associated with the database within the annotation.(在注解中包含与数据库像关联的实体的列表)
      • Contain an abstract method that has 0 arguments and returns the class that is annotated with @Dao.(包含一个包含0个参数的抽象方法,并返回用@Dao注释的类)
        • At runtime,you can acquire an instance of Database by calling Room.databaseBuilder() or Room.inMemoryDatabaseBuilder().(在运行时,你可以通过调用Room.databaseBuilder()Room.inMemoryDatabaseBuilder()来获取一个数据库的实例)
    • Entity:Representes a table within the database.(表示数据库中的一个表)
    • DAO:Contains the methods used for accessing the database.(包含用于访问数据库的方法)
      • The app uses the Room database to get the data access objects,or DAOs,associated with that databse.The app then uses eachDAO to get entities from the database and save any changes to those eneities back to the database.Finally,the app uses an entity to get and set values that correspond to table columns within the database.(应用程序使用Room数据库来获取与该数据库相关联的数据访问对象,或DAOs。然后,该应用程序使用每个DAO从数据库中获取实体,并将这些实体进行的任何更改保存回数据库中。最后,该应用程序使用一个实体来获取和设置对应于数据库中的表列的值。)
        For example,the following code snippet contains a sample database configuration with one entity and one DAO.(例如,以下代码片段包含一个实体和一个DAO的示例数据库配置:)
        notion image
        After creating the files above,you get an instance of the created database using the following code:(创建上述文件后,你将使用以下代码获得已创建数据库的实例)

    Content providers(内容提供者)


    Content providers can help an application manage access to data stored by itself,stored by other apps,and provide a way to share data with other apps.They encapsulate the data,and provide mechanisms for defining data security.Content providers are the standard interface that connects data in one process with code running in another process.A content provider can be used to manage access to a variety of data storage sources,including both structured data,such as a SQLite relational database,or unstructured data such as image files.(内容提供商可以帮助应用程序管理自己存储的、由其他应用程序存储的数据的访问,并提供一种与其它应用程序共享数据的方式。它们封装了数据,并提供了定义数据完全性的机制。内容提供程序是将在一个进程中运行的数据与在另一个进程中运行的代码连接起来的标准接口。内容提供程序可用于管理和对各种数据存储源的访问,包括结构化数据,如SQLite关系数据库,或非结构化数据,如图像文件)

    2.Content provider basics(内容提供基础知识)

    A content provider manages access to a central repository of data.A provider is part of an Android application,which often provides its own UI for working with the data.However,content providers are primarily intended to be used by other applications,which access the provider using a provider client object.Together,providers and provider clients offer a consistent,standard interface to data that also handles inter-process communication and secure data access.(内容提供程序管理对中心数据存储库的访问。提供者是安卓应用程序的一部分,该应用程序通常提供自己的UI来处理数据。但是内容提供程序主要是供其他应用程序使用,这些应用程序使用提供程序客户端对象访问提供程序。提供商和提供商客户端一起为数据提供了一个一致的、标准的接口,它还可以处理进程间的通信和安全的数据访问)
    As can be seen from Figure 2,typically you work with content providers in one of two scenarious:(从图2中可以看出,通常你在两种场景中与内容提供程序合作:)
    1. You may want to implement code to access an existing content provider in another application;(你可能希望实现代码以访问另一个应用程序中的现有内容提供程序)
    1. You may want to create a new content provider in your application to share data with other applications.(你可能希望在应用程序中创建一个新的内容提供程序,以与其他应用程序共享数据)
    notion image

    Contacts provider(联系人提供程序)


    The Contacts Provider is a powerful and flexible Android component that manages the device’s central repository of data about people.The Contreacts Provider is the source of data you see in the device’s contacts application,and you can also access its data in your own application and transfer data between the device and online services.The provider accommodates a wide range of data sources and tries to manage as much data as possible for each person,with the result that its organization is complex.Because of this,thr provider’s API includes an extensive set of contract classes and interfaces that facilitate both data retrieval and modification.(联系人提供程序是一个强大而领活的安卓组件,它管理设备的中央数据库。联系人提供程序是您在设备的联系人应用程序中看到的数据来源,您还可以在您自己的应用程序中访问其数据,并在设备和在线服务之间传输数据。提供商提供了广泛的数据源,并试图为每个人管理尽可能多的数据,其结果是其组织是复杂的。因此,提供者的API包含了一组广泛的契约类和接口,便于数据检索和修改)

    1.1 Contacts Provider organization(联系人提供程序结构)

    The Contacts Provider is an Android content provider component.It maintains three types of data about a person,each of which corresponds to a table offered by the provider,as illustrated in Figure 11:(联系人提供程序是 Android 内容提供程序的一个组件。它保留了三种类型的联系人数据,每种数据都对应提供程序提供的一个表,如图 1 所示:)
    notion image
    The three tables are commonly referred to by the names of their contract classes.The classes define constants for content URIs,column name,and column values and used by the tables:
    • ContactsContract.Contacts table.Rows representing different people, based on aggregations of raw contact rows.(表示不同联系人的行,基于聚合的原始联系人行)
    • ContactsContract.RawContacts table.Rows containing a summary of a person’s data, specific to a user account and type.(包含联系人数据摘要的行,针对特定用户帐户和类型)
    • ContactsContract.Data table.Rows containing the details for raw contact, such as email addresses or phone numbers.(包含原始联系人详细信息(例如电子邮件地址或电话号码)的行)

    1.2 RawContacts Table(原始联系人表)

    A raw contact represents a person’s data coming from a single account type and account name. Because the Contacts Provider allows more than one online service as the source of data for a person. The Contacts Provider allows multiple raw contacts for the same person. Multiple raw contacts also allow a user to combine a person’s data.(原始联系人表示来自某一帐户类型和帐户名称的某一联系人数据。由于联系人提供程序允许将多个在线服务作为某一联系人的数据源,因此它允许同一联系人对应多个原始联系人。借助支持多个原始联系人的特性,用户还可将某一联系人在帐户类型相同的多个帐户中的数据进行合并)

    1.3 Data Table(数据表)

    ​ **As noted previously, the data for a raw contact is stored in a ContactsContract.Data row that is linked to the raw contact’s _ID value. This allows a single raw contact to have multiple instances of the same type of data such as email addresses or phone numbers.** (如前文所述,原始联系人的数据存储在 ContactsContract.Data 行中,该行链接到原始联系人的 _ID 值。基于此,一位原始联系人便可拥有多个数据类型相同的实例,如电子邮件地址或电话号码。)

    1.4 Contacts Table(联系人)

    The Contacts Provider combines the raw contact rows across all account types and account names to form a contact. This facilitates displaying and modifying all the data a user has collected for a person. The Contacts Provider manages the creation of new contact rows, and the aggregation of raw contacts with an existing contact row. Neither applications nor sync adapters are allowed to add contacts, and some columns in a contact row are read-only.(联系人提供程序会将所有帐户类型和帐户名称的原始联系人行进行合并,从而形成联系人。这有助于显示和修改用户针对某一联系人收集的所有数据。联系人提供程序可管理新联系人行的创建,以及原始联系人与现有联系人行的合并。系统不允许应用或同步适配器添加联系人,并且联系人行中的某些列为只读列。)



    A notification is a message that Android displays outside your app’s UI to provide the user with reminders,communication from other people,or other timely information from your app.Users can tap the notification to open your app or take an action directly from the notification.(通知是指 Android 在您应用的界面之外显示的消息,旨在向用户提供提醒、来自他人的通信信息或您应用中的其他实时信息。用户可以点按通知来打开应用,或直接从通知中执行操作。)

    1.1 Notification anatomy(通知剖析)

    The design of a notification is determined by system templates—your app simply defines the contents for each portion of the template (see Figure 6). Some details of the notification appear only in the expanded view.(通知的设计由系统模板决定,您的应用只需要定义模板中各个部分的内容即可(看图6)。通知的部分详情仅在展开后的视图中显示。)
    notion image
    Figure 6
    1. Small icon:This is required and set with setSmallIcon().(必须提供,通过 setSmallIcon() 进行设置)
    1. App name:This is provided by the system.(由系统提供)
    1. Time stamp:This is provided by the system but you can override with setWhen() or hide it with setShowWhen(false).(由系统提供,但您可以使用 setWhen() 替换它或者使用 setShowWhen(false) 隐藏它)
    1. Large icon:This is optional(usually used only for contact photos;do not use it for your app icon) and set with setLargeIcon()(可选内容(通常仅用于联系人照片,请勿将其用于应用图标),通过 setLargeIcon() 进行设置)
    1. Title:This is optional and set with setContentTitle()(可选内容,通过 setContentTitle() 进行设置)
    1. Text:This is optional and set with setContextText()(可选内容,通过 setContentText() 进行设置)

    1.2 Set lock screen visibility(设置锁定屏幕可见性)

    As can be seen from Figure 16, to control the level of detail visible in the notification from the lock screen, call setVisibility() and specify one of the following values:(从图16可以看出,要控制锁屏通知中可见的详细级别,请调用setVisibility()并指定以下值)
    • VISIBILITY_PUBLIC shows the notification’s full content.(显示通知的完整内容)
    • VISIBILITY_SECRET doesn’t show any part of this notification on the lock screen.(不在锁定屏幕上显示该通知的任何部分)
    • VISIBILITY_PRIVATE shows basic information, such as the notification’s icon and the content title, but hides the notification’s full content.(显示基本信息,例如通知图标和内容标题,但隐藏通知的完整内容)
    notion image
    Figure 16

    1.3 Remove a notification(删除通知)

    Notifications remain visible until one of the following happens:(通知始终可见,知道发生以下情况之一)
    • The user dismisses the notification.(用户拒绝该通知)
    • The user clicks the notification, and you called setAutoCancel() when you created the notification.(用户点击通知,且你在创建通知时调用了 setAutoCancel())
      • .setAutoCancel(true)
    • You call cancel() for a specific notification ID. This method also deletes ongoing notifications.(您针对特定的通知 ID 调用了 cancel()。此方法还会删除当前通知)
      • notificationManager.cancel(notificationId)
    • You call cancelAll(), which removes all of the notifications you previously issued.(您调用了 cancelAll() 方法,该方法将移除之前发出的所有通知)
      • notificationManager.cancelAll()
    • If you set a timeout when creating a notification using setTimeoutAfter(), the system cancels the notification after the specified duration elapses. If required, you can cancel a notification before the specified timeout duration elapses.(如果您在创建通知时使用 setTimeoutAfter() 设置了超时,系统会在指定持续时间过后取消通知。如果需要,您可以在指定的超时持续时间过去之前取消通知)
      • .setTimeoutAfter(1000)