组件的实际应用
既然按钮有了资源ID,就可以在QuizActivity中直接获取它们。首先,在QuizActivity.java文件中增加两个成员变量,如下所示:
public class QuizActivity extends Activity { private Button mTrueButton; private Button mFalseButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_quiz); } ... }
代码清单1-8:添加成员变量(QuizActivity.java)
文件保存后,可看到两个错误提示。请注意新增的两个成员(实例)变量名称的m前缀。该前缀是Android编程所遵循的命名约定,本书将始终遵循该约定。
现在,请将鼠标移至代码左边的错误提示处,可看到两条同样的错误:Button cannot be resolved to a type。
该错误提示告诉我们需要在QuizActivity.java文件中导入android.widget.Button类包。可在文件头部手动输入以下代码:
import android.widget.Button
或者采用虾米那介绍的便捷方式自动导入。
类包组织导入
用类包组织导入,就是让Eclipse依据代码来决定应该导入哪些Java或Android SDK类包。如果之前导入的类包不再需要了,Eclipse也会自动删除它们。
通过以下组合键命令,进行类包组织导入:
Command+Shift+O(Mac系统);
Ctrl+Shift+O(Windows和Linux系统)。
类包导入完成后,刚才的错误提示应该就会消失了。(如果错误提示仍然存在,请检查Java代码以及XML文件,确认是否存在输入或拼写错误。)
接下来,我们来编码使用按钮组件,这需要以下两个步骤:
引用生成的视图对象;
为对象设置监听器,以响应用户操作。
应用组件
在activity中,可通过以下Activity方法引用已生成的组件:
public View findViewById( int id )
该方法接受组件的资源ID作为参数,返回一个视图对象。
在QuizActivity.java文件中,使用按钮的资源ID获取生成的对象后,赋值给对应的成员变量,如代码清单1-9所示。注意,赋值前,必须先将返回的View转型(cast)为Button。
public class QuizActivity extends Activity { private Button mTrueButton; private Button mFalseButton; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_quiz); mTrueButton = (Button)findViewById( R.id.true_button ); mFalseButton = (Button)findViewById( R.id.false_button ); }
代码清单1-9:引用组件(QuizActivity.java)
设置监听器
Android应用属于典型的事件驱动类型。不同于命令行或脚本程序,事件驱动型应用启动后,即开始等待行为事件的发生,如用户单击某个按钮。(事件也可以由操作系统或其他应用触发,但用户触发的事件更显而易见。)
应用等待某个特定事件的发生,也可以说该应用正在“监听”特定事件。为响应某个事件而创建的对象叫做监听器(listener)。监听器是实现特定监听器接口的对象,用来监听某类事件的发生。
Android SDK已经为各种事件内置开发了很多监听器接口。当前应用需要监听用户的按钮“单击”事件,因此监听器需实现View.OnClickListener接口。
首先处理True按钮,如下代码所示:
@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_quiz); mTrueButton = (Button)findViewById( R.id.true_button ); mTrueButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick( View v ) { // Does nothing yet, but soon! } } ); mFalseButton = (Button)findViewById( R.id.false_button ); }
代码清单1-10:为True按钮设置监听器(QuizActivity.java)
(如果遇到View cannot be resolved to a type的错误提示,请使用Mac的Command+Shift+O或Windows的Ctrl+Shift+O快捷键导入View类。)
在代码清单1-10中,我们设置了一个监听器。当按钮mTrueButton被点击后,监听器会立即通知我们。setOnClickListener(OnClickListener)方法以监听器作为参数被调用。在特殊情况下,该方法以一个实现了OnClickListener接口的对象作为参数被调用。
使用匿名内部类
SetOnClickListener(OnClickListener)方法传入的监听器参数是一个匿名内部类 (anon-ymous inner class)实现,语法看上去稍显复杂,不过,只需记住最外层括号内的全部实现代码是作为整体参数传入SetOnClickListener(OnClickListener)方法内的即
可。该传入的参数就是新建的一个匿名内部类的实现代码。
mTrueButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick( View v ) { // Does nothing yet, but soon! } } );
监听器作为匿名内部类来实现。这样做的好处有二。其一,在大量代码块中,监听器方法的实现一目了然;其二,匿名内部类的使用只出现在一个地方,因此可以减少一些命名类的使用。
匿名内部类实现了OnClickListener接口,因此它也必须实现该接口唯一的onClick(View)方法。onClick(View)方法的代码暂时是一个空结构。实现监听器接口需要实现onClick(View)方法,但具体如何实现由使用者决定,因此即使是空的实现方法,编译器也可以
编译通过。
我们为False按钮设置类似的时间监听器。
mFalseButton = (Button)findViewById( R.id.false_button ); mFalseButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick( View v ) { // Does nothing yet, but soon! } } );
代码清单1-11:为False按钮设置监听器(QuizActivity.java)
创建提示消息
接下来要实现的就是,分别单击两个按钮,弹出我们称为toast的提示消息。Android的toast指用来通知用户的简短弹出消息,但无需用户输入或做出任何操作。这里,我们要做的就是使用toast来告知用户其答案正确与否。
首先回到strings.xml文件,如代码清单1-12所示,为toast添加消息显示用的字符串资源。
<?xml version = "1.0" encoding = "utf-8" ?> <resources> <string name = "app_name" > GeoQuiz </string> <string name = "question_text" > Constantinople is the largest city in Turkey. </string> <string name = "true_button" > True </string> <string name = "false_button" > False </string> <string name = "correct_toast" > Correct! </string> <string name = "incorrect_toast" > Incorrect! </string> <string name = "action_settings" > Settings </string> <!-- 每个人版本不一样,星月这里跟书上不同。书上是:name = "menu_settings" --> </resources>
代码清单1-12:增加toast字符串(strings.xml)
通过调用来自Toast类的以下方法,可创建一个toast:
public static Toast makeText( Context context, int resId, int duration )
该方法的Context参数通常是Activity的一个实例(Activity本身就是Context的子类) 。第二个参数是toast待显示字符串消息的资源ID。Toast类必须利用context才能找到并使用字符串的资源ID。第三个参数通常是两个Toast常量中的一个,用来指定toast消息
显示的持续时间。
创建Toast后,可通过调用Toast.show()方法使toast消息显示在屏幕上。
在QuizActivity代码里, 分别对两个按钮的监听器调用makeText(...)方法, 如代码清单1-13所示。在添加makeText(...)时,可利用Eclipse的代码自动补全功能,让代码输入工作更加轻松。
mTrueButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick( View v ) { Toast.makeText( QuizActivity.this , R.string.incorrect_toast , Toast.LENGTH_SHORT ).show(); } } ); mFalseButton.setOnClickListener( new View.OnClickListener() { @Override public void onClick( View v ) { Toast.makeText( QuizActivity.this , R.string.correct_toast , Toast.LENGTH_SHORT ).show(); } } );
代码清单1-13:创建提示消息(QuizActivity.java)
使用代码自动补全
代码自动补全功能可以节约大量开发时间,越早掌握受益越多。 参照代码清单1-13,依次输入代码。当输入到Toast类后的点号时,Eclipse会弹出一个窗口,窗口内显示了建议使用的Toast类的常量与方法。
为便于选择所需的建议方法,可按Tab键移焦至自动补全弹出窗口上。(如果想忽略Eclipse的代码自动补全功能,请不要按Tab键或使用鼠标点击弹出窗口,只管继续输入代码直至完成。)
在列表建议清单里,选择makeText(Context, int, int)方法,代码自动补全功能会自动添加完成方法调用,包括参数的占位符值。
第一个占位符号默认加亮,直接输入实际参数值QuizActivity.this。然后按Tab键转至下一个占位符,输入实际参数值,依次类推,直至参照代码清单1-13完成全部参数的输入。
在makeText(...)里,传入QuizActivity实例作为Context的参数值。注意此处应输入的参数是QuizActivit.this,不要想当然地直接输入this作为参数。因为匿名类的使用,这里的this指的是监听器View.OnClickListener。