第5章 基本程序单元Activity
(
教学录像:2小时4分钟)
在前面介绍的实例中已经应用过Activity,不过那些实例中的所有操作都是在一个Activity中进行的,在实际的应用开发中,经常需要包含多个Activity,而且这些Activity之间可以相互跳转或传递数据。本章将对Activity进行详细介绍。
通过阅读本章,您可以:
★ 了解Activity及其生命周期
★ 掌握创建、配置、启动和关闭Activity的方法
★ 掌握如何使用Bundle在Activity之间交换数据
★ 掌握如何调用另一个Activity并返回结果
★ 掌握创建Fragment的方法
★ 掌握在Activity中添加Fragment的两种方法
5.1 Activity概述
教学录像:光盘\TM\lx\5\ Activity概述.exe
Activity的中文意思是活动。在Android中,Activity代表手机屏幕的一屏,或是平板电脑中的一个窗口。它是Android应用的重要组成单元之一,提供了和用户交互的可视化界面。在一个Activity中,可以添加很多组件,这些组件负责具体的功能。
在Android应用中,可以有多个Activity,这些Activity组成了Activity栈(Stack),当前活动的Activity位于栈顶,之前的Activity被压入下面,成为非活动Activity,等待是否可能被恢复为活动状态。在Activity的生命周期中,有如表5.1所示的4个重要状态。
表5.1 Activity的4个重要状态
| 状 态 | 描 述 |
| 活动状态 | 当前的Activity,位于Activity栈顶,用户可见,并且可以获得焦点 |
| 暂停状态 | 失去焦点的Activity,仍然可见,但是在内存低的情况下,不能被系统killed(杀死) |
| 停止状态 | 该Activity被其他Activity所覆盖,不可见,但是它仍然保存所有的状态和信息。当内存低的情况下,它将要被系统killed(杀死) |
| 销毁状态 | 该Activity结束,或Activity所在的Dalvik进程结束 |
在了解了Activity的4个重要状态后,我们来看图5.1(参照Android官方文档),该图显示了一个Activity的各种重要状态,以及相关的回调方法。
图5.1 Activity的生命周期及回调方法
在图5.1中,用矩形方块表示的内容为可以被回调的方法,而带底色的椭圆形则表示Activity的重要状态。从该图可以看出,在一个Activity的生命周期中有以下方法会被系统回调。
[√]onCreate()方法:在创建Activity时被回调。该方法是最常见的方法,在Eclipse中创建Android项目时,会自动创建一个Activity,在该Activity中,默认重写了onCreate(Bundle savedInstanceState)方法,用于对该Activity执行初始化。
[√]onStart()方法:启动Activity时被回调,也就是当一个Activity变为显示时被回调。
[√]onRestart()方法:重新启动Activity时被回调,该方法总是在onStart()方法以后执行。
[√]onPause()方法:暂停Activity时被回调。该方法需要被非常快速地执行,因为直到该方法执行完毕后,下一个Activity才能被恢复。在该方法中,通常用于持久保存数据。例如,当我们正在玩游戏时,突然来了一个电话,这时就可以在该方法中将游戏状态持久保存起来。
[√]onResume()方法:当Activity由暂停状态恢复为活动状态时调用。调用该方法后,该Activity位于Activity栈的栈顶。该方法总是在onPause()方法以后执行。
[√]onStop()方法:停止Activity时被回调。
[√]onDestroy()方法:销毁Activity时被回调。
说明:在Activity中,可以根据程序的需要来重写相应的方法。通常情况下,onCreate()和onPause()方法是最常用的,经常需要重写这两个方法。
5.2 创建、配置、启动和关闭Activity
教学录像:光盘\TM\lx\5\创建、启动和关闭Activity.exe
在Android中,Activity提供了与用户交互的可视化界面。在使用Activity时,需要先对其进行创建和配置,然后还可能需要启动或关闭Activity。下面将详细介绍创建、配置、启动和关闭Activity的方法。
5.2.1 创建Activity
创建Activity,大致可以分为以下两个步骤。
(1)创建一个Activity,一般是继承android.app包中的Activity类,不过在不同的应用场景下,也可以继承Activity的子类。例如,在一个Activity中,只想实现一个列表,那么就可以让该Activity继承ListActivity;如果只想实现选项卡效果,那么就可以让该Activity继承TabActivity。创建一个名为MainAcrivity的继承Activity类的Activity,具体代码如下:
- import android.app.Activity;
- public class MainActivity extends Activity {
- }
(2)重写需要的回调方法。通常情况下,都需要重写onCreate()方法,并且在该方法中调用setContentView()方法设置要显示的视图。例如,在步骤(1)中创建的Activity中,重写onCreate()方法,并且设置要显示的视图的具体代码如下:
- @Override
- public void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.main);
- }
说明:使用带ADT插件的Eclipse创建Android项目后,默认会创建一个Activity。该Activity继承Activity类,并且重写onCreate()方法。
5.2.2 配置Activity
创建Activity后,还需要在AndroidManifest.xml文件中进行配置,如果没有配置,而又在程序中启动了该Activity,那么将抛出如图5.2所示的异常信息。
图5.2 日志面板中抛出的异常信息
具体的配置方法是在<application></application>标记中添加<activity></activity>标记。<activity>标记的基本格式如下:
- <activity
- android:icon="@drawable/图标文件名"
- android:name="实现类"
- android:label="说明性文字"
- android:theme="要应用的主题"
- …
- >
- …
- </activity>
在<activity></activity>标记中,android:icon属性用于为Activity指定对应的图标,其中的图标文件名不包括扩展名;android:name属性用于指定对应的Activity实现类;android:label用于为该Activity指定标签;android:theme属性用于设置要应用的主题。
说明:如果该Activity类在<manifest>标记指定的包中,则android:name属性的属性值可以直接写类名,也可以加一个“.”点号;如果在<manifest>标记指定包的子包中,则属性值需要设置为“.子包序列.类名”或者是完整的类名(包括包路径)。
在AndroidManifest.xml文件中配置名称为DetailActivity的Activity,该类保存在<manifest>标记指定的包中,关键代码如下:
- <activity
- android:icon="@drawable/ic_launcher"
- android:name="DetailActivity"
- android:label="详细"
- >
- </activity>
5.2.3 启动和关闭Activity
- 启动Activity
在一个Android项目中,如果只有一个Activity,那么只需要在AndroidManifest.xml文件中对其进行配置,并且将其设置为程序的入口。这样,当运行该项目时,将自动启动该Activity。否则,需要应用startActivity()方法来启动需要的Activity。startActivity()方法的语法格式如下:
- public void startActivity (Intent intent)
该方法没有返回值,只有一个Intent类型的入口参数,Intent是Android应用里各组件之间的通信方式,一个Activity通过Intent来表达自己的“意图”。在创建Intent对象时,需要指定想要被启动的Activity。
说明:关于Intent的详细介绍请参见本书的第6章。
例如,要启动一个名称为DetailActivity的Activity,可以使用下面的代码:
- Intent intent = new Intent(MainActivity.this,DetailActivity.class);
- startActivity(intent);
- 关闭Activity
在Android中,如果想要关闭当前的Activity,可以使用Activity类提供的finish()方法。finish()方法的语法格式如下:
- public void finish ()
该方法的使用比较简单,既没有入口参数,也没有返回值,只需要在Activity中相应的事件中调用该方法即可。例如,想要在单击按钮时关闭该Activity,可以使用下面的代码:
- Button button1 = (Button)findViewById(R.id.button1);
- button1.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- finish(); //关闭当前Activity
- }
- });
说明:如果当前的Activity不是主活动,那么执行finish()方法后,将返回到调用它的那个Activity;否则,将返回到主屏幕中。
5.2.4 范例1:实现启动和关闭Activity
例5.1 在Eclipse中创建Android项目,名称为5.1,实现创建两个Activity,在第一个Activity中单击“查看详细内容”按钮,进入到第二个Activity中,单击“关闭”按钮,关闭当前的Activity,返回到第一个Activity中。(实例位置:光盘\TM\sl\5\5.1)
(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的TextView组件删除,然后添加一个“查看详细内容”按钮,android:id属性值为@+id/button1。由于此处的布局代码比较简单,这里不再给出。
(2)在包资源管理器的项目名称节点上单击鼠标右键,在弹出的快捷菜单中选择“新建”/“类”命令,在打开的“新建Java类”对话框的“包”文本框中输入包名,这里为com.mingrisoft;在“名称”文本框中输入类名,这里为DetailActivity;单击“超类”后面的“浏览”按钮,在打开的“选择类型”对话框中输入Activity后单击“确定”按钮,返回到“新建Java类”对话框中,单击“完成”按钮,完成Activity的创建,如图5.3所示。
图5.3 “新建Java类”对话框
(3)在res\layout目录中创建一个布局文件,名称为detail.xml,在该布局文件中添加垂直线性布局管理器,并在该布局管理器中添加一个TextView组件(用于显示提示文字)和一个Button组件(用于关闭当前Activity)。
(4)在DetailActivity中,重写onCreate()方法。在重写的onCreate()方法中,首先设置要使用的布局文件,然后获取“关闭”按钮,最后为该按钮添加单击事件监听器,在重写的onClick()方法中调用finish()方法,关闭当前Activity,具体代码如下:
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.detail); //设置布局文件
- Button button1 = (Button)findViewById(R.id.button1); //获取“关闭”按钮
- button1.setOnClickListener(new View.OnClickListener() {
@Overridepublic void onClick(View v) {finish(); //关闭当前Activity}});}
(5)打开默认创建的主活动MainActivity,在onCreate()方法中,获取“查看详细内容”按钮,并为其添加单击事件监听器,在重写的onClick()方法中,创建一个DetailActivity所对应的Intent对象,并调用startActivity()方法,启动DetailActivity,具体代码如下:
- Button button=(Button)findViewById(R.id.button1);
- button.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent = new Intent(MainActivity.this,DetailActivity.class); //创建Intent对象
- startActivity(intent); //启动Activity
- }
- });
(6)在AndroidManifest.xml文件中配置DetailActivity,配置的主要属性有Activity使用的图标、实现类和标签,具体代码如下:
- <activity
- android:icon="@drawable/ic_launcher"
- android:name=".DetailActivity"
- android:label="详细"
- >
- </activity>
运行本实例,将显示如图5.4所示的运行结果,单击“查看详细内容”按钮,将显示如图5.5所示的运行结果,单击“关闭”按钮,将返回到如图5.4所示的页面。
![]() | ![]() |
| 图5.4 第一个Activity的运行结果 | 图5.5 第二个Activity的运行结果 |
5.2.5 范例2:实现应用对话框主题的关于Activity
例5.2 在Eclipse中创建Android项目,名称为5.2,实现应用对话框主题的AboutActivity。(实例位置:光盘\TM\sl\5\5.2)
(1)修改新建项目的res\layout目录下的布局文件main.xml,应用线性布局和相对布局完成一个带“关于”按钮的游戏开始界面。该界面的设计代码与3.2.6节的例3.10的布局代码基本相同,这里不再给出,具体代码可以参见光盘。
(2)在com.mingrisoft包中,创建一个继承Activity类的AboutActivity,并且重写onCreate()方法。在重写的onCreate()方法中,首先创建一个线性布局管理器对象,并设置其内边距,然后创建一个TextView对象,并设置字体大小及要显示的内容,再将TextView添加到线性布局管理器中,最后设置在该Activity中显示线性布局管理器对象。关键代码如下:
- public class AboutActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- LinearLayout ll=new LinearLayout(this); //创建线性布局管理器对象
- ll.setPadding(20,20,20,20);
- TextView tv=new TextView(this); //创建TextView对象
- tv.setTextSize(24); //设置字体大小
- tv.setText(R.string.about); //设置要显示的内容
- ll.addView(tv); //将TextView添加到线性布局管理器中
- setContentView(ll); //设置该Activity显示的内容视图
- }
- }
说明:在上面的代码中,为TextView组件设置要显示的文本内容时,采用的是使用字符串资源的方法。这里就需要在项目的res\values目录下的strings.xml文件中添加一个名称为about的字符串变量,内容是要显示的关于信息。名称为about的变量的设置代码如下:
- <string name="about">泡泡龙游戏是一款十分流行的益智游戏。它可以从下方中央的弹珠发射台射出彩珠,当有多于3个同色弹珠相连时,这些弹珠将会爆掉,否则该弹珠被连接到指向的位置,直到泡泡下压越过下方的警戒线,游戏结束。</string>
(3)打开默认创建的主活动MainActivity,在onCreate()方法中,获取“关于”按钮并为其添加单击事件监听器,在重写的onClick()方法中,创建一个AboutActivity所对应的Intent对象,并调用startActivity()方法,启动AboutActivity,具体代码如下:
- ImageView about=(ImageView)findViewById(R.id.about); //获取“关于”按钮
- about.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent=new Intent(MainActivity.this, AboutActivity.class); //创建Intent对象
- startActivity(intent); //启动About Activity
- }
- });
(4)在AndroidManifest.xml文件中配置AboutActivity,配置的主要属性有Activity使用的图标、实现类、标签和使用的主题,具体代码如下:
- <activity
- android:icon="@drawable/ic_launcher"
- android:name=".AboutActivity"
- android:label="关于..."
- android:theme="@android:style/Theme.Dialog"
- >
- </activity>
说明:在<activity>标记中,为Activity设置主题时,除了上面设置的主题样式@android:style/The- me.Dialog外,还可以设置为@android:style/Theme.DeviceDefault.Light.Dialog、@android:style/Theme. Holo.Dialog、@android:style/Theme.DeviceDefault.Dialog或者@android:style/Theme. Holo.Light.Dia- log等。使用这些主题可以让该Activity采用不同的对话框样式。
运行本实例,将显示泡泡龙游戏的主界面,单击“关于”按钮,将显示如图5.6所示的“关于”对话框。
图5.6 “关于”对话框
5.3 多个Activity的使用
教学录像:光盘\TM\lx\5\多个Activity的使用.exe
在Android应用中,经常会有多个Activity,而这些Activity之间又经常需要交换数据。下面就来介绍如何使用Bundle在Activity之间交换数据,以及如何调用另一个Activity并返回结果。
5.3.1 使用Bundle在Activity之间交换数据
当在一个Activity中启动另一个Activity时,经常需要传递一些数据。这时就可以通过Intent来实现,因为Intent通常被称为是两个Activity之间的信使,通过将要传递的数据保存在Intent中,就可以将其传递到另一个Activity中了。
在Android中,可以将要保存的数据存放在Bundle对象中,然后通过Intent提供的putExtras()方法将要携带的数据保存到Intent中。下面通过一个具体的实例介绍如何使用Bundle在Activity之间交换数据。
说明:Bundle是一个字符串值到各种Parcelable类型的映射,用于保存要携带的数据包。
例5.3 在Eclipse中创建Android项目,名称为5.3,实现用户注册界面,并在单击“提交”按钮时,启动另一个Activity显示填写的注册信息。(实例位置:光盘\TM\sl\5\5.3)
(1)修改新建项目的res\layout目录下的布局文件main.xml,在默认添加的垂直线性布局管理器中,添加用于输入用户注册信息的文本框和编辑框以及一个“提交”按钮。由于此处的布局代码比较简单,这里不再给出,具体代码可以参见光盘。
(2)打开默认创建的主活动MainActivity,在onCreate()方法中,获取“提交”按钮,并为其添加单击事件监听器,在重写的onClick()方法中,首先获取输入的用户名、密码、确认密码和E-mail地址,并保存到相应的变量中,然后判断输入信息是否为空,如果为空给出提示框,否则判断两次输入的密码是否一致,如果不一致,将给出提示信息,并清空“密码”和“确认密码”编辑框,让“密码”编辑框获得焦点,否则,将输入的信息保存到Bundle中,并启动一个新的Activity显示输入的用户注册信息,具体代码如下:
- Button submit=(Button)findViewById(R.id.submit); //获取“提交”按钮
- submit.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- String user=((EditText)findViewById(R.id.user)).getText().toString(); //获取输入的用户名
- String pwd=((EditText)findViewById(R.id.pwd)).getText().toString(); //获取输入的密码
- String repwd=((EditText)findViewById(R.id.repwd)).getText().toString(); //获取输入的确认密码
- String email=((EditText)findViewById(R.id.email)).getText().toString(); //获取输入的E-mail地址
- if(!"".equals(user) && !"".equals(pwd) && !"".equals(email)){
- if(!pwd.equals(repwd)){ //判断两次输入的密码是否一致
- Toast.makeText(MainActivity.this, "两次输入的密码不一致,请重新输入!",
- Toast.LENGTH_LONG).show();
- ((EditText)findViewById(R.id.pwd)).setText(""); //清空“密码”编辑框
- ((EditText)findViewById(R.id.repwd)).setText(""); //清空“确认密码”编辑框
- ((EditText)findViewById(R.id.pwd)).requestFocus(); //让“密码”编辑框获得焦点
- }else{ //将输入的信息保存到Bundle中,并启动一个新的Activity显示输入的用户注册信息
- Intent intent=new Intent(MainActivity.this,RegisterActivity.class);
- Bundle bundle=new Bundle(); //创建并实例化一个Bundle对象
- bundle.putCharSequence("user", user); //保存用户名
- bundle.putCharSequence("pwd", pwd); //保存密码
- bundle.putCharSequence("email", email); //保存E-mail地址
- intent.putExtras(bundle); //将Bundle对象添加到Intent对象中
- startActivity(intent); //启动新的Activity
- }
- }else{
- Toast.makeText(MainActivity.this, "请将注册信息输入完整!", Toast.LENGTH_LONG).show();
- }
- }
- });
说明:在上面的代码中,加粗的代码用于创建Intent对象,并将要传递的用户注册信息通过Bundle对象添加到该Intent对象中。
(3)在res\layout目录中,创建一个名为register.xml的布局文件,在该布局文件中采用垂直线性布局管理器,并且添加3个TextView组件,分别用于显示用户名、密码和E-mail地址。
(4)在com.mingrisoft包中,创建一个继承Activity类的RegisterActivity,并且重写onCreate()方法。在重写的onCreate()方法中,首先设置该Activity使用的布局文件register.xml中定义的布局,然后获取Intent对象以及传递的数据包,最后将传递过来的用户名、密码和E-mail地址显示到对应的TextView组件中。关键代码如下:
- public class RegisterActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.register); //设置该Activity中要显示的内容视图
- Intent intent=getIntent(); //获取Intent对象
- Bundle bundle=intent.getExtras(); //获取传递的数据包
- TextView user=(TextView)findViewById(R.id.user); //获取显示用户名的TextView组件
- //获取输入的用户名并显示到TextView组件中
- user.setText("用户名:"+bundle.getString("user"));
- TextView pwd=(TextView)findViewById(R.id.pwd); //获取显示密码的TextView组件
- pwd.setText("密码:"+bundle.getString("pwd")); //获取输入的密码并显示到TextView组件中
- TextView email=(TextView)findViewById(R.id.email); //获取显示E-mail地址的TextView组件
- //获取输入的E-mail地址并显示到TextView组件中
- email.setText("E-mail:"+bundle.getString("email"));
- }
- }
说明:在上面的代码中,加粗的代码用于获取通过Intent对象传递的用户注册信息。
(5)在AndroidManifest.xml文件中配置AboutActivity,配置的主要属性有Activity使用的图标、实现类和标签,具体代码如下:
- <activity
- android:label="显示用户注册信息"
- android:icon="@drawable/ic_launcher"
- android:name=".RegisterActivity">
- </activity>
运行本实例,将显示一个填写用户注册信息的界面,输入用户名、密码、确认密码和E-mail地址后,如图5.7所示,单击“提交”按钮,将显示如图5.8所示的界面,显示填写的用户注册信息。
![]() | ![]() |
| 图5.7 填写用户注册信息界面 | 图5.8 显示用户注册信息界面 |
5.3.2 调用另一个Activity并返回结果
在Android应用开发时,有时需要在一个Activity中调用另一个Activity,当用户在第二个Activity中选择完成后,程序自动返回到第一个Activity中,第一个Activity必须能够获取并显示用户在第二个Activity中选择的结果;或者,在第一个Activity中将一些数据传递到第二个Activity,由于某些原因,又要返回到第一个Activity中,并显示传递的数据,如程序中经常出现的“返回上一步”功能。这时,也可以通过Intent和Bundle来实现。与在两个Acitivity之间交换数据不同的是,此处需要使用startActivityForResult()方法来启动另一个Activity。下面通过一个具体的实例介绍如何调用另一个Activity并返回结果。
说明:在5.3.1节中的例5.3中,已经介绍了填写用户注册信息界面及显示注册信息界面的实现方法,本实例将在例5.3的基础上进行修改,为其添加“返回上一步”功能。
例5.4 在Eclipse中,复制项目5.3,并修改项目名为5.4,实现用户注册中的“返回上一步”功能。(实例位置:光盘\TM\sl\5\5.4)
(1)打开MainActivity,定义一个名称为CODE的常量,用于设置requestCode请求码。该请求码由开发者根据业务自行设定,这里设置为0x717,关键代码如下:
- final int CODE= 0x717; //定义一个请求码常量
(2)将原来使用startActivity()方法启动新Activity的代码修改为使用startActivityForResult()方法实现,这样就可以在启动一个新的Activity时,获取指定Activity返回的结果。修改后的代码如下:
- startActivityForResult(intent, CODE); //启动新的Activity
(3)打开res\layout目录中的register.xml布局文件,在该布局文件中添加一个“返回上一步”按钮,并设置该按钮的android:id属性值为@+id/back,关键代码如下:
- <Button
- android:id="@+id/back"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="返回上一步" />
(4)打开RegisterActivity,在onCreate()方法中,获取“返回上一步”按钮,并为其添加单击事件监听器,在重写的onClick()方法中,首先设置返回的结果码,并返回调用该Activity的Activity,然后关闭当前Activity,关键代码如下:
- Button button=(Button)findViewById(R.id.back); //获取“返回上一步”按钮
- button.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- setResult(0x717,intent); //设置返回的结果码,并返回调用该Activity的Activity
- finish(); //关闭当前Activity
- }
- });
说明:为了让程序知道返回的数据来自于哪个新的Activity,需要使用resultCode结果码。
(5)再次打开MainActivity,重写onActivityResult()方法,在该方法中,需要判断requestCode请求码和resultCode结果码是否与预先设置的相同,如果相同,则清空“密码”编辑框和“确认密码”编辑框,关键代码如下:
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- if(requestCode==CODE && resultCode==CODE){
- ((EditText)findViewById(R.id.pwd)).setText(""); //清空“密码”编辑框
- ((EditText)findViewById(R.id.repwd)).setText(""); //清空“确认密码”编辑框
- }
- }
运行本实例,将显示一个填写用户注册信息的界面,输入用户名、密码、确认密码和E-mail地址后,如图5.7所示,单击“提交”按钮,将显示如图5.9所示的界面,显示填写的用户注册信息及一个“返回上一步”按钮,单击“返回上一步”按钮,即可返回到如图5.7所示的界面,只是没有显示密码和确认密码。
图5.9 显示用户注册信息及“返回上一步”按钮界面
5.3.3 范例1:实现根据身高计算标准体重
例5.5 在Eclipse中创建Android项目,名称为5.5,实现根据输入的性别和身高计算标准体重。(实例位置:光盘\TM\sl\5\5.5)
(1)修改新建项目的res\layout目录下的布局文件main.xml,在默认添加的垂直线性布局管理器中,添加用于选择性别信息的单选按钮组和用于输入身高的编辑框,以及一个“确定”按钮。由于此处的布局代码比较简单,这里不再给出,具体代码可以参见光盘。
(2)编写一个实现java.io.Serializable接口的Java类,在该类中创建两个变量,一个用于保存性别,另一个用于保存身高,并为这两个属性添加对应的setter()和getter()方法,关键代码如下:
- public class Info implements Serializable {
- private static final long serialVersionUID = 1L;
- private String sex=""; //性别
- private int stature=0; //身高
- public String getSex() {
- return sex;
- }
- public void setSex(String sex) {
- this.sex = sex;
- }
- … //此处省略了stature变量对应的setter()方法和getter()方法
- }
说明:在使用Bundle类传递数据包时,可以放入一个可序列化的对象。这样,当要传递的数据字段比较多时,采用该方法比较方便。在本实例中,为了在Bundle中放入一个可序列化的对象,我们创建了一个可序列化的Java类,方便存储可序列化对象。
(3)打开默认创建的主活动MainActivity,在onCreate()方法中,获取“确定”按钮,并为其添加单击事件监听器,在重写的onClick()方法中,实例化一个保存性别和身高的可序列化对象info,并判断输入的身高是否为空,如果为空,则给出消息提示并返回;否则,首先获取性别和身高并保存到info中,然后实例化一个Bundle对象,并将输入的身高和性别保存到Bundle对象中,接下来创建一个启动显示结果Activity的intent对象,并将bundle对象保存到该intent对象中,最后启动intent对应的Activity。关键代码如下:
- Button button=(Button)findViewById(R.id.button1);
- button.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Info info=new Info(); //实例化一个保存输入基本信息的对象
- if("".equals(((EditText)findViewById(R.id.stature)).getText().toString())){
- Toast.makeText(MainActivity.this, "请输入您的身高,否则不能计算!",
- Toast.LENGTH_SHORT).show();
- return;
- }
- int stature=Integer.parseInt(((EditText)findViewById(R.id.stature)).getText().toString());
- RadioGroup sex=(RadioGroup)findViewById(R.id.sex); //获取设置性别的单选按钮组
- //获取单选按钮组的值
- for(int i=0;i<sex.getChildCount();i++){
- RadioButton r=(RadioButton)sex.getChildAt(i); //根据索引值获取单选按钮
- if(r.isChecked()){ //判断单选按钮是否被选中
- info.setSex(r.getText().toString()); //获取被选中的单选按钮的值
- break; //跳出for循环
- }
- }
- info.setStature(stature); //设置身高
- Bundle bundle=new Bundle(); //实例化一个Bundle对象
- bundle.putSerializable("info", info); //将输入的基本信息保存到Bundle对象中
- Intent intent=new Intent(MainActivity.this,ResultActivity.class); //创建一个Intent对象
- intent.putExtras(bundle); //将bundle保存到Intent对象中
- startActivity(intent); //启动intent对应的Activity
- }
- });
说明:在上面的代码中,加粗的代码用于创建一个Bundle对象,并在该对象中放入一个可序列化的Info类的对象。
(4)在res\layout目录中,创建一个名为result.xml的布局文件,在该布局文件中采用垂直线性布局管理器,并且添加3个TextView组件,分别用于显示性别、身高和计算后的标准体重。
(5)在com.mingrisoft包中,创建一个继承Activity类的ResultActivity,并且重写onCreate()方法。在重写的onCreate()方法中,首先设置该Activity使用的布局文件result.xml中定义的布局,然后获取性别、身高和标准体重文本框,再获取Intent对象以及传递的数据包,最后将传递过来的性别、身高和计算后的标准体重显示到对应的文本框中。关键代码如下:
- setContentView(R.layout.result); //设置该Activity使用的布局
- TextView sex=(TextView)findViewById(R.id.sex); //获取显示性别的文本框
- TextView stature=(TextView)findViewById(R.id.stature); //获取显示身高的文本框
- TextView weight=(TextView)findViewById(R.id.weight); //获取显示标准体重的文本框
- Intent intent=getIntent(); //获取Intent对象
- Bundle bundle=intent.getExtras(); //获取传递的数据包
- Info info=(Info)bundle.getSerializable("info"); //获取一个可序列化的info对象
- sex.setText("您是一位"+info.getSex()+"士"); //获取性别并显示到相应文本框中
- stature.setText("您的身高是"+info.getStature()+"厘米"); //获取身高并显示到相应文本框中
- //显示计算后的标准体重
- weight.setText("您的标准体重是"+getWeight(info.getSex(),info.getStature())+"公斤");
(6)编写根据身高和性别计算标准体重的方法getWeight(),该方法包括两个入口参数:身高和体重,返回值为字符串类型的标准体重。getWeight()方法的具体代码如下:
- /**
- * 功能:计算标准体重
- * @param sex
- * @param stature
- * @return
- */
- private String getWeight(String sex,float stature){
- String weight=""; //保存体重
- NumberFormat format=new DecimalFormat();
- if(sex.equals("男")){ //计算男士标准体重
- weight=format.format((stature-80)*0.7);
- }else{ //计算女士标准体重
- weight=format.format((stature-70)*0.6);
- }
- return weight;
- }
(7)在AndroidManifest.xml文件中配置ResultActivity,配置的主要属性有Activity使用的标签、图标和实现类,具体代码如下:
- <activity
- android:label="显示结果"
- android:icon="@drawable/ic_launcher"
- android:name=".ResultActivity">
- </activity>
运行本实例,将显示一个输入计算标准体重条件的界面,选择性别并输入身高后,如图5.10所示,单击“确定”按钮,将显示如图5.11所示的计算结果界面。
![]() | ![]() |
| 图5.10 输入性别和身高界面 | 图5.11 显示计算结果界面 |
5.3.4 范例2:带选择头像的用户注册页面
例5.6 在Eclipse中创建Android项目,名称为5.6,实现带选择头像的用户注册页面,打开新的Activity选择头像,并将选择的头像返回到原Activity中。(实例位置:光盘\TM\sl\5\5.6)
(1)修改新建项目的res\layout目录下的布局文件main.xml,将默认添加的垂直线性布局管理器修改为水平线性布局管理器,并将默认添加的TextView组件删除,然后添加两个垂直线性布局管理器,并在第一个线性布局管理器中添加一个4行的表格布局管理器,在第二个线性布局管理器中添加一个ImageView组件和一个Button组件,最后在表格布局管理器的各行中添加用于输入用户名、密码和E-mail地址等的TextView组件和EditText组件。由于此处的布局代码比较简单,这里不再给出,具体代码可以参见光盘。
(2)打开默认创建的主活动MainActivity,在onCreate()方法中,获取“选择头像”按钮,并为其添加单击事件监听器,在重写的onClick()方法中,创建一个要启动的Activity对应的Intent对象,并应用startActivityForResult()方法启动指定的Activity并等待返回结果,具体代码如下:
- Button button=(Button)findViewById(R.id.button1); //获取“选择头像”按钮
- button.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- Intent intent=new Intent(MainActivity.this,HeadActivity.class);
- startActivityForResult(intent, 0x11); //启动指定的Activity
- }
- });
(3)在res\layout目录中,创建一个名为head.xml的布局文件,在该布局文件中采用垂直线性布局管理器,并且添加一个GridView组件,用于显示可选择的头像列表,关键代码如下:
- <GridView android:id="@+id/gridView1"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:layout_marginTop="10px"
- android:horizontalSpacing="3px"
- android:verticalSpacing="3px"
- android:numColumns="4"
- />
(4)在com.mingrisoft包中,创建一个继承Activity类的HeadActivity,并且重写onCreate()方法。然后定义一个保存要显示头像id的一维数组,关键代码如下:
- public int[] imageId = new int[] { R.drawable.img01, R.drawable.img02,
- R.drawable.img03, R.drawable.img04, R.drawable.img05,
- R.drawable.img06, R.drawable.img07, R.drawable.img08,
- R.drawable.img09
- }; //定义并初始化保存头像id的数组
(5)在重写的onCreate()方法中,首先设置该Activity使用布局文件head.xml中定义的布局,然后获取GridView组件,并创建一个与之关联的BaseAdapter适配器,关键代码如下:
- setContentView(R.layout.head); //设置该Activity使用的布局
- GridView gridview = (GridView) findViewById(R.id.gridView1); //获取GridView组件
- BaseAdapter adapter=new BaseAdapter() {
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- ImageView imageview; //声明ImageView的对象
- if(convertView==null){
- imageview=new ImageView(HeadActivity.this); //实例化ImageView的对象
- /*************设置图像的宽度和高度******************/
- imageview.setAdjustViewBounds(true);
- imageview.setMaxWidth(158);
- imageview.setMaxHeight(150);
- /**************************************************/
- imageview.setPadding(5, 5, 5, 5); //设置ImageView的内边距
- }else{
- imageview=(ImageView)convertView;
- }
- imageview.setImageResource(imageId[position]); //为ImageView设置要显示的图片
- return imageview; //返回ImageView
- }
- /*
- * 功能:获得当前选项的id
- */
- @Override
- public long getItemId(int position) {
- return position;
- }
- /*
- * 功能:获得当前选项
- */
- @Override
- public Object getItem(int position) {
- return position;
- }
- /*
- * 获得数量
- */
- @Override
- public int getCount() {
- return imageId.length;
- }
- };
- gridview.setAdapter(adapter); //将适配器与GridView关联
(6)为GridView添加OnItemClickListener事件监听器,在重写的onItemClick()方法中,首先获取Intent对象,然后创建一个要传递的数据包,并将选中的头像id保存到该数据包中,再将要传递的数据包保存到intent中,并设置返回的结果码及返回的Activity,最后关闭当前Activity。关键代码如下:
- gridview.setOnItemClickListener(new OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position,long id) {
- Intent intent=getIntent(); //获取Intent对象
- Bundle bundle=new Bundle(); //实例化传递的数据包
- bundle.putInt("imageId",imageId[position] ); //显示选中的图片
- intent.putExtras(bundle); //将数据包保存到intent中
- setResult(0x11,intent); //设置返回的结果码,并返回调用该Activity的Activity
- finish(); //关闭当前Activity
- }
- });
(7)重新打开MainActivity,在该类中,重写onActivityResult()方法,在该方法中,需要判断requestCode请求码和resultCode结果码是否与预先设置的相同,如果相同,则获取传递的数据包,并从该数据包中获取选择的头像id并显示。具体代码如下:
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- if(requestCode==0x11 && resultCode==0x11){ //判断是否为待处理的结果
- Bundle bundle=data.getExtras(); //获取传递的数据包
- int imageId=bundle.getInt("imageId"); //获取选择的头像id
- //获取布局文件中添加的ImageView组件
- ImageView iv=(ImageView)findViewById(R.id.imageView1);
- iv.setImageResource(imageId); //显示选择的头像
- }
- }
(8)在AndroidManifest.xml文件中配置HeadActivity,配置的主要属性有Activity使用的标签、图标和实现类,具体代码如下:
- <activity
- android:label="选择头像"
- android:icon="@drawable/ic_launcher"
- android:name=".HeadActivity">
- </activity>
运行本实例,将显示一个填写用户注册信息的界面,输入用户名、密码、确认密码和E-mail地址后,单击“选择头像”按钮,将打开如图5.12所示的选择头像界面,单击想要的头像,将返回到填写用户注册信息界面,如图5.13所示。
图5.12 选择头像界面
图5.13 填写用户注册信息界面
5.4 使用Fragment
教学录像:光盘\TM\lx\5\使用Fragment.exe
Fragment是Android 3.0新增的概念,其中文意思是碎片,它与Activity十分相似,用来在一个Activity中描述一些行为或一部分用户界面。使用多个Fragment可以在一个单独的Activity中建立多个UI面板,也可以在多个Activity中重用Fragment。
一个Fragment必须被嵌入到一个Activity中,它的生命周期直接受其所属的宿主Activity的生命周期影响。例如,当Activity被暂停时,其中的所有Fragment也被暂停;当Activity被销毁时,所有隶属于它的Fragment也将被销毁。然而,当一个Activity处于resumed状态(正在运行)时,可以单独地对每一个Fragment进行操作,如添加或删除等。
5.4.1 创建Fragment
要创建一个Fragment,必须创建一个Fragment的子类,或者继承自另一个已经存在的Fragment的子类。例如,要创建一个名称为NewsFragment的Fragment,并重写onCreateView()方法,可以使用下面的代码:
- public class NewsFragment extends Fragment {
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- //从布局文件news.xml 加载一个布局文件
- View v = inflater.inflate(R.layout.news, container, true);
- return v;
- }
- }
说明:当系统首次调用Fragment时,如果想绘制一个UI界面,那么在Fragment中,必须重写onCreateView()方法返回一个View;否则,如果Fragment没有UI界面,可以返回null。
5.4.2 在Activity中添加Fragment
向Activity中添加Fragment,有两种方法;一种是直接在布局文件中添加,将Fragment作为Activity整个布局的一部分;另一种是当Activity运行时,将Fragment放入Activity布局中。下面分别进行介绍。
- 直接在布局文件中添加Fragment
直接在布局文件中添加Fragment可以使用<fragment></fragment>标记实现。例如,要在一个布局文件中添加两个Fragment,可以使用下面的代码:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:orientation="horizontal" >
- <fragment android:name="com.mingrisoft.ListFragment"
- android:id="@+id/list"
- android:layout_weight="1"
- android:layout_width="0dp"
- android:layout_height="match_parent" />
- <fragment android:name="com.mingrisoft.DetailFragment"
- android:id="@+id/detail"
- android:layout_weight="2"
- android:layout_marginLeft="20px"
- android:layout_width="0dp"
- android:layout_height="match_parent" />
- </LinearLayout>
说明:在<fragment></fragment>标记中,android:name属性用于指定要添加的Fragment。
- 当Activity运行时添加Fragment
当Activity运行时,也可以将Fragment添加到Activity的布局中,实现方法是获取一个FragmentTransaction的实例,然后使用add()方法添加一个Fragment,add()方法的第一个参数是Fragment要放入的ViewGroup(由Resource ID指定),第二个参数是需要添加的Fragment,最后为了使改变生效,还必须调用commit()方法提交事务。例如,要在Activity运行时添加一个名称为DetailFragment的Fragment,可以使用下面的代码:
- DetailFragment details = new DetailFragment(); //实例化DetailFragment的对象
- FragmentTransaction ft = getFragmentManager()
- .beginTransaction(); //获得一个FragmentTransaction的实例
- ft.add(android.R.id.content, details).commit(); //添加一个显示详细内容的Fragment
- ft.commit(); //提交事务
Fragment比较强大的功能之一就是可以合并两个Activity,从而让这两个Activity在一个屏幕上显示。如图5.14所示(参照Android官方文档),左边的两个图分别代表两个Activity,右边的图表示包括两个Fragment的Activity,其中第一个Fragment的内容是Activity A,第二个Fragment的内容是Activity B。
图5.14 使用Fragment合并两个Activity
下面通过一个具体的实例介绍如何使用Fragment合并两个Activity,从而实现在一个屏幕上显示标题列表及选定标题对应的详细内容。
例5.7 在Eclipse中创建Android项目,名称为5.7,实现在一个屏幕上显示标题列表及选定标题对应的详细内容。(实例位置:光盘\TM\sl\5\5.7)
(1)创建布局文件。为了让该程序既支持横屏,又支持竖屏,所以需要创建两个布局文件,分别是在res\layout目录中创建的main.xml和在res\layout-land目录中创建的main.xml。其中在layout目录中创建的main.xml是支持手机时用的布局文件,在该文件中,只包括一个Fragment;在layout-land目录中创建的是支持平板电脑时用的布局文件,在该文件中,需要在水平线性布局管理器中添加一个Fragment和一个FrameLayout。在layout-land目录中创建的main.xml的具体代码如下:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="match_parent">
- <fragment class="com.mingrisoft.ListFragment"
- android:id="@+id/titles"
- android:layout_weight="1"
- android:layout_width="0px"
- android:layout_height="match_parent" />
- <FrameLayout android:id="@+id/detail"
- android:layout_weight="2"
- android:layout_width="0px"
- android:layout_height="match_parent"
- android:background="?android:attr/detailsElementBackground" />
- </LinearLayout>
说明:在上面的代码中,加粗的代码同在layout目录中添加的main.xml中的代码是完全一样的。
(2)创建一个名称为Data的final类,在该类中创建两个静态的字符串数组常量,分别用于保存标题和详细内容。Data类的关键代码如下:
- public final class Data {
- //标题
- public static final String[] TITLES = {
- "线性布局",
- "表格布局",
- "帧布局",
- "相对布局"
- };
- //详细内容
- public static final String[] DETAIL = {
- "线性布局是将放入其中的组件按照垂直或水平方向来布局,也就是控制放入其中的组件横向排列或纵向排列。" +
- "在线性布局中,每一行(针对垂直排列)或每一列(针对水平排列)中只能放一个组件。" +
- "并且Android的线性布局不会换行,当组件一个挨着一个排列到窗体的边缘后,剩下的组件将不会被显示出来。",
- //此处省略了部分代码
- };
- }
(3)创建一个继承自ListFragment的ListFragment,用于显示一个标题列表,并且设置当选中其中的一个列表项时,显示对应的详细内容(如果为横屏,则创建一个DetialFragment的实例来显示,否则创建一个Activity来显示)。ListFragment类的具体代码如下:
- public class ListFragment extends android.app.ListFragment {
- boolean dualPane; //是否在一屏上同时显示列表和详细内容
- int curCheckPosition = 0; //当前选择的索引位置
- @Override
- public void onActivityCreated(Bundle savedInstanceState) {
- super.onActivityCreated(savedInstanceState);
- setListAdapter(new ArrayAdapter<String>(getActivity(),
- android.R.layout.simple_list_item_checked, Data.TITLES)); //为列表设置适配器
- //获取布局文件中添加的FrameLayout帧布局管理器
- View detailFrame = getActivity().findViewById(R.id.detail);
- dualPane = detailFrame != null &&
- detailFrame.getVisibility() == View.VISIBLE; //判断是否在一屏上同时显示列表和详细内容
- if (savedInstanceState != null) {
- curCheckPosition = savedInstanceState.getInt("curChoice", 0); //更新当前选择的索引位置
- }
- if (dualPane) { //如果在一屏上同时显示列表和详细内容
- getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE); //设置列表为单选模式
- showDetails(curCheckPosition); //显示详细内容
- }
- }
- //重写onSaveInstanceState()方法,保存当前选中的列表项的索引值
- @Override
- public void onSaveInstanceState(Bundle outState) {
- super.onSaveInstanceState(outState);
- outState.putInt("curChoice", curCheckPosition);
- }
- //重写onListItemClick()方法
- @Override
- public void onListItemClick(ListView l, View v, int position, long id) {
- showDetails(position); //调用showDetails()方法显示详细内容
- }
- void showDetails(int index) {
- curCheckPosition = index; //更新保存当前索引位置的变量的值为当前选中值
- if (dualPane) { //当在一屏上同时显示列表和详细内容时
- getListView().setItemChecked(index, true); //设置选中列表项为选中状态
- DetailFragment details = (DetailFragment) getFragmentManager()
- .findFragmentById(R.id.detail); //获取用于显示详细内容的Fragment
- if (details == null || details.getShownIndex() != index) {
- //创建一个新的DetailFragment实例,用于显示当前选择项对应的详细内容
- details = DetailFragment.newInstance(index);
- //要在activity中管理fragment, 需要使用FragmentManager
- FragmentTransaction ft = getFragmentManager()
- .beginTransaction(); //获得一个FragmentTransaction的实例
- ft.replace(R.id.detail, details); //替换原来显示的详细内容
- ft.setTransition(FragmentTransaction.TRANSIT_FRAGMENT_FADE); //设置转换效果
- ft.commit(); //提交事务
- }
- } else { //在一屏上只能显示列表或详细内容中的一个内容时
- //使用一个新的Activity显示详细内容
- Intent intent = new Intent(getActivity(),MainActivity.DetailActivity.class); //创建一个Intent对象
- intent.putExtra("index", index); //设置一个要传递的参数
- startActivity(intent); //开启一个指定的Activity
- }
- }
- }
(4)创建一个继承自Fragment的DetailFragment,用于显示选中标题对应的详细内容。在该类中,首先创建一个DetailFragment的新实例,其中包括要传递的数据包,然后编写一个名称为getShownIndex()的方法,用于获取要显示的列表项的索引,最后再重写onCreateView()方法,设置要显示的内容。DetailFragment类的具体代码如下:
- public class DetailFragment extends Fragment {
- //创建一个DetailFragment的新实例,其中包括要传递的数据包
- public static DetailFragment newInstance(int index) {
- DetailFragment f = new DetailFragment();
- //将index作为一个参数传递
- Bundle bundle = new Bundle(); //实例化一个Bundle对象
- bundle.putInt("index", index); //将索引值添加到Bundle对象中
- f.setArguments(bundle); //将bundle对象作为Fragment的参数保存
- return f;
- }
- public int getShownIndex() {
- return getArguments().getInt("index", 0); //获取要显示的列表项索引
- }
- @Override
- public View onCreateView(LayoutInflater inflater, ViewGroup container,
- Bundle savedInstanceState) {
- if (container == null) {
- return null;
- }
- ScrollView scroller = new ScrollView(getActivity()); //创建一个滚动视图
- TextView text = new TextView(getActivity()); //创建一个文本框对象
- text.setPadding(10, 10, 10, 10); //设置内边距
- scroller.addView(text); //将文本框对象添加到滚动视图中
- text.setText(Data.DETAIL[getShownIndex()]); //设置文本框中要显示的文本
- return scroller;
- }
- }
(5)打开默认创建的MainActivity,在该类中创建一个内部类,用于在手机界面中通过Activity显示详细内容,具体代码如下:
- //创建一个继承Activity的内部类,用于在手机界面中通过Activity显示详细内容
- public static class DetailActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- //判断是否为横屏,如果为横屏,则结束当前Activity,准备使用Fragment显示详细内容
- if (getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
- finish(); //结束当前Activity
- return;
- }
- if (savedInstanceState == null) {
- //在初始化时插入一个显示详细内容的Fragment
- DetailFragment details = new DetailFragment(); //实例化DetailFragment的对象
- details.setArguments(getIntent().getExtras()); //设置要传递的参数
- getFragmentManager().beginTransaction()
- .add(android.R.id.content, details).commit(); //添加一个显示详细内容的Fragment
- }
- }
- }
(6)在AndroidManifest.xml文件中配置DetailActivity,配置的主要属性有Activity使用的标签和实现类,具体代码如下:
- <activity
- android:name=".MainActivity$DetailActivity"
- android:label="详细内容" />
说明:由于DetailActivity是在MainActivity中定义的内部类,所以在AndroidManifest.xml文件中配置时,指定的android:name属性应该是.MainActivity$DetailActivity,而不能直接写成.DetailActivity或不进行配置。
运行本实例,在屏幕的左侧将显示一个标题列表,右侧将显示左侧选中标题对应的详细内容。例如,在左侧选中“表格布局”列表项,将显示如图5.15所示的运行结果。
图5.15 在一个屏幕上显示标题列表及选定标题对应的详细内容
5.5 经典范例
5.5.1 仿QQ客户端登录界面
例5.8 在Eclipse中创建Android项目,名称为5.8,实现在第一个Activity中显示登录界面,输入正确的账号和密码后,启动另一个Activity显示当前登录用户的昵称。(实例位置:光盘\TM\sl\5\5.8)
(1)在res\layout目录下创建布局文件login.xml,在该文件中应用表格布局完成用户登录界面,包括用于输入登录账号的编辑框和输入密码的编辑框。由于该布局文件的内容同第3章的例3.6类似,所以这里不再给出,具体代码请参见光盘。
(2)在com.mingrisoft包中创建一个final类,在该类中创建一个保存用户信息的常量数组,具体代码如下:
- public final class Data {
- //用户信息
- public static final String[][] USER = {
- {"1001","111","明日"},
- {"1002","111","mrsoft"},
- {"1003","111","wgh"}
- };
- }
(3)在com.mingrisoft包中,创建一个继承android.app.Activity的LoginActivity,并重写onCreate()方法,在重写的onCreate()方法中,首先获取“登录”按钮,并为其添加单击事件监听器,在重写的onClick()方法中,获取输入的账号和密码,并判断账号和密码是否正确,如果正确,将对应的昵称保存到Intent中,并启动主界面MainActivity,然后获取“退出”按钮,并为其添加单击事件监听器,在重写的onClick()方法中,应用finish()方法,关闭当前Activity。关键代码如下:
- public class LoginActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.login); //设置该Activity使用的布局
- Button button=(Button)findViewById(R.id.login);
- button.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- String number=((EditText)findViewById(R.id.editText1)).getText().toString();
- String pwd=((EditText)findViewById(R.id.editText2)).getText().toString();
- boolean flag=false; //用于记录登录是否成功的标记变量
- String nickname=""; //保存昵称的变量
- //通过遍历数据的形式判断输入的账号和密码是否正确
- for(int i=0;i<Data.USER.length;i++){
- if(number.equals(Data.USER[i][0])){ //判断账号是否正确
- if(pwd.equals(Data.USER[i][1])){ //判断密码是否正确
- nickname=Data.USER[i][2]; //获取昵称
- flag=true; //将标志变量设置为true
- break; //跳出for循环
- }
- }
- }
- if(flag){
- //创建要显示Activity对应的Intent对象
- Intent intent=new Intent(LoginActivity.this,MainActivity.class);
- Bundle bundle=new Bundle(); //创建一个Bundle的对象bundle
- bundle.putString("nickname", nickname); //保存昵称
- intent.putExtras(bundle); //将数据包添加到intent对象中
- startActivity(intent); //开启一个新的Activity
- }else{
- Toast.makeText(LoginActivity.this,
- "您输入的账号或密码错误!", Toast.LENGTH_SHORT);
- }
- }
- });
- Button exit=(Button)findViewById(R.id.exit);
- exit.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- finish(); //关闭当前Activity
- }
- });
- }
- }
(4)打开默认创建的main.xml文件,将默认添加的TextView组件删除,然后添加一个水平线性布局管理器和一个ListView组件,并且在线性布局管理器中添加一个id为nickname的TextView组件和一个id为m_exit的Button组件。关键代码如下:
- <LinearLayout
- android:id="@+id/linearLayout2"
- android:orientation="horizontal"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
- <TextView
- android:id="@+id/nickname"
- android:layout_width="wrap_content"
- android:layout_weight="9"
- android:textSize="24px"
- android:padding="20px"
- android:layout_height="wrap_content"
- android:text="TextView" />
- <Button
- android:id="@+id/m_exit"
- android:layout_weight="1"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:text="退出登录" />
- </LinearLayout>
- <ListView
- android:id="@+id/listView1"
- android:entries="@array/option"
- android:layout_width="match_parent"
- android:layout_height="wrap_content">
- </ListView>
说明:在上面的代码中,加粗的代码用于通过数组资源为ListView组件设置要显示的列表项。所以还需要在res\value目录中创建一个定义数组资源的XML文件arrays.xml,并在该文件中添加名称为option的字符串数组,关键代码如下:
- <resources>
- <string-array name="option">
- <item>在线好友</item>
- <item>我的好友</item>
- <item>陌生人</item>
- <item>黑名单</item>
- </string-array>
- </resources>
(5)打开默认添加的MainActivity,在onCreate()方法中,首先获取Intent对象以及传递的数据包,然后通过该数据包获取传递的昵称,再获取显示登录用户昵称的TextView组件,并通过该组件显示登录用户的昵称,最后获取“退出登录”按钮,并为其添加单击事件监听器,在重写的onClick()方法中,关闭当前Activity。关键代码如下:
- Intent intent=getIntent(); //获取Intent对象
- Bundle bundle=intent.getExtras(); //获取传递的数据包
- String nickname=bundle.getString("nickname"); //获取传递过来的昵称
- TextView tv=(TextView)findViewById(R.id.nickname); //获取用于显示当前登录用户的TextView组件
- tv.setText("当前登录:"+nickname); //显示当前登录用户的昵称
- Button button=(Button)findViewById(R.id.m_exit); //获取“退出登录”按钮
- button.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- finish(); //关闭当前Activity
- }
- });
(6)打开AndroidManifest.xml文件,修改默认的配置代码。在该文件中,首先修改入口Activity,这里修改为LoginActivity,并为其设置android:theme属性,然后配置MainActivity。修改后的关键代码如下:
- <activity
- android:label="@string/app_name"
- android:theme="@android:style/Theme.Dialog"
- android:name=".LoginActivity" >
- <intent-filter >
- <action android:name="android.intent.action.MAIN" />
- <category android:name="android.intent.category.LAUNCHER" />
- </intent-filter>
- </activity>
- <activity
- android:name=".MainActivity"
- android:label="主界面" />
运行本实例,在屏幕上将显示一个登录对话框,输入账号和密码后,如图5.16所示,单击“登录”按钮,将判断输入的账号和密码是否正确,如果正确,将打开如图5.17所示的主界面,在该界面中,将显示当前登录用户的昵称和“退出登录”按钮,单击“退出登录”按钮,将返回到如图5.16所示的用户登录界面。
![]() | ![]() |
| 图5.16 登录界面 | 图5.17 显示昵称的主界面 |
5.5.2 带查看原图功能的图像浏览器
例5.9 在Eclipse中创建Android项目,名称为5.9,实现在第一个Activity中显示图片缩略图,单击任意图片时,启动另一个Activity显示该图片的原图。(实例位置:光盘\TM\sl\5\5.9)
(1)修改新建项目的res\layout目录下的布局文件main.xml,在默认添加的垂直线性布局管理器中,将默认添加的TextView组件删除,然后添加一个用于显示图片缩略图的GridView,并设置该组件的顶上边距、水平间距、垂直间距和列数,关键代码如下:
- <GridView android:id="@+id/gridView1"
- android:layout_height="match_parent"
- android:layout_width="match_parent"
- android:layout_marginTop="10px"
- android:horizontalSpacing="3px"
- android:verticalSpacing="3px"
- android:numColumns="4"
- />
(2)在主活动MainActivity中,定义一个用于保存要显示图片id的数组(需要将要显示的图片复制到res\drawable文件夹中),关键代码如下:
- public int[] imageId = new int[] { R.drawable.img01, R.drawable.img02,
- R.drawable.img03, R.drawable.img04, R.drawable.img05,
- R.drawable.img06, R.drawable.img07, R.drawable.img08,
- R.drawable.img09, R.drawable.img10, R.drawable.img11,
- R.drawable.img12}; //定义并初始化保存图片id的数组
(3)在主活动MainActivity的onCreate()方法中,首先获取布局文件中添加的GridView组件,然后创建BaseAdapter类的对象,并重写其中的getView()、getItemId()、getItem()和getCount()方法,其中最主要的是重写getView()方法来设置显示图片的格式,最后将该适配器与GridView关联,并且为了在用户单击某张图片时启动新的Activity显示图片的原图,还需要为GridView添加单击事件监听器,在重写的onItemClick()方法中,将选择图片的id保存到Bundle中,并启动一个新的Activity显示对应的图片原图。关键代码如下:
- GridView gridview = (GridView) findViewById(R.id.gridView1); //获取GridView组件
- BaseAdapter adapter = new BaseAdapter() {
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- ImageView imageview; //声明ImageView的对象
- if (convertView == null) {
- imageview = new ImageView(MainActivity.this); //实例化ImageView的对象
- /************* 设置图像的宽度和高度 ******************/
- imageview.setAdjustViewBounds(true);
- imageview.setMaxWidth(180);
- imageview.setMaxHeight(135);
- /**************************************************/
- imageview.setPadding(5, 5, 5, 5); //设置ImageView的内边距
- } else {
- imageview = (ImageView) convertView;
- }
- imageview.setImageResource(imageId[position]); //为ImageView设置要显示的图片
- return imageview; //返回ImageView
- }
- /*
- * 功能:获得当前选项的id
- */
- @Override
- public long getItemId(int position) {
- return position;
- }
- /*
- * 功能:获得当前选项
- */
- @Override
- public Object getItem(int position) {
- return position;
- }
- /*
- * 获得数量
- */
- @Override
- public int getCount() {
- return imageId.length;
- }
- };
- gridview.setAdapter(adapter); //将适配器与GridView关联
- gridview.setOnItemClickListener(new OnItemClickListener() {
- @Override
- public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
- Intent intent = new Intent(MainActivity.this, BigActivity.class);
- Bundle bundle = new Bundle(); //创建并实例化一个Bundle对象
- bundle.putInt("imgId", imageId[position]); //保存图片id
- intent.putExtras(bundle); //将Bundle对象添加到intent对象中
- startActivity(intent); //启动新的Activity
- }
- });
说明:在上面的代码中,加粗的代码用于创建Intent对象,并将选择的图片id通过Bundle对象添加到该Intent对象中。
(4)在res\layout目录中,创建一个名为big.xml的布局文件,在该布局文件中采用垂直线性布局,并且添加一个用于显示图片原图的ImageView和返回按钮Button。具体代码请参见光盘。
(5)在com.mingrisoft包中,创建一个继承Activity类的BigActivity,并且重写onCreate()方法。在重写的onCreate()方法中,首先设置该Activity使用布局文件big.xml中定义的布局,然后获取Intent对象以及传递的数据包,再获取布局文件中添加的ImageView组件,并将传递过来的图片id作为该组件的图片源显示,最后获取“返回”按钮,并为其添加单击事件监听器,在重写的onClick()方法中,应用finish()方法关闭当前Activity。关键代码如下:
- public class BigActivity extends Activity {
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.big); //设置使用的布局文件
- Intent intent=getIntent(); //获取Intent对象
- Bundle bundle=intent.getExtras(); //获取传递过来的数据包
- int imgId=bundle.getInt("imgId");
- ImageView iv=(ImageView)findViewById(R.id.imageView1);
- iv.setImageResource(imgId); //设置要显示的图片
- Button button=(Button)findViewById(R.id.button1); //获取“返回”按钮
- button.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- finish(); //返回
- }
- });
- }
- }
(6)在AndroidManifest.xml文件中配置用于显示大图片的BigActivity,配置的主要属性有Activity使用的标签和实现类,具体代码如下:
- <activity
- android:name=".BigActivity"
- android:label="原图" />
运行本实例,在屏幕上将显示如图5.18所示的图片缩略图,单击任意图片,可以显示该图片的原始图像。例如,单击第2行第3列的图片,将显示如图5.19所示的界面。
![]() | ![]() |
| 图5.18 在第一个Activity上显示图片缩略图 | 图5.19 在第二个Activity上显示图片原图 |
5.6 小 结
本章主要介绍了Android应用的重要组成单元——Activity。首先介绍了如何创建、启动和关闭单一的Activity,实际上,在应用Eclipse创建Android项目时,就已经默认创建并配置了一个Activity,如果只需一个Activity,直接使用即可。然后介绍了多个Activity的使用,主要包括如何在两个Activity之间交换数据和如何调用另一个Activity并返回结果。接着介绍了可以合并多个Activity的Fragment,最后列举了两个实用的经典范例,来巩固前面所学的知识。
5.7 实践与练习
编写Android程序,实现根据输入的生日判断星座。(答案位置:光盘\TM\sl\5\5.10)
编写Android程序,实现带选择所在城市的用户注册。(答案位置:光盘\TM\sl\5\5.11)
