Theme NexT works best with JavaScript enabled
0%

Android入门

^_^

下载和安装

进入官网下载最近版本的 Android Studio,下载地址:https://developer.android.google.cn/studio

创建项目 & 运行应用

创建项目

  1. 在 Welcome to Android Studio 窗口中,点击 Create New Project。
  2. 在 Select a Project Template 窗口中,选择 Empty Activity,然后点击 Next。
  3. 在 Configure your project 窗口中,完成以下操作:
    1. 在 Name 字段中输入项目名,可包含空格。
    2. 在 Package name 字段中输入存放 MainActivity 的包,默认为“com.example.myfirstapp”。
    3. 如果您想将项目放在其他文件夹中,请更改其 Save 位置。
    4. 从 Language 下拉菜单中选择 JavaKotlin
    5. 在 Minimum SDK 字段中选择您希望应用支持的最低 Android 版本。
  4. 点击 Finish,经过一段时间的处理后,Android Studio 主窗口会出现。

最重要的文件

  1. MainActivity:这是主 activity。它是应用的入口点。当您构建和运行应用时,系统会启动此 Activity 的实例并加载其布局。
  2. activity_main.xml:此 XML 文件定义了 activity 界面 (UI) 的布局。它包含一个 TextView 元素,其中具有“Hello, World!”文本
  3. AndroidManifest.xml:清单文件描述了应用的基本特性并定义了每个应用组件。
  4. build.gradle:有两个使用此名称的文件:一个针对项目“Project: My First App”,另一个针对应用模块“Module: My_First_App.app”。每个模块均有自己的 build.gradle 文件。

运行应用

在模拟器上运行

  1. 通过按钮 AVD Manager 创建一个 Android 虚拟设备 (AVD),模拟器可以使用该设备安装和运行您的应用。
  2. 在工具栏中,从运行/调试配置下拉菜单中选择您的应用。
  3. 从目标设备下拉菜单中,选择要用来运行应用的 AVD。
  4. 点击 Run 图标

在真实设备上运行

  1. 使用一根 USB 线将设备连接到开发机器。
  2. 执行以下步骤,在手机的开发者选项窗口中启用 USB 调试
  3. 按照以下步骤操作,在设备上运行应用:
    1. 在 Android Studio 中,从工具栏中的运行/调试配置下拉菜单中选择您的应用。
    2. 在工具栏中,从目标设备下拉菜单中选择要用来运行应用的设备。
  4. 点击 Run

构建首个应用

构建简单的界面

Android 应用的界面 (UI) 以布局和微件的层次结构形式构建而成。布局是 ViewGroup 对象,即控制其子视图在屏幕上的放置方式的容器。微件是 View 对象,即按钮和文本框等界面组件。

打开布局编辑器

首先,请按照以下步骤设置工作区:

  1. 在 Project 窗口中,依次打开 app > res > layout > activity_main.xml
  2. 若要给布局编辑器留出空间,请隐藏 Project 窗口。
  3. 如果您的编辑器显示 XML 源代码,请点击窗口右上角的 Design 标签页。
  4. 按如下方式配置布局。图中外边距部分设置为16。

左下方的 Component Tree 面板显示布局的视图层次结构。在本例中,根视图是 ConstraintLayout,它仅包含一个 TextView 对象。

ConstraintLayout 是一种布局,它根据同级视图和父布局的约束条件定义每个视图的位置。这样一来,使用扁平视图层次结构既可以创建简单布局,又可以创建复杂布局。这种布局无需嵌套布局。嵌套布局是布局内的布局,会增加绘制界面所需的时间。

添加文本框

  1. 首先,您需要在 Component Tree 面板中移除布局中已有的内容。
  2. Palette 面板中,点击 Text 以显示可用的文本控件。
  3. Plain Text 拖动到设计编辑器中,并将其放在靠近布局顶部的位置。这是一个接受纯文本输入的 EditText 微件。
  4. 点击设计编辑器中的视图。现在,您可以在每个角上看到调整视图大小的正方形手柄,并在每个边上看到圆形约束锚点
  5. 点击并按住顶边上的锚点,将其向上拖动,直至其贴靠到布局顶部,然后将其释放。这是一个约束条件:它会将视图约束在已设置的默认外边距内。在本例中,您将其设置为距离布局顶部 16 dp。
  6. 使用相同的过程创建一个从视图左侧到布局左侧的约束条件。

最终结果:

添加按钮

  1. Palette 面板中,点击 Buttons
  2. Button 微件拖到设计编辑器中,并将其放在靠近右侧的位置。
  3. 创建一个从按钮左侧到文本框右侧的约束条件。
  4. 如需按水平对齐约束视图,请创建一个文本基线之间的约束条件。为此,请右键点击按钮,然后选择 Show Baseline 在布局编辑器中显示基准操作。基线锚点显示在按钮内部。点击并按住此锚点,然后将其拖动到相邻文本框中显示的基线锚点上。

最终结果:

更改界面字符串

若要预览界面,请点击工具栏中的 Select Design Surface,然后选择 Design

  1. 打开 Project 窗口,然后打开 app > res > values > strings.xml

    这是一个字符串资源文件,您可在此文件中指定所有界面字符串。您可以利用该文件在一个位置管理所有界面字符串,使字符串的查找、更新和本地化变得更加容易。

  2. 点击窗口顶部的 Open editor。此时将打开 Translations Editor,它提供了一个可以添加和修改默认字符串的简单界面。它还有助于让所有已翻译的字符串井然有序。
  3. 点击 + 可以创建一个新字符串作为文本框的“提示文本”。在 Add Key 对话框中,完成以下步骤:
    1. 在 Key 字段中输入“edit_message”。
    2. 在 Default Value 字段中输入“Enter a message”。
    3. 点击 OK。
  4. 再添加一个名为“button_send”且值为“Send”的键。

现在,您可以为每个视图设置这些字符串。若要返回布局文件,请点击标签页栏中的 activity_main.xml。然后,添加字符串,如下所示:

  1. 点击布局中的文本框。如果右侧还未显示 Attributes 窗口,请点击右侧边栏上的 Attributes
  2. 找到 text 属性(当前设为“Name”)并删除相应的值。
  3. 找到 hint 属性,然后点击文本框右侧的椭圆(Pick a Resource)。在显示的对话框中,双击列表中的 edit_message
  4. 点击布局中的按钮,找到其 text 属性(当前设为“Button”)。然后点击椭圆(Pick a Resource),并选择 button_send

让文本框大小可灵活调整

若要创建一个适应不同屏幕尺寸的布局,您需要让文本框拉伸以填充去除按钮和外边距后剩余的所有水平空间。

继续操作之前,请点击工具栏中的 Select Design Surface,然后选择 Blueprint

若要让文本框大小可灵活调整,请按以下步骤操作:

  1. 选择两个视图。若要执行此操作,请点击一个视图,在按住 Shift 键的同时点击另一个视图,然后右键点击任一视图并依次选择 Chains > Create Horizontal Chain

    链是两个或多个视图之间的双向约束条件,可让您采用一致的方式安排链接的视图。

  2. 选择按钮并打开 Attributes 窗口。然后使用 Constraint Widget 将右外边距设为 16 dp。
  3. 点击文本框以查看其属性。然后,点击宽度指示器两次,确保将其设置为锯齿状线 (Match Constraints)。

    “Match constraints”表示宽度将延长以符合水平约束条件和外边距的定义。因此,文本框将拉伸以填充去除按钮和所有外边距后剩余的水平空间。

最终结果:

启动另一个 activity

在本节中,您将向 MainActivity 添加一些代码,以便在用户点按 Send 按钮时启动一个显示消息的新 activity。

响应“Send”按钮

  1. app > java > com.example.myfirstapp > MainActivity 文件中,添加以下 sendMessage() 方法桩:
    1
    2
    3
    4
    /** Called when the user taps the Send button */
    public void sendMessage(View view) {
    // Do something in response to button
    }
  2. 返回到 activity_main.xml 文件,并从该按钮调用此方法:
    1. 选择布局编辑器中的相应按钮。
    2. Attributes 窗口中,找到 onClick 属性,并从其下拉列表中选择 sendMessage
  3. 接下来,填写此方法,以读取文本字段的内容,并将该文本传递给另一个 activity

构建一个 intent

Intent 是在相互独立的组件(如两个 activity)之间提供运行时绑定功能的对象。Intent 表示应用执行某项操作的意图。您可以使用 intent 执行多种任务,但在本例中,您的 intent 将用于启动另一个 activity。

MainActivity 中,添加 EXTRA_MESSAGE 常量和 sendMessage() 代码,如下所示:

1
2
3
4
5
6
7
8
9
10
public static final String EXTRA_MESSAGE = "com.example.myfirstapp.MESSAGE";

/** Called when the user taps the Send button */
public void sendMessage(View view) {
Intent intent = new Intent(this, DisplayMessageActivity.class);
EditText editText = (EditText) findViewById(R.id.editText);
String message = editText.getText().toString();
intent.putExtra(EXTRA_MESSAGE, message);
startActivity(intent);
}

sendMessage() 将发生以下情况:

  1. Intent 构造函数会获取两个参数:ContextClass。首先使用 Context 参数,因为 Activity 类是 Context 的子类,所以将 Main Activity传递过去。在本例中,传递到的应用组件的 Class 参数是要启动的 activity。
  2. putExtra() 方法将 EditText 的值添加到 intent。Intent 能够以称为“extra”的键值对形式携带数据类型。

    您的键是一个公共常量 EXTRA_MESSAGE,因为下一个 activity 将使用该键检索文本值。为 intent extra 定义键时,最好使用应用的软件包名称作为前缀。这样可以确保这些键是独一无二的,这在您的应用需要与其他应用进行交互时会很重要。

  3. startActivity() 方法将启动一个由 Intent 指定的 DisplayMessageActivity 实例。接下来,您需要创建该类。

创建第二个 activity

若要创建第二个 activity,请按以下步骤操作:

  1. Project 窗口中,右键点击 app 文件夹,然后依次选择 New > Activity > Empty Activity
  2. Configure Activity 窗口中,输入“DisplayMessageActivity”作为 Activity Name。将所有其他属性保留为默认设置,然后点击 Finish。

Android Studio 会自动执行下列三项操作:

  • 创建 DisplayMessageActivity 文件。
  • 创建 DisplayMessageActivity 文件对应的布局文件 activity_display_message.xml。
  • 在 AndroidManifest.xml 中添加所需的 <activity> 元素。

如果您运行应用并点按第一个 activity 上的按钮,将启动第二个 activity,但它为空。这是因为第二个 activity 使用模板提供的空布局。

添加文本视图

新 activity 包含一个空白布局文件。请按以下步骤操作,在显示消息的位置添加一个文本视图:

  1. 打开 app > res > layout > activity_display_message.xml 文件。
  2. 点击工具栏中的 Enable Autoconnection to Parent 。系统将启用 Autoconnect。
  3. 在 Palette 面板中,点击 Text,将 TextView 拖动到布局中,然后将其放置在靠近布局顶部中心的位置,使其贴靠到出现的垂直线上。Autoconnect 将添加左侧和右侧约束条件,以便将该视图放置在水平中心位置。

最终结果:

显示消息

在此步骤中,您将修改第二个 activity 以显示第一个 activity 传递的消息。

  1. DisplayMessageActivity 中,将以下代码添加到 onCreate() 方法中:
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_display_message);

    // Get the Intent that started this activity and extract the string
    Intent intent = getIntent();
    String message = intent.getStringExtra(MainActivity.EXTRA_MESSAGE);

    // Capture the layout's TextView and set the string as its text
    TextView textView = findViewById(R.id.textView);
    textView.setText(message);
    }

添加向上导航功能

在您的应用中,不是主入口点的每个屏幕(所有不是主屏幕的屏幕)都必须提供导航功能,以便将用户引导至应用层次结构中的逻辑父级屏幕。为此,请在应用栏中添加向上按钮。

若要添加向上按钮,您需要在 AndroidManifest.xml 文件中声明哪个 activity 是逻辑父级。打开 app > manifests > AndroidManifest.xml 文件,找到 DisplayMessageActivity<activity> 标记,然后将其替换为以下代码:

1
2
3
4
5
6
7
<activity android:name=".DisplayMessageActivity"
android:parentActivityName=".MainActivity">
<!-- The meta-data tag is required if you support API level 15 and lower -->
<meta-data
android:name="android.support.PARENT_ACTIVITY"
android:value=".MainActivity" />
</activity>

应用基础知识

您可以使用 Kotlin、Java 和 C++ 语言编写 Android 应用。Android SDK 工具会将您的代码连同任何数据和资源文件编译成一个 APK(Android 软件包),即带有 .apk 后缀的归档文件。

每个 Android 应用都处于各自的安全沙盒中,并受以下 Android 安全功能的保护:

  • Android 操作系统是一种多用户 Linux 系统,其中的每个应用都是一个不同的用户;
  • 默认情况下,系统会为每个应用分配一个唯一的 Linux 用户 ID(该 ID 仅由系统使用,应用并不知晓)。系统会为应用中的所有文件设置权限,使得只有分配给该应用的用户 ID 才能访问这些文件;
  • 每个进程都拥有自己的虚拟机 (VM),因此应用代码独立于其他应用而运行。
  • 默认情况下,每个应用都在其自己的 Linux 进程内运行。Android 系统会在需要执行任何应用组件时启动该进程,然后当不再需要该进程或系统必须为其他应用恢复内存时,其便会关闭该进程。

Android 系统实现了最小权限原则。换言之,默认情况下,每个应用只能访问执行其工作所需的组件,而不能访问其他组件。这样便能创建非常安全的环境,在此环境中,应用无法访问其未获得权限的系统部分。不过,应用仍可通过一些途径与其他应用共享数据以及访问系统服务:

  • 可以安排两个应用共享同一 Linux 用户 ID,在此情况下,二者便能访问彼此的文件。为节省系统资源,也可安排拥有相同用户 ID 的应用在同一 Linux 进程中运行,并共享同一 VM。应用还必须使用相同的证书进行签名。
  • 应用可以请求访问设备数据(如用户的联系人、短信消息、可装载存储装置(SD 卡)、相机、蓝牙等)的权限。

应用组件

应用组件是 Android 应用的基本构建块。每个组件都是一个入口点,系统或用户可通过该入口点进入您的应用。有些组件会依赖于其他组件。

共有四种不同的应用组件类型:

  • Activity
  • 服务
  • 广播接收器
  • 内容提供程序

Android 系统设计的独特之处在于,任何应用都可启动其他应用的组件。例如,当您想让用户使用设备相机拍摄照片时,另一个应用可能也可执行该操作,因而您的应用便可使用该应用,而非自行产生一个 Activity 来拍摄照片。您无需加入甚至链接到该相机应用的代码。只需启动拍摄照片的相机应用中的 Activity 即可。完成拍摄时,系统甚至会将照片返回您的应用,以便您使用。对用户而言,这就如同相机是您应用的一部分。

当系统启动某个组件时,它会启动该应用的进程(如果尚未运行),并实例化该组件所需的类。例如,如果您的应用启动相机应用中拍摄照片的 Activity,则该 Activity 会在属于相机应用的进程(而非您的应用进程)中运行。因此,与大多数其他系统上的应用不同,Android 应用并没有单个入口点(即没有 main() 函数)。

由于系统在单独的进程中运行每个应用,且其文件权限会限制对其他应用的访问,因此您的应用无法直接启动其他应用中的组件,但 Android 系统可以。如要启动其他应用中的组件,请向系统传递一条消息,说明启动特定组件的 Intent。系统随后便会为您启动该组件。

Activity

Activity 是与用户交互的入口点。它表示拥有界面的单个屏幕。例如,电子邮件应用可能有一个显示新电子邮件列表的 Activity、一个用于撰写电子邮件的 Activity 以及一个用于阅读电子邮件的 Activity。尽管这些 Activity 通过协作在电子邮件应用中形成一种紧密结合的用户体验,但每个 Activity 都独立于其他 Activity 而存在。因此,其他应用可以启动其中任何一个 Activity(如果电子邮件应用允许)。例如,相机应用可以启动电子邮件应用内用于撰写新电子邮件的 Activity,以便用户共享图片。

您需将 Activity 作为 Activity 类的子类来实现。

服务

服务是一个通用入口点,用于因各种原因使应用在后台保持运行状态。它是一种在后台运行的组件,用于执行长时间运行的操作或为远程进程执行作业。服务不提供界面。

例如,当用户使用其他应用时,服务可能会在后台播放音乐或通过网络获取数据,但这不会阻断用户与 Activity 的交互。诸如 Activity 等其他组件可以启动服务,使该服务运行或绑定到该服务,以便与其进行交互。

事实上,有两种截然不同的语义服务可以告知系统如何管理应用:

  • 音乐播放是用户可直接感知的服务,因此,应用会向用户发送通知,表明其希望成为前台,从而告诉系统此消息;在此情况下,系统明白它应尽全力维持该服务进程运行,因为进程消失会令用户感到不快。
  • 通常,用户不会意识到常规后台服务正处于运行状态,因此系统可以更自由地管理其进程。如果系统需要使用 RAM 来处理用户更迫切关注的内容,则其可能允许终止服务(然后在稍后的某个时刻重启服务)。

您需将服务作为 Service 的子类来实现。

广播接收器

借助广播接收器组件,系统能够在常规用户流之外向应用传递事件,从而允许应用响应系统范围内的广播通知。由于广播接收器是另一个明确定义的应用入口,因此系统甚至可以向当前未运行的应用传递广播。

许多广播均由系统发起,例如,通知屏幕已关闭、电池电量不足或已拍摄照片的广播。应用也可发起广播,例如,通知其他应用某些数据已下载至设备,并且可供其使用。尽管广播接收器不会显示界面,但其可以创建状态栏通知,在发生广播事件时提醒用户。但广播接收器更常见的用途只是作为通向其他组件的通道,旨在执行极少量的工作。

广播接收器作为 BroadcastReceiver 的子类实现,并且每条广播都作为 Intent 对象进行传递。

内容提供程序

内容提供程序管理一组共享的应用数据,您可以将这些数据存储在文件系统、SQLite 数据库、网络中或者您的应用可访问的任何其他持久化存储位置。其他应用可通过内容提供程序查询或修改数据(如果内容提供程序允许)。

我们很容易将内容提供程序看作数据库上的抽象,因为其内置的大量 API 和支持时常适用于这一情况。但从系统设计的角度看,二者的核心目的不同。对系统而言,内容提供程序是应用的入口点,用于发布由 URI 架构识别的已命名数据项。

内容提供程序作为 ContentProvider 的子类实现,并且其必须实现一组标准 API,以便其他应用能够执行事务。

启动组件

在四种组件类型中,有三种(Activity、服务和广播接收器)均通过异步消息 Intent进行启动。Intent 会在运行时对各个组件进行互相绑定。您可以将 Intent 视为从其他组件(无论该组件是属于您的应用还是其他应用)请求操作的信使。

您需使用 Intent 对象创建 Intent,该对象通过定义消息来启动特定组件(显式 Intent)或特定的组件类型(隐式 Intent)。

对于 Activity 和服务,Intent 会定义要执行的操作(例如,查看或发送某内容),并且可指定待操作数据的 URI,以及正在启动的组件可能需要了解的信息。对于广播接收器,Intent 只会定义待广播的通知。

与 Activity、服务和广播接收器不同,内容提供程序并非由 Intent 启动。相反,它们会在成为 ContentResolver 的请求目标时启动。内容解析程序会通过内容提供程序处理所有直接事务,因此通过提供程序执行事务的组件便无需执行事务,而是改为在 ContentResolver 对象上调用方法。这会在内容提供程序与请求信息的组件之间留出一个抽象层(以确保安全)。

每种组件都有不同的启动方法:

  • 如要启动 Activity,您可以向 startActivity()startActivityForResult() 传递 Intent(当您想让 Activity 返回结果时),或者为其安排新任务。
  • 在 Android 5.0(API 级别 21)及更高版本中,您可以使用 JobScheduler 类来调度服务操作。
  • 您可以通过向 sendBroadcast()sendOrderedBroadcast()sendStickyBroadcast() 等方法传递 Intent 来发起广播。
  • 您可以通过在 ContentResolver 上调用 query(),对内容提供程序执行查询。

清单文件

在 Android 系统启动应用组件之前,系统必须通过读取应用的清单文件 (AndroidManifest.xml) 确认组件存在。您的应用必须在此文件中声明其所有组件,该文件必须位于应用项目目录的根目录中。

除了声明应用的组件外,清单文件还有许多其他作用,如:

  • 确定应用需要的任何用户权限,如互联网访问权限或对用户联系人的读取权限。
  • 根据应用使用的 API,声明应用所需的最低 API 级别。
  • 声明应用使用或需要的硬件和软件功能,如相机、蓝牙服务或多点触摸屏幕。
  • 声明应用需要链接的 API 库(Android 框架 API 除外),如 Google 地图库。

您必须使用以下元素声明所有应用组件:

  • Activity 的 <activity> 元素。
  • 服务的 <service> 元素。
  • 广播接收器的 <receiver> 元素。
  • 内容提供程序的 <provider> 元素。

如果未在清单文件中声明源代码中包含的 Activity、服务和内容提供程序,则这些组件对系统不可见,因此也永远不会运行。

应用资源

Android 应用并非仅包含代码,它还需要与源代码分离的资源,如图像、音频文件以及任何与应用的视觉呈现有关的内容。

对于您在 Android 项目中加入的每一项资源,SDK 构建工具均会定义唯一的整型 ID,您可以利用此 ID 来引用资源,这些资源或来自应用代码,或来自 XML 中定义的其他资源。例如,如果您的应用包含名为 logo.png 的图像文件(保存在 res/drawable/ 目录中),则 SDK 工具会生成名为 R.drawable.logo 的资源 ID。此 ID 映射到应用特定的整型数,您可以利用它来引用该图像,并将其插入您的界面。