
3.1 理解Activity
本章首先展示如何创建Activity。要创建Activity,首先要新建一个继承Activity基类的Java类。
package com.jfdimarzio.chapter1helloworld; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } }
Activity类从res/layout文件夹中加载由XML文件定义的用户界面(UI)组件。在这个示例中,是从main.xml文件中加载UI的:
setContentView(R.layout.activity_main);
应用中的每一个Activity必须在AndroidManifest.xml文件中声明,如下所示:
<? xml version="1.0" encoding="utf-8"? > <manifest xmlns:android="http://schemas.android.com/apk/res/android package="com.jfdimarzio.chapter1helloworld"> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:supportsRtl="true" android:theme="@style/AppTheme"> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
Activity基类定义了一系列事件,管理着Activity的生命周期。图3-1展示了一个Activity的生命周期。

图3-1
Activity类定义了以下事件:
● onCreate()——当首次创建Activity时被调用
● onStart()——当Activity显示在用户面前时被调用
● onResume()——当Activity能够开始与用户交互时被调用
● onPause()——在当前的Activity将暂停并且前一个Activity将要被重新开始时被调用
● onStop()——当Activity不再显示在用户面前时被调用
● onDestroy()——当Activity被系统销毁前调用(手动销毁或者系统回收内存时)
● onRestart()——当Activity停止后并重新启动时被调用
在默认情况下,新建的Activity都包含onCreate()事件。这个事件处理程序中的代码将有助于在屏幕上显示UI元素。
图3-2展示了一个Activity的生命周期以及它经历的各个阶段—— 从Activity启动到结束。

图3-2
理解一个Activity各个阶段的最佳方法是创建一个新项目,实现各种事件,根据各种用户交互观察Activity的不同状态。
试一试:了解Activity的生命周期(Activity101.zip)
(1) 使用Android Studio创建一个新Android项目,命名为Activity101。
(2) 在Activity101Activity.java文件中,添加如下突出显示的代码(注意:在这个示例中,确保把所有对com.jfdimarzio的引用修改成你自己项目使用的包名)。
package com.jfdimarzio.activity101; import android.support.v7.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; public class MainActivity extends AppCompatActivity { String tag = "Lifecycle Step"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); Log.d(tag, "In the onCreate() event"); } public void onStart() { super.onStart(); Log.d(tag, "In the onStart() event"); } public void onRestart() { super.onRestart(); Log.d(tag, "In the onRestart() event"); } public void onResume() { super.onResume(); Log.d(tag, "In the onResume() event"); } public void onPause() { super.onPause(); } Log.d(tag, "In the onPause() event"); public void onStop() { super.onStop(); Log.d(tag, "In the onStop() event"); } public void onDestroy() { super.onDestroy(); Log.d(tag, "In the onDestroy() event"); } }
(3) 单击快捷键Shift+F9或者选择菜单Run | Debug开始调试应用。在弹出窗口中选择一个Android虚拟设备。
(4) 当Activity被首次加载时,应该可以在logcat控制台中看到非常相似的信息(如图3-3所示)。如果没有看到logcat控制台,单击Android Studio窗口底端的Android Monitor。
11-16 06:25:59.396: D/Lifecycle Step(559): In the onCreate() event 11-16 06:25:59.396: D/Lifecycle Step(559): In the onStart() event 11-16 06:25:59.396: D/Lifecycle Step(559): In the onResume() event

图3-3
(5) 如果在Android模拟器中单击Back按钮,将会看到如下信息:
11-16 06:29:26.665: D/Lifecycle Step(559): In the onPause() event 11-16 06:29:28.465: D/Lifecycle Step(559): In the onStop() event 11-16 06:29:28.465: D/Lifecycle Step(559): In the onDestroy() event
(6) 单击Home按钮,单击Overview图标,选择Activity101应用,将会看到如下信息:
11-16 06:31:08.905: D/Lifecycle Step(559): In the onCreate() event 11-16 06:31:08.905: D/Lifecycle Step(559): In the onStart() event 11-16 06:31:08.925: D/Lifecycle Step(559): In the onResume() event
(7) 在Android模拟器中单击Home按钮,然后单击Phone按钮,将Activity推到后台。观察logcat窗口中的输出:
11-16 06:32:00.585: D/Lifecycle Step(559): In the onPause() event 11-16 06:32:05.015: D/Lifecycle Step(559): In the onStop() event
(8) 注意onDestory()事件还没有被调用,说明这个Activity仍然在内存中。单击Back按钮退出电话拨号应用。Activity又重新显示出来。观察logcat窗口中的输出:
11-16 06:32:50.515: D/Lifecycle(559): In the onRestart() event 11-16 06:32:50.515: D/Lifecycle(559): In the onStart() event 11-16 06:32:50.515: D/Lifecycle(559): In the onResume() event
此时onRestart()事件被激活,紧接着onStart()和onResume()方法被依次激活。
示例说明
在这个示例中可以看到,当单击Back按钮时Activity会被销毁。理解这一点非常关键,因为无论Activity现在处于什么状态都会丢失。也就是说你需要在Activity中写一些代码,当它被销毁时保存它的状态(第4章中会讨论如何实现)。此刻,注意onPause()方法在下列两种情况下都会被调用:
● 当Activity被发送到后台时
● 当用户单击Back按钮关闭Activity时
当一个Activity启动时,onStart()和onResume()方法总会被调用,无论这个Activity是从后台被恢复的还是新建的。当一个Activity首次创建时,会调用onCreate()方法。
从之前的示例中,可总结出以下知识点:
● 使用onCreate()方法新建和实例化在应用中使用的对象。
● 使用onResume()方法启动那些当Activity在前台时需要运行的服务和代码。
● 使用onPause()方法停止那些当Activity不在前台时不需要运行的服务和代码。
● 使用onDestory()方法在Activity销毁前释放资源。
注意:即使一个应用只有一个Activity并且这个Activity已经被杀死,这个应用仍然在内存中运行。
3.1.1 在Activity上应用样式和主题
在默认情况下,Activity使用默认的Android主题。然而,近几年一直在推广使用一个称为Material的新主题。Material主题具有更加现代和干净的外观。
Material主题有两个版本可供Android开发者选择:Material Light和Material Dark。在AndroidManifest.xml中可以指定使用任意一种。
要在Activity上应用某一个Material主题,可以非常简单地在AndroidManifest.xml文件中修改<Application>元素的android:theme默认值(请确保将所有“com.jfdimarzio”实例修改成你自己项目使用的包名)。
<? xml version="1.0" encoding="utf-8"? >
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.jfdimarzio.activity101">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@android:style/Theme.Material">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
把默认主题修改为@android:style/Theme.Material,如以上代码段中突出显示的代码,应用Material Dark主题会使应用具有深色的外观,如图3-4所示。

图3-4
3.1.2 隐藏Activity的标题
如果需要的话,也可以隐藏Activity的标题(比如说,你只想为用户显示一个状态更新)。要隐藏标题,可以调用requestWindowFeature()方法并传入Window.FEATURE_NO_TITLE常量,如下所示:
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.Window;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
requestWindowFeature(Window.FEATURE_NO_TITLE);
}
}
接着需要修改AndroidManifest.xml文件中的主题,设置一个没有标题栏的主题。请确保把所有com.jfdimarzio实例修改成你自己项目使用的包名。
package com.jfdimarzio.activity101;
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.jfdimarzio.activity101">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@android:style/Theme.NoTitleBar">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
图3-5显示了没有标题栏的主题。

图3-5
3.1.3 显示对话框
在应用中,需要显示对话框获得用户确认的情况非常多。这种情况下,可重写在Activity基类中定义的保护类型方法onCreateDialog()来显示对话框。在以下的“试一试”部分中将演示代码是如何实现的。
试一试:使用Activity显示一个对话框(Dialog.zip)
(1) 使用Android Studio创建一个新的Android项目,命名为Dialog。在选项界面中,把主Activity命名为DialogActivity。
(2) 在AndroidManifest.xml文件中添加以下粗体标出的主题值。请确保将所有com.jfdimarzio实例改成你自己项目使用的包名。
<? xml version="1.0" encoding="utf-8"? >
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.jfdimarzio.dialog" >
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<activity
android:name=".DialogActivity"
android:label="@string/app_name"
android:theme="@style/Theme.AppCompat.Dialog" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
(3) 检查你的DialogActivity.java文件中的代码是否和以下代码一致:
package com.jfdimarzio.dialog; import android.os.Bundle; import android.support.design.widget.FloatingActionButton; import android.support.design.widget.Snackbar; import android.support.v7.app.AppCompatActivity; import android.support.v7.widget.Toolbar; import android.view.View; import android.view.Menu; import android.view.MenuItem; public class DialogActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_dialog); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); FloatingActionButton fab = (FloatingActionButton) findViewById(R.id.fab); fab.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG) .setAction("Action", null).show(); } }); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.menu_dialog, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); //noinspection SimplifiableIfStatement if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }
(4) 单击快捷键Shift+F9在Android模拟器中调试应用。单击按钮显示对话框(如图3-6所示)。

图3-6
示例说明
Android使用AppCompat.Dialog主题把标准Activity绘制成一个自由漂浮的对话框。如果你想在对话框中提供一个OK或者Cancel选择,在对话框中添加类似的按钮是非常容易的。
需要注意,主题只是应用在Activity上,而不是项目上。因此,可以在一个项目中有多个Activity,但只需要在一个Activity上应用对话框主题。
3.1.4 显示进度对话框
当一个应用在执行一个耗时很长的任务时,在Android上通常能看到一个Please wait对话框。例如,应用可能需要登录服务器以后用户才能使用,或者在向用户显示结果以前需要做一个计算。这种情况下,显示一个对话框是非常有用的,这个对话框称为进度对话框,所以用户可以继续等待。
Android提供了一个ProgressDialog类,当你想要向用户显示一个进度条时可以调用这个类。在Activity中调用ProgressDialog非常方便。
在以下的“试一试”部分中将演示如何显示进度对话框。
试一试:显示进度(请等待)对话框
(1) 使用本章之前创建的Activity101项目,确保在AndroidManifest.xml文件中使用的是Material主题。请确保将所有com.jfdimarzio实例修改成你自己项目使用的包名。
<? xml version="1.0" encoding="utf-8"? >
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.jfdimarzio.activity101">
<application
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@android:style/Theme.Material">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
(2) 在MainActivity.java文件中加入以下示例代码中的粗体显示部分。
package com.jfdimarzio.activity101; import android.app.Activity; import android.app.ProgressDialog; import android.os.CountDownTimer; import android.os.Bundle; public class MainActivity extends Activity{ ProgressDialog progressDialog; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } public void onStart() { super.onStart(); progressDialog = ProgressDialog.show(this, "Please Wait", "Processing...", true); CountDownTimer timer = new CountDownTimer(3000,1000) { @Override public void onTick(long millisUntilFinished) { } @Override public void onFinish() { progressDialog.dismiss(); } }.start(); } }
(3) 单击快捷键Shift+F9在Android模拟器中调试应用。你能看到一个进度对话框,如图3-7所示。它会在三秒后消失。

图3-7
示例说明
要创建一个进度对话框,需要创建ProgressDialog类的一个实例,并且调用show()方法:
progressDialog = ProgressDialog.show(this, "Please Wait", "Processing...", true);
这会显示如图3-7所示的进度对话框。因为这个是模态对话框,所以在它关闭前会遮住整个UI。要关闭这个对话框,需要创建一个计时器并在三秒后调用dismiss()方法(第12章会介绍线程,讨论当一个进度对话框显示时,如何从外部线程中调用方法完成其他工作)。
CountDownTimer timer = new CountDownTimer(3000,1000) { @Override public void onTick(long millisUntilFinished) { } @Override public void onFinish() { progressDialog.dismiss(); } }.start();
三秒钟后,调用dismiss()方法关闭了对话框。
下一节将解释如何使用Intent,使用Intent有助于在多个Activity之间导航。