通过上一章的学习,你已经成功创建了你的第一个Android项目。不过仅仅满足于此显然是 不够的,是时候学点新的东西了。作为你的导师,我有义务帮你制定好后面的学习路线,那么今 夭我们应该从哪儿入手呢?现在你可以想象一下,假如你已经写出了一个非常优秀的应用程序, 然后推荐给你的第一个用户,你会从哪里开始介绍呢?毫无疑问,当然是从界面开始介绍了!因 为即使你的程序算法再高效,架构再出色,用户根本不会在乎这些,他们一开始只会对看得到的 东西感兴趣,那么我们今天的主题自然也要从看得到的入手了。
2.1活动是什么
活动(Activity )是最容易吸引用户的地方,它是一种可以包含用户界面的组件,主要用于和用户进行交互。一个应用程序中可以包含零个或多个活动,但不包含任何活动的应用程序很少见,谁也不想让自己的应用永远无法被用户看到吧?
其实在上一章中,你已经和活动打过交道了,并且对活动也有了初步的认识。不过上一章我们的重点是创建你的第一个Android项目,对活动的介绍并不多,在本章中我将对活动进行详细的介绍。
2.2活动的基本用法
到现在为止,你还没有手动创建过活动呢,因为上一章中的HelloWorldActivity是Android Studio帮我们自动创建的。手动创建活动可以加深我们的理解,因此现在是时候应该自己动手了。
由于Android Studio在一个工作区间内只允许打开一个项目,因此首先你需要将当前的项目 关闭,点击导航栏File—>CloseProjecto然后再新建一个Android项目,项目名可以叫作ActivityTest, 包名我们就使用默认值com.example.activitytest。新建项目的步骤你已经在上一章学习过了,不 过图1.12中的那一步需要稍做修改,我们不再选择Empty Activity这个选项,而是选择Add NoActivity,因为这次我们准备手动创建活动,如图2.1所示。
图 2.1 选择不添加活动
点击Finish,等待Gradle构建完成后,项目就创建成功了。
2.2.1手动创建活动
项目创建成功后,仍然会默认使用Android模式的项目结构,这里我们手动改成Project模式, 本书中后面的所有项目都要这样修改,以后就不再赘述了。目前ActivityTest项目中虽然还是会自 动生成很多文件,但是app/src/main/java/com.example.activitytest目录应该是空的了,如图2.2所示。
图 2.2 初始项目结构
现在右击 com. example. activity test 包—>New—> Activity—>Empty Activity,会弹出一个创建活动 的对话框,我们将活动命名为First Activity,并且不要勾选Generate Layout File和Launcher Activity 这两个选项,如图2.3所示。
图 2.3 新建活动对话框
勾选Generate Layout File表示会自动为First Activity创建一个对应的布局文件,勾选Launcher Activity表示会自动将FirstActivity设置为当前项目的主活动,这里由于你是第一次手动创建活 动,这些自动生成的东西暂时都不要勾选,下面我们将会一个个手动来完成。勾选Backwards Compatibility表示会为项目启用向下兼容的模式,这个选项要勾上。点击Finish完成创建。
你需要知道,项目中的任何活动'都应该重写Activity的onCreateO方法,而目前我们的 FirstActivity中已经重写了这个方法,这是由Android Studio自动帮我们完成的,代码如下所示:
public class FirstActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedlnstanceState) {
super.onCreate(savedlnstanceState);
}
}
可以看到,onCreateO方法非常简单,就是调用了父类的onCreateO方法。当然这只是默 认的实现,后面我们还需要在里面加入很多自己的逻辑。
2.2.2创建和加载布局
前面我们说过,Android程序的设计讲究逻辑和视图分离,最好每一个活动都能对应一个布 局,布局就是用来显示界面内容的,因此我们现在就来手动创建一个布局文件。
右击app/src/main/res目录—>New—^Directory,会弹出一个新建目录的窗口,这里先创建一个 名为layout的目录。然后对着layout目录右键^Layout resource file,又会弹出一个新建布局资源 文件的窗口,我们将这个布局文件命名为first_layout,根元素就默认选择为LinearLayout,如图 2.4所示。
图 2.4 新建布局资源文件
点击0K完成布局的创建,这时候你会看到如图2.5所示的布局编辑器。
图 2.5 布局编辑器
这是Android Studio 为我们提供的可视化布局编辑器,你可以在屏幕的中央区域预览当前的 布局。在窗口的最下方有两个切换卡,左边是 Design, 右边是 Text 。 Design 是当前的可视化布局 编辑器,在这里你不仅可以预览当前的布局,还可以通过拖放的方式编辑布局。而 Text 则是通 过 XML 文件的方式来编辑布局的,现在点击一下 Text 切换卡,可以看到如下代码:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android: layout_height=,,match_parent">
</LinearLayout>
由于我们刚才在创建布局文件时选择了 LinearLayout作为根元素,因此现在布局文件中已经 有一个LinearLayout元素了。那我们现在对这个布局稍做编辑,添加一个按钮,如下所示:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="@+id/button 1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Button 1"
/>
</LinearLayout>
这里添加了一个Button元素,并在Button元素的内部增加了几个属性。android:id是给当 前的元素定义一个唯一标识符,之后可以在代码中对这个元素进行操作。你可能会对@+id/ button_l这种语法感到陌生,但如果把加号去掉,变成@id/button_l,这样你就会觉得有些熟 悉了吧,这不就是在XML中引用资源的语法吗?只不过是把string替换成了 id。是的,如果 你需要在XML中引用一个id,就使用@id/id_name这种语法,而如果你需要在XML中定义一 个id,贝ij要使用@+id/id_name这种语法。随后android:layout width指定了当前元素的宽 度,这里使用match parent表示让当前元素和父元素一样宽。android :layout_height指定 了当前元素的高度,这里使用wrap content表示当前元素的高度只要能刚好包含里面的内容就 行。android:text指定了元素中显示的文字内容。如果你还不能完全看明白,没有关系,关于 编写布局的详细内容我会在下一章中重点讲解,本章只是先简单涉及一些。现在按钮已经添加完 了,你可以通过右侧工具栏的Preview来预览一下当前布局,如图2.6所示。
图 2.6 预览当前布局
可以看到,按钮已经成功显示出来了,这样一个简单的布局就编写完成了。那么接下来我们 要做的,就是在活动中加载这个布局。
重新回到First Activity,在onCreate()方法中加入如下代码:
public class FirstActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedlnstanceState) {
super.onCreate(savedlnstanceState);
setContentView(R.layout . first_layout);
}
}
可以看到,这里调用了 setContentViewO方法来给当前的活动加载一个布局,而在 setContentViewO方法中,我们一般都会传入一个布局文件的ido在第1章介绍项目资源的时候我曾提到过,项目中添加的任何资源都会在R文件中生成一个相应的资源id,因此我们刚才创建的first_layout.xml布局的id现在应该是已经添加到R文件中了。在代码中去引用布局文件的方法你也已经学过了,只需要调用R.layout. first layout就可以得到first layout. xml布局的id,然后将这个值传入setContentViewO方法即可。
2.2.3 在 AndroidManifest 文件中注册
别忘了在上一章我们学过,所有的活动都要在AndroidManifest.xml中进行注册才能生效,而 实际上 First Activity 已经在 AndroidManifest.xml 中注册过了,我们打开 app/src/main/AndroidManifest.xml 文件瞧一瞧,代码如下所示:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.activitytest">
<application
android:aflowBackup="true"
android:icon="@mipmap/ic_launcher"
android: label="(astring/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme">
<activity and roid :name=". First Act ivity"x/activity>
</application>
</manifest>
可以看到,活动的注册声明要放在<application>标签内,这里是通过<activity>标签来对活动进行注册的。那么又是谁帮我们自动完成了对FirstActivity的注册呢?当然是Android Studio T,之前在使用Eclipse创建活动或其他系统组件时,很多人者S会忘记要去AndroidManifest.xml中注册一下,从而导致程序运行崩溃,很显然Android Studio在这方面做得更加人性化。
在〈activity〉标签中我们使用了 android:name来指定具体注册哪一个活动,那么这里填入 的.FirstActivity 是什么意思呢?其实这不过就是 com.example.activitytest. FirstActivity 的缩写而已。由于在最外层的<manifest>标签中已经通过package属性指定了程序的包名是 com.example.activitytest,因此在注册活动时这一部分就可以省略了,直接使用.FirstActivity 就足够了。
不过,仅仅是这样注册了活动,我们的程序仍然是不能运行的,因为还没有为程序配置主活 动,也就是说,当程序运行起来的时候,不知道要首先启动哪个活动。配置主活动的方法其实在 第1章中已经介绍过了,就是在<activity>标签的内部加入<intent-filter>标签,并在这个 标签里添加<action android:name=,,android.intent.action.MAIN'7>和〈category android: name="android.intent.category.LAUNCHER1' />这两句声明即可。
除此之外,我们还可以使用android:label指定活动中标题栏的内容,标题栏是显示在活 动最顶部的,待会儿运行的时候你就会看到。需要注意的是,给主活动指定的label不仅会成为 标题栏中的内容,还会成为启动器(Launcher)中应用程序显示的名称。
修改后的AndroidManifest.xml文件,代码如下所示:
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.activitytest">
<application
...>
<activity android:name=".FirstActivity"
android:label="This is FirstActivity">
<intent-filter>
<action android:name=,aandroid.intent.action.MAIN11 />
<category android:name=llandroid.intent.category. LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
这样的话,FirstActivity就成为我们这个程序的主活动了,即点击桌面应用程序图标时首先 打开的就是这个活动。另外需要注意,如果你的应用程序中没有声明任何一个活动作为主活动, 这个程序仍然是可以正常安装的,只是你无法在启动器中看到或者打开这个程序。这种程序一般 都是作为第三方服务供其他应用在内部进行调用的,如支付宝快捷支付服务。
好了,现在一切都已准备就绪,让我们来运行一下程序吧,结果如图2.7所示
图 2.7 首次运行结果
在界面的最顶部是一个标题栏,里面显示着我们刚才在注册活动时指定的内容。标题栏的下 面就是在布局文件firstjayout.xml中编写的界面,可以看到我们刚刚定义的按钮。现在你已经 成功掌握了手动创建活动的方法,下面让我们继续看一看你在活动中还能做哪些事情吧。
2.2.4在活动中使用Toast
Toast是Android系统提供的一种非常好的提醒方式,在程序中可以使用它将一些短小的信息 通知给用户,这些信息会在一段时间后自动消失,并且不会占用任何屏幕空间,我们现在就尝试 一下如何在活动中使用Toast。
首先需要定义一个弹出Toast的触发点,正好界面上有个按钮,那我们就让点击这个按钮的 时候弹出一个ToastP巴。在onCreateO方法中添加如下代码:
protected void onCreate(Bundle savedlnstanceState) {
super.onCreate(savedlnstanceState);
setContentView(R.layout.firstlayout);
Button buttonl = (Button) findViewByld(R.id.button^l);
buttonl.setOnClickListenerfnew View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(FirstActivity.this, "You clicked Button 1",
Toast.LENGTH^SHORT).show();
}
});
}
在活动中,可以通过findViewByldO方法获取到在布局文件中定义的元素,这里我们传入 R.id. button l,来得到按钮的实例,这个值是刚才在first layout.xml中通过android: id属性指定的。findViewByldO方法返回的是一个View对象,我们需要向下转型将它转成Button对象。得到按钮的实例之后,我们通过调用setOnClickListenerO方法为按钮注册一个监听器, 点击按钮时就会执行监听器中的onClick()方法。因此,弹出Toast的功能当然是要在onClickO方法中编写了。
Toast的用法非常简单,通过静态方法makeText ()创建出一个Toast对象,然后调用show() 将Toast显示出来就可以了。这里需要注意的是,makeText ()方法需要传入3个参数。第一个参数是Context,也就是Toast要求的上下文,由于活动本身就是一个Context对象,因此这里直接传入FirstActivity.this即可。第二个参数是Toast显示的文本内容,第三个参数是Toast 显示的时长,有两个内置常量可以选择Toast. LENGTH SHORT和Toast. LENGTH_LONG0
现在重新运行程序,并点击一下按钮,效果如图2.8所示。
2.2.5在活动中使用Menu
手机毕竟和电脑不同,它的屏幕空间非常有限,因此充分地利用屏幕空间在手机界面设计中就显得非常重要了。如果你的活动中有大量的菜单需要显示,这个时候界面设计就会比较尴尬, 因为仅这些菜单就可能占用屏幕将近三分之一的空间,这该怎么办呢?不用担心,Android给我们提供了一种方式,可以让菜单都能得到展示的同时,还能不占用任何屏幕空间。
首先在res目录下新建一个menu文件夹,右击res目录—>New-^Directory,输入文件夹名 menu,点击OK。接着在这个文件夹下再新建一个名叫main的菜单文件,右击menu文件夹-> New-^Menu resource file,如图 2.9 所示。
图 2.9 新建Menu资源文件
<menu xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id=”@+id/add_itenT
android: title=,,Add*7>
<item
android:id="@+id/remove_item"
android:title="Remove,7>
</menu>
这里我们创建了两个菜单项,其中<item>标签就是用来创建具体的某一个菜单项,然后通过android:id给这个菜单项指定一个唯一的标识符,通过android:title给这个菜单项指定 一个名称。
接着重新回到FirstActivity中来重写onCreateOptionsMenu()方法,重写方法可以使用Ctrl + 0快捷键(Mac系统是control + 0 ),如图2.10所示。
图 2.10 重写onCreateOptionsMenu()方法
然后在onCreateOptionsMenu()方法中编写如下代码:
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.main, menu);
return true;
}
通过getMenuInflaterO方法能够得到Menulnflater对象,再调用它的inflate。方法就可以给当前活动创建菜单了。inflate。