学习如何开发 Android 应用程序






4.82/5 (93投票s)
本文介绍了开发Android应用的基本概念。

引言
如今,智能手机的需求日益增长,我们有各种类型的客户端,例如触摸屏手机、平板电脑、笔记本等。这些智能客户端对应用程序的需求也在不断增加,我们有多种操作系统可供选择,例如 Android、iOS 和 Windows 等。本文将为 .NET 开发者或初学者提供开发 Android 应用程序的指南。
开发环境
本文不关注如何安装/配置开发环境,您可以在互联网上找到不同的开发环境。在本文中,我将使用“eclipse mobile juno”开发环境。
创建新项目
要创建新项目,请单击“文件”->“新建”->“项目”。

这将打开新的向导窗口,您可以在其中选择应用程序模板并设置项目名称和包名。

单击“下一步”按钮,它会进入下一步。在此,提供“应用程序名称”、“项目名称”和“包名称”。“包名称”与 .NET 中的“命名空间”相同,并且必须是唯一的。“项目名称”仅由 Eclipse 使用,并且必须在工作区中是唯一的。

您还需要从下拉列表中选择“最低必需 SDK”。这是您的应用程序将支持的最低 Android 版本。然后选择“目标 SDK”,这是应用程序已知可与之配合使用的最高 API。然后为“编译方式”选项选择已安装的 SDK,以便为选定的目标 SDK 编译您的代码。
在向导的下一步中,您需要选择图标、一些其他信息,并在最后一步提供活动名称及其导航类型。

稍后我会提供活动和布局的详细信息,现在您可以将其视为桌面应用程序的窗口窗体或 Web 应用程序的网页。提供活动和布局的名称。暂时将导航类型保留为“无”。按“完成”按钮。Eclipse 将自动为您生成启动活动。

在 Eclipse 中,您可以在屏幕左侧的“包资源管理器”窗格中看到您的项目。“HelloWorld”应用程序包含多个自动生成的文件夹和文件。让我们逐一讨论。
- /Src: 包含与项目关联的所有 Java 源文件。例如,Eclipse 生成的 MainActivity.java 文件存储在此目录下的您在向导中指定的“com.MyFirst.helloworld”包中。您可以为应用程序添加更多包,例如 com.MyFirst.Fragments、CommonClasses 等。
-
/gen: 包含 Eclipse 生成的 Java 源文件和其他代码文件。我们将在项目稍后使用 R.java 文件代码。此文件用于将您的资源文件链接到 /src 文件夹中的 Java 文件中使用。
- Android 目录 (/Android 4.2 和 /Android Dependencies): Android 4.2 目录是根据您选择的 Android SDK 生成的,Dependencies 文件夹的支撑文件是为了向后兼容以前版本的 Android SDK 生成的。
- /assets: 默认情况下,这是一个空文件夹,但您可以将原始资源放在其中,这些文件将按原样包含在您的项目中。例如,这是纹理和游戏数据的理想位置。
- /bin: 这是构建的输出目录。您可以在此文件夹中找到最终的 .apk 文件和其他编译的资源。
- /libs: 包含您可能想在应用程序中使用的私有库 (jar)。
- /res: 包含与您的应用程序相关的所有资源文件。应用程序的所有图形元素、字符串和布局都存在于 res 的某个子文件夹中。我们将在该项目中稍后添加一些资源。Eclipse 自动生成的布局文件“activity_main.xml”位于 layout 子文件夹中。
- Project.properties: 此文件由 Android 项目向导生成,用于 Eclipse 设置。直接修改此文件的可能性非常小。而是右键单击 Eclipse 中的项目,然后单击“属性”,然后进行任何必要的更改。
在模拟器中运行您的应用程序
首先,您需要配置模拟器来测试您的应用程序。要配置您的模拟器,请单击“窗口”->“Android 虚拟设备管理器”。


这将打开一个弹出窗口,您可以在其中创建新的虚拟设备、编辑现有设备并启动任何虚拟设备。创建新的虚拟设备后,关闭此窗口。现在,右键单击屏幕左侧“包资源管理器”窗格中的应用程序,然后单击“运行方式”->“Android 应用程序”。它将编译您的应用程序并在模拟器中执行它。

几分钟后,模拟器将启动,您将在其中看到您的 HelloWorld 应用程序。

在屏幕上,您可以看到状态栏、操作栏和导航栏。您无需关心状态栏和导航栏,它们由系统管理。操作栏包含应用程序的徽标和标题,您还可以通过单击操作栏上的菜单按钮(三个垂直点)来打开菜单。布局区域是我们放置所有 UI 控件的地方。
设计布局
如前所述,Eclipse 默认会生成一个布局。在模拟器中,应用程序仅在屏幕中央显示“Hello World!”文本。从 /res/layout/activity_main.xml 打开布局,您可以在 Eclipse 中间区域看到设计器中的布局。您可以根据需要从图形视图或 XML 视图切换。Eclipse 在布局底部为您提供了“图形布局”或“activity_main.xml”这两个选项。

在设计器中,您可以在不同选项卡(例如文本字段、布局等)中看到所有可用的 UI 设计控件。我将创建一个下面的图像所示的 UI,以了解 Android 应用程序的基本组件。让我们开始玩转布局。

此布局使用线性布局设计。LinearLayout
是一个视图组,它将子视图沿单个方向(水平或垂直)对齐。android:orientation
属性用于设置方向。例如,android:orientation="vertical"
。Eclipse 在屏幕右侧提供属性面板,用于从设计器设置属性。TextView
控件是只读文本。您只能查看而不能编辑。EditText
控件用于获取用户输入。Button
是一个标准按钮控件,单击时会执行相应的操作。
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> <TextView android:layout_width="fill_parent" android:layout_height="30dp" android:background="@drawable/header_bg_royal" android:paddingLeft="8dp" android:paddingTop="6dp" android:text="@string/intent_title" android:textColor="@color/white_color" android:textStyle="bold" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:layout_marginBottom="10dp"> <Button android:id="@+id/btn_phone_call" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/phone_call_title" /> <Button android:id="@+id/btn_map_application" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/map_title" /> </LinearLayout> <TextView android:layout_width="fill_parent" android:layout_height="30dp" android:background="@drawable/header_bg_royal" android:paddingLeft="8dp" android:paddingTop="6dp" android:text="@string/activity_title" android:textColor="@color/white_color" android:textStyle="bold" /> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:layout_marginBottom="10dp"> <Button android:id="@+id/btn_open_activity" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/open_activity_title" /> </LinearLayout> . . . </LinearLayout>
您必须注意的一点是,我还没有在此布局中为按钮注册任何事件。我们可以在这里使用 onClick
属性完成,但这并不是一个好方法。现在是时候了解一些 UI 元素/属性了。
属性
layout_width & layout_height: 这些属性用于设置元素的宽度和高度。可能的值为“fill_parent
”、“match_parent
”、“wrap_content
”和任何数字(例如 100dp)。fill_parent
和 match_parent
是相同的。fill_parent
在 API 级别 8 及更高版本中重命名为 match_parent
,这意味着视图想要与其父项一样大(减去内边距)。wrap_content
表示根据内容或子项设置宽度或高度。
android:background="@drawable/header_bg_royal": 此属性类似于其他编程语言中用于设置元素背景的属性。有趣的一点是从 Android 应用程序的资源中设置背景。header_bg_royal
是我粘贴到 res/drawable-hdpi
中的图像。您可以在下面的图像中看到完整路径。

在布局 XML 文件中,我们可以使用资源名称开头的 @
符号来访问资源。@drawable
表示从 drawable 文件夹获取资源。您可能会看到多个 drawable 文件夹,例如 drawable-hdpi、drawable-ldpi 等。存在多个文件夹的原因是,我们有各种各样的客户端机器,有些使用平板电脑、笔记本、手机等。屏幕尺寸和分辨率因客户而异。您可以为不同的分辨率创建图标、图像,并将其放入相应的文件夹中。Android 操作系统将自动选择最适合显示的图像。@drawable/header_bg_royal
表示从 drawable
文件夹获取 header_bg_royal
图像/资源。
android:text="@string/intent_title": 我希望您已经理解了 @
符号的含义,以及它后面的字符串代表什么,intent_title
又是什么。在再次解释之前,让我先说明为什么需要将所有字符串放入资源文件中。如果我在 XML 文件中硬编码任何控件的文本,Eclipse 会警告您将其移至资源文件。您可以在下面给出的图像中看到警告,当我将按钮的文本属性设置为“Button”时,Eclipse 会发出警告消息,提示将其移至 string
资源文件中。

问题是为什么它应该是字符串资源。虽然您可以硬编码,但这并不是一个好的编程实践。假设您在不同的活动或布局中有 10 个文本出现。要更改该文本,您需要进入每个活动/布局并在那里进行更改。如果您将该文本放入字符串资源中,那么更改只需要一个地方。您还可以使用这些资源文件创建多语言应用程序。
@string/intent_title
表示从 string
资源中获取 intent_title
的值。
android:textColor="@color/white_color": 用于设置文本的前景色,从资源文件中获取颜色值。在下一节中,您将了解如何向资源文件添加值。
android:id="@+id/btn_phone_call": 如果您想在代码中访问任何控件,请为其分配一个 ID。@
符号前的 +
表示如果资源存在则使用它,否则创建它。@+id/btn_phone_call
表示在 ID 资源中使用 btn_phone_call
,如果它不存在则创建它。
资源文件

Eclipse 提供了一个使用设计器添加资源的选项。您也可以使用 XML 视图来添加资源。您可以添加不同类型的资源,例如字符串、颜色、数组等。本文不详细介绍资源。您可以在其他教程中了解更多相关信息。
Activity
这是 Android 开发的一个非常重要的概念。Activity 代表应用程序中的一个屏幕。您可以在不同方式下使用它,例如作为浮动窗口或嵌入到另一个 Activity 中等。您的 Activity 类必须继承自 Activity
类。extends
关键字用于 Java 中的继承。
public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.activity_main, menu); return true; } }
onCreate
方法用于初始化您的 Activity。我们通常调用 setContentView()
方法来定义 Activity 的布局,并使用 findViewByid()
获取需要以编程方式交互的 UI 控件。
super.onCreate()
表示调用基类的 onCreate
方法。Super
用于在 Java 中访问基类。与此 Activity 关联的布局位于 activity_main.xml 中。您可以使用 R.layout.activity_main
获取该资源的 ID。R
是自动生成的类,它维护资源,我们使用它来访问代码中的资源。setContentView(R.layout.activity_main)
设置 Activity 的布局。
onCreateOptionsMenu()
方法用于处理该 Activity 的菜单。稍后我会解释。
在 Activity 中访问控件/视图
设置 Activity 的内容视图后,您可以使用 findViewById(viewId)
方法获取控件。它将视图/控件 ID 作为参数,并返回找到的视图。View
是小部件的基类,用于创建交互式 UI 组件(按钮、文本字段等)。我们需要将 view
强制转换为原始小部件。
Button btnPhoneCall = (Button)findViewById(R.id.btn_phone_call); EditText txtName = (EditText)findViewById(R.id.txt_name);
在上面的示例代码中,findViewById(R.id.btn_phone_call)
查找具有作为参数传入的 ID 的按钮,并查找 ID 为
的控件。现在,找到它们之后,我们就可以在代码中使用这些视图/控件了。现在我们需要注册按钮的单击事件,在单击时我们将打开 Android 的电话拨号界面。
btnPhoneCall.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
onPhoneCallClick();
}
});
在 Java 中实现监听器有三种方法,它们各有优缺点。这三种方法是
- 内联实现
- 使用 implements 关键字
- 通过使用变量
您可以在互联网上学习这些不同的方法。在上面的示例中,我使用内联实现为按钮注册了监听器。调用按钮的 setOnClickListener()
方法,并将 OnClickListener
作为参数传递。在 OnClickListener
处理程序中,重写 onClick
事件。当用户单击按钮时,它将调用 onClick
事件。您可以在 onClick
中编写您的代码。
Intent
Intent
是一个异步消息,它允许 Android 组件向 Android 系统中的其他组件请求功能。它代表应用程序“要做某事”的意图。我们可以使用 Intent 执行各种任务,例如拨打电话、打开地图、打开 Activity 等。但最常用于启动另一个 Activity。
如何启动另一个 Activity
到目前为止,您已经学习了 Activity、布局资源和 Intent。创建一个名为“LifeCycleActivity
”的另一个 Activity,并在布局文件夹中创建其布局“activity_life_cycle.xml
”。最好使用 Eclipse 将 Activity 添加到您的应用程序中,它会自动生成该 Activity 的布局,并将 Activity 的必要信息自动放入“AndroidManifest.xml”文件中。否则,您需要手动完成。右键单击左侧“Package Explorer”窗格中的应用程序,然后单击“New > Other”。这将打开一个弹出窗口,您需要在其中选择“Android Activity”,然后在完成向导后,它将为您创建一个 Activity 和默认布局。
创建 Intent 类的对象并将其传递给 startActivity()
方法。Intent
类有不同的构造函数类型,用于启动 Activity,请将上下文和 Activity 类传递给对象。Activity
类是 Context 的子类,所以将 this 作为第一个参数,然后传递系统应该接收 Intent 的类。然后将此 Intent 传递给 startActivity()
方法,您的第二个 Activity 将启动。
Intent intent = new Intent(this, LifeCycleActivity.class);
startActivity(intent);
还有一些其他启动 Activity 的方法。您也可以了解它们。
- startActivityForResult(intent, requestCode)
- startActivityFromChild(child, intent, requestCode)
- startActivityFromFragment(fragment, intent, requestCode)
打开电话拨号器
在 Android 中启动电话拨号器也非常简单,您可以通过 Intent 向 Android OS 发送消息以运行特定应用程序。
Uri uri = Uri.parse("tel:03361122334");
Intent intent = new Intent(Intent.ACTION_VIEW,uri);
startActivity(intent);
当您创建来自 Uri
的异步消息(Intent)时,它会告诉系统打开可以处理 Uri
方案的 Activity。在上面的示例中,Uri
以 tel: 开头,会加载电话拨号器应用程序的 Activity,并将号码加载其中。
将数据传递到另一个 Activity
您可以轻松地将数据与异步消息(Intent)一起传递,就像我们传递给电话拨号器 Activity 一样。但我们通过 Uri
传递给电话拨号器 Activity。您也可以将字符串、整数或其他值放入 Intent 中,还可以放入自定义类对象。使用 intent.putExtra()
方法将额外信息放入 Intent 中。此方法有许多重载方法,请使用适合您数据的相应方法。
Student std = getStudent();
Intent intent = new Intent(this, DetailActivity.class);
intent.putExtra("student", (Serializable)std);
startActivity(intent);
接收 Intent 的 Activity “DetailActivity
”公开了用于检索额外信息的方法。getIntent()
方法返回 Intent,然后您可以使用 getExtras()
方法获取额外信息。此方法返回一个 Bundle,然后您可以从 Bundle 中使用 get 方法根据您的信息类型获取所需信息。在此示例中,我调用“(Student)bundle.getSerializable("student");
”,因为我的信息是一个可序列化的对象,然后将其转换回我的具体类对象。
Bundle bundle = this.getIntent().getExtras();
Student std = (Student)bundle.getSerializable("student");
String name = std.getName();
Activity 的生命周期
为了正确理解 Activity,了解 Activity 的生命周期是必要的。Activity 在系统中被管理为一个 Activity 堆栈。当启动新的 Activity 时,它会被放置在堆栈的顶部,并成为运行中的 Activity。之前的 Activity 始终保留在堆栈的下方,并且直到新的 Activity 退出,否则不会移到前面。以下是 Activity 的每个状态调用方法的列表:
@Override
protected void onCreate(Bundle savedInstanceState) {
}
@Override
protected void onStart() {
}
@Override
protected void onRestart() {
}
@Override
protected void onResume() {
}
@Override
protected void onPause() {
}
@Override
protected void onStop() {
}
@Override
protected void onDestroy() {
}
onCreate()
方法在 Activity 首次创建时调用。onStart()
在 Activity 对用户可见时调用,onResume()
在应用程序开始与用户交互时调用。此时,您的 Activity 将位于 Activity 堆栈的顶部。
onPause()
方法在系统即将开始恢复前一个 Activity 时调用。它通常用于保存未保存的数据以持久化,停止动画或其他可能消耗 CPU 的工作。
onStop()
方法在 Activity 不再对用户可见时调用,因为另一个 Activity 已恢复并覆盖了此 Activity。
onRestart()
在 Activity 已停止后调用。在再次启动之前调用。
onDestroy()
在 Activity 被销毁之前调用。
创建菜单

要创建菜单,请打开 res/menu/activity_main.xml 文件并在其中添加您的菜单项。为每个菜单项设置 ID 和标题,然后您就可以在 Activity 类中按 ID 处理此菜单项。
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item
android:id="@+id/menu_settings"
android:showAsAction="never"
android:title="@string/menu_settings"/>
<item
android:id="@+id/menu_other"
android:showAsAction="never"
android:title="@string/menu_other"/>
<item
android:id="@+id/menu_exit"
android:showAsAction="never"
android:title="@string/menu_exit"/>
</menu>
要处理菜单项的单击方法,请在您的 Activity 中重写 onOptionsItemSelected(MenuItem item)
方法。每当用户单击/选择任何菜单项时,此方法都会触发。要为每个元素处理不同的操作,请使用 getItemId()
方法获取所选菜单项的 ID,并为每个菜单项执行操作。
@Override
public boolean onOptionsItemSelected(MenuItem item) {
boolean handled = false;
int id = item.getItemId();
switch(id)
{
case R.id.menu_settings:
{
Toast.makeText(this, "Clicked on setting menu item.", Toast.LENGTH_SHORT).show();
handled = true;
break;
}
case R.id.menu_other:
{
onOpenActivity();
handled = true;
break;
}
case R.id.menu_exit:
{
finish();
handled = true;
break;
}
default:
{
handled = super.onOptionsItemSelected(item);
}
}
return handled;
}
每个 Activity 都可以有自己的菜单。您可以为每个 Activity 设置不同的菜单项并分别处理。某些 Activity 可能没有任何菜单。为此,请不要在您的 Activity 中重写 onCreateOptionsMenu
方法。在此方法中,我们将菜单项MenuInflater。