课程 1: Intent 和 Activity

结束 Android 开发(入门)课程 的第一部分《布局和交互》后,来到第二部分《多屏幕应用》,这部分课程要完成一个 Miwok Dictionary 的多屏幕应用,这个应用由 Numbers、Colors、Family Members、Phrases 四个类别的 English 与 Miwok 对照列表以及对应图片和音频文件内容组成,每个列表有一个屏幕 (Activity)。
从现在开始,学员不再是初学者,所以课程的难度开始增加,进度也逐渐加快了。不过练习的机会也变多了,保证了学员能跟上节奏。

Miwok App 分五节课完成,每个课程的进度分配如下:

  1. 使 App 能切换显示多个屏幕,每个屏幕暂时保持空白,主要处理用户的触摸事件;
  2. 使 App 显示 English 与 Miwok 对照列表,主要涉及数组 Array 和列表 List 这两个存储数据的 Java 数据结构;
  3. 改进 App 列表,在单词旁显示图片,微调排版;
  4. 在 App 列表添加播放音频按钮,播放由 Andrea Delgado-Olsen 录制的 Miwok mp3 文件;
  5. 利用四个 fragment 将四个屏幕整合到一个 Activity 。

这是第二部分《多屏幕应用》的第一节课,导师是 Katherine Kuan 和 Jessica Lin。

关键词:Implicit Intent & Explicit Intent、AndroidManifest.xml、Event Listeners、Abstract Method、Interface

Activity

通常与他人协作时,无需自己从头开始新建项目,可以从 Github 下载已有项目 zip,解压后在 Android Studio 选择 "Import Project…" 导入工程;或者直接在 Android Studio 初始界面选择 "Check out projects from version control" 导入带版本控制的工程。
作为一名开发者,要学会阅读别人的项目代码,可以通过描绘图表来了解大致的项目结构。对于一些大工程,可以关注一些关键文件,例如 App 的主屏幕 app/src/main/java/MainActivity.java,资源文件 app/src/main/res,包括

  • layout 目录下保存的布局 XML 文件;
  • mipmap 目录下保存的 App icon 图标图片文件;
  • values 目录下保存的 colors 颜色声明 XML 文件、dimens 尺寸 (dp & sp) 声明 XML 文件、strings 字符串声明 XML 文件、styles 主题样式定义 XML 文件。

来看看 MainActivity.java 的文件结构,下面是一个新工程的 MainActivity.java 文件,可分为五部分理解。

package com.example.android.miwok;

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity {

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);

       // Set the content of the activity to use the activity_main.xml layout file
       setContentView(R.layout.activity_main);
   }
}
  • 第一行,文件包名,由 Java 关键词 package 开头,后面跟着新建项目时指定的唯一包名,用于 Android 设备 和 Play Store 识别 App 的唯一标识。
  • 第二部分,import statement,引用 Activity 需要的由 Android 团队提供的 Android 框架代码,主要是 Java Class,随着代码的增多,import 语句也会增多,Android Studio 可开启自动添加 import 声明功能。
  • 第三部分,Class statement,public class MainActivity 代表 MainActivity 的公共类,在声明内的代码包含 MainActivity 类的定义;extends AppCompatActivity 代表这个类继承了 Super Class(超级类)AppCompatActivity 的所有行为,包括在设备上显示窗口和应用栏。
  • 第四部分,Method override,即 MainActivity 改写了 AppCompatActivity 的 onCreate method,自定义 App 初始化后执行的代码,一般 App 都会出现这个 override,这也是 Android Studio 自动生成的原因。
  • 第五部分,将一个 XML 布局资源文件设置为内容视图。
Android Manifest

在 Android Studio 新建 Activity,可以右键 app/Activity/Empty Activity,输入名称,点击完成。成功新建 Activity 后会自动在 AndroidManifest.xml 添加一个新的 Activity XML 元素。
来看看 AndroidManifest.xml 的文件结构。

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
   package="com.example.android.miwok">

   <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>
       <activity
           android:name=".NumbersActivity"
           android:label="@string/category_numbers" />
   </application>
</manifest>

每个 App 都有 AndroidManifest.xml 文件,由 Android Studio 自动生成并根据项目进度自动更新,它相当于一个 App 的目录,存储了关于 App 的重要信息,例如

<!-- 保存 App 的 icon 图标 -->
android:icon="@mipmap/ic_launcher"
<!-- 保存 App 在应用栏显示的名称 -->
android:label="@string/app_name"
<!-- 保存 App 的主题样式路径 -->
android:theme="@style/AppTheme"

设备在安装 App 后,在运行任何代码之前,会首先查看 AndroidManifest.xml 文件。
在 MainActivity 部分,可以看到 <intent-filter>,这表示 MainActivity 能够接受和响应 intent 请求,中间包含的两条语句

<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />

表示 App 启动时进入的是 MainActivity,相当于 App 启动时 Android 系统向 App 发送了一个 intent,由 MainActivity 接受和响应。
新添加的 Activity 紧接着出现在 MainActivity 后面,支持修改 Activity 的属性,例如 Google 搜索 "Android Manifest Activity tag" 可以找到 Android <activity> 文档,其中 android:label 属性可以修改 Activity 在应用栏显示的标签名。

Intent

两个 Activity 之间可以通过 intent 联系,这里对之前 Just Java App 对邮件的 intent 作详细介绍,intent 可分为 Explicit intent(显性 intent)和 Implicit intent(隐性 intent)。

  • Implicit intent 不指定响应 Activity,通常用于外部 App。
  • Explicit intent 须指定响应 Activity,App 内使用,不能用来 intent 外部 App,因为设备上不一定有指定的 App。

两者的代码也有区别。

Implicit intent 代码包含 Action,Data URL,以及帮助 Android 判断什么 App 适合处理此 intent 的 Category,components,extras 可选数据,还有最后 resolveActivity 的判断语句来处理设备上没有 App 响应 intent 的情况。例如

// Create the text message with a string
Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, textMessage);
sendIntent.setType("text/plain");

// Verify that the intent will resolve to an activity
if (sendIntent.resolveActivity(getPackageManager()) != null) {
   startActivity(sendIntent);
}

Explicit intent 代码则较简单,说明 context 和 component(通常是 Class 或 Activity)即可,也可以包含可选的 Data URL。例如

// Executed in an Activity, so 'this' is the Context
// The fileUrl is a string URL, such as "http://www.example.com/image.png"
Intent downloadIntent = new Intent(this, DownloadService.class);
downloadIntent.setData(Uri.parse(fileUrl));
startService(downloadIntent);

Explicit intent 和 Implicit intent 代码的共同点是都包含下面两条语句

Intent downloadIntent = new Intent(this, DownloadService.class);
startService(downloadIntent);

即对象的声明(隐形 intent 需要操作字符串,显性 intent 需要提供 context 和 component(实例化))以及 startService 语句。

Event Listener

当用户点击屏幕时,会由 XML 的 View(onClick 是 View 的属性,Button、TextView、ImageView 都属于 View 的子类,所以 TextView 或 ImageView 也可以使用 onClick 属性)执行 onClick 指定函数,这种行为实际上是 Android 为 Event Listeners(事件监听器)做的快捷方式。事实上,用户交互会触发 Event Listeners,随后事件监听器再识别用户交互的 View。因此,要实现不修改 XML 而仅在 Java 端实现捕捉和响应触摸、长按、拖动等用户交互,可以通过直接操作 Event Listeners 做到。例如要监听触摸事件,可以利用 onClickListener 实现,然后与相关的 View 连接(onClick)进行更改。

首先来看 Event Listeners 作为一种 Interface(接口)的定义:接口只有 Abstract methods(抽象 method,指定返回值、名称、输入参数,分号结束,大括号中间的代码实现由开发者自由发挥的 method)。类似的,还有 Abstract Class(抽象类:部分实现的类,包括状态 state,一些完全实现的 method,一些抽象 method)。如下图所示,从 methods 实现程度来看,“完全实现的类”到“抽象类”再到“接口”是一个连续过程,像 TextView 这种完全实现的类,Android 设计成完全的标准化;到 ViewGroups 这种抽象类,包含了 TextView 等标准化的类,也包含 LinearLayout 等子类是抽象的;再到 onClickListener 这种接口,只规范了抽象的 method,具体实现是开放的(回调函数)。

设置 Event Listeners 的具体操作(代替 XML 的 android:onClick 及其 Java 对应的函数)。

  1. 定义 Event Listeners 并具化抽象 methods;(引用 OnClickLitstener)

In NumbersActivity.java

public class NumbersClickListner implements OnClickLitstener {
    @override
    Pubilc void onClick(View view) {
        Toast.makeText(view.getContext(), “Open the list of numbers”, Toast.LENTH_SHORT).show();
    }
}
  1. 通过构造函数为 Event Listeners 创建一个新的对象实例

In MainActivity.java

NumbersClickListener clickListener = new NumbersClickListener();
  1. 为 Event Listeners 连接要操作的 View

In MainActivity.java

Button buttonView = findViewById(R.id.button);
buttonView.setOnClickListener(clickListener);

上述代码可以简化为如下。注意括号配对。

In MainActivity.java

Button buttonView = findViewById(R.id.button);
buttonView.setOnClickListener(new NumbersClickListener(){
    @Override
    pubilc void onClick(View view) {
        Toast.makeText(view.getContext(), "Open the list of numbers", Toast.LENTH_SHORT).show();
    }
});

这里直接操作 Event Listener 实现了用户点击按钮时出现一条 "Open the list of numbers" 的 Toast 信息,没有通过 Button 的 android:onClick 属性实现。


完成第一节课后,我做了第四个实战项目:NotEasyMusic 音乐应用结构,项目托管在我的 GitHub 上。主要应用了这节课学习的 OnClickListeners 和 Explicit Intent,详细介绍我写在 GitHub 的 README 上。App 目前的效果如下:

目前它只是一个应用结构,没有实现任何音乐播放器的功能,很多地方都是硬编码,但随着课程深入,我会逐步完善这个 App。
这次项目提交上去后,导师依旧给出很棒的建议,例如在局部变量加上 private 防止外部类修改变量,还有编写函数来批量处理多次的 intent 和 onClickListener。我按照导师给出的建议修改了代码,记录都可以在我的 GitHub 上找到。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,530评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 86,403评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,120评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,770评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,758评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,649评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,021评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,675评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,931评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,659评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,751评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,410评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,004评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,969评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,042评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,493评论 2 343

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,431评论 25 707
  • ¥开启¥ 【iAPP实现进入界面执行逐一显】 〖2017-08-25 15:22:14〗 《//首先开一个线程,因...
    小菜c阅读 6,351评论 0 17
  • Intent组件虽然不是四大组件,但却是连接四大组件的桥梁,学习好这个知识,也非常的重要。 一、什么是Intent...
    困惑困惑困惑阅读 1,494评论 0 0
  • 深圳是个让人又爱又恨的城市。因为它坚硬的墙冷漠的心,以及脆弱的生活再也没有坚不可摧的爱情,山盟海誓太容易被击溃,再...
    忆听雨轩阅读 129评论 0 0
  • 雨后的黄昏 云朵幻化成精灵 灯光的魅影 让城市寂寞 宁静 我经过这里 遇到你 像是梦境 从此我在你眼里 你在我心中
    紫色茜茜阅读 154评论 0 1