Android 简明教程
Android - Intents and Filters
Android Intent
是要执行操作的抽象描述。它可以与 startActivity
一起使用来启动活动,sendBroadcast
将其发送到任何感兴趣的 BroadcastReceiver 组件,以及 bindService(Intent, ServiceConnection, int)
来与后台服务通信。
例如,让我们假设你有一个活动,需要启动电子邮件客户端并使用安卓设备发送电子邮件。为此目的,你的活动将把 ACTION_SEND 与适当的 Intent
一起发送到 Android 意图解析器。指定的选择器为用户提供了适当的界面,用于选择如何发送电子邮件数据。
Intent email = new Intent(Intent.ACTION_SEND, Uri.parse("mailto:"));
email.putExtra(Intent.EXTRA_EMAIL, recipients);
email.putExtra(Intent.EXTRA_SUBJECT, subject.getText().toString());
email.putExtra(Intent.EXTRA_TEXT, body.getText().toString());
startActivity(Intent.createChooser(email, "Choose an email client from..."));
上面的语法调用 startActivity 方法启动电子邮件活动,结果应如下所示 −
例如,假设你有一个活动,需要在安卓设备上的网络浏览器中打开 URL。为此目的,你的活动会将 ACTION_WEB_SEARCH 意图发送到安卓意图解析器,以在网络浏览器中打开给定的 URL。意图解析器会解析活动列表,并从中选择最匹配你的意图的那个,在本例中,即网络浏览器活动。然后,意图解析器会将你的网页传递给网络浏览器,并启动网络浏览器活动。
String q = "tutorialspoint";
Intent intent = new Intent(Intent.ACTION_WEB_SEARCH );
intent.putExtra(SearchManager.QUERY, q);
startActivity(intent);
以上示例将在安卓搜索引擎中搜索 tutorialspoint
,并在你的活动中给出 tutorialspoint 的结果。
向每种类型的组件(活动、服务和广播接收器)递送意图有不同的机制。
Sr.No |
Method & Description |
1 |
|
2 |
|
3 |
|
Intent Objects
意图对象是一个信息捆绑,由接收该意图的组件以及安卓系统使用的信息使用。
意图对象可以包含以下组件,具体取决于其将要执行或正在传递的内容 −
Action
这是意图对象中的必需部分,是一条命名要执行的动作的字符串——或者在广播意图的情况下,就是发生并正在报告的动作。该动作在很大程度上决定了意图对象的其余部分的结构方式。意图类定义了许多与不同意图相对应的动作常量。以下显示 Intent
中可以包含的动作列表:
Intent 对象中的动作可以通过 setAction() 方法设置,并通过 getAction() 进行读取。
Data
将数据规范添加到意图过滤器中。规范可以仅为数据类型(mimeType 属性)、仅为 URI,或者既为数据类型又为 URI。URI 由其每个部分的单独属性指定 −
指定 URL 格式的这些属性是可选的,但也存在相互依赖关系−
-
如果未为意图筛选器指定方案,则忽略所有其他 URI 属性。
-
如果未为筛选器指定主机,则忽略端口属性和所有路径属性。
setData() 方法仅指定数据为 URI,setType() 仅指定为 MIME 类型,而 setDataAndType() 同时将其指定为 URI 和 MIME 类型。getData() 读取 URI,getType() 读取类型。
一些动作/数据对的示例如下−
Sr.No. |
Action/Data Pair & Description |
1 |
ACTION_VIEW content://contacts/people/1 显示 ID 为“1”的联系人的详细信息。 |
2 |
ACTION_DIAL content://contacts/people/1 使用已填入联系人信息的电话拨号程序。 |
3 |
ACTION_VIEW tel:123 使用已填入给定号码的电话拨号程序。 |
4 |
ACTION_DIAL tel:123 使用已填入给定号码的电话拨号程序。 |
5 |
ACTION_EDIT content://contacts/people/1 编辑 ID 为“1”的联系人的详细信息。 |
6 |
ACTION_VIEW content://contacts/people/ 显示联系人列表,以便用户浏览。 |
7 |
ACTION_SET_WALLPAPER 显示壁纸选择设置 |
8 |
ACTION_SYNC 同步数据,常量值为 *android.intent.action.SYNC * |
9 |
ACTION_SYSTEM_TUTORIAL 启动平台定义的教程(默认教程或启动教程) |
10 |
ACTION_TIMEZONE_CHANGED 它在时区发生更改时通知 |
11 |
ACTION_UNINSTALL_PACKAGE 用于运行默认卸载程序 |
Category
类别是 Intent 对象的可选部分,它是一个字符串,包含有关应该处理意图的组件类型的其他信息。addCategory() 方法将类别放置在 Intent 对象中,removeCategory() 删除先前添加的类别,getCategories() 获取当前对象中所有类别的集合。以下是 Android Intent Standard Categories 的列表。
您可以在以下部分查看意图筛选器的详细信息以了解如何使用类别为意图选择合适的活动。
Extras
对于应该传送到处理意图的组件的其他信息,它将使用键值对。分别使用 putExtras() 和 getExtras() 方法设置和读取扩展字段。以下是 Android Intent Standard Extra Data 的列表
Flags
这些标志是 Intent 对象的可选部分,它会指示 Android 系统如何启动 activity,以及在启动之后如何处理 activity 等。
Sr.No |
Flags & Description |
1 |
FLAG_ACTIVITY_CLEAR_TASK 如果设置在传递给 Context.startActivity() 的 Intent 中,则此标志会导致与 activity 关联的所有现有任务在启动 activity 之前被清除。也就是说,该 activity 成为一个否则为空的任务的新根,并且任何旧 activity 都将完成。只能将此标志与 FLAG_ACTIVITY_NEW_TASK 一起使用。 |
2 |
FLAG_ACTIVITY_CLEAR_TOP 如果已设置,并且正在启动的 activity 已在当前任务中运行,则不会启动该 activity 的新实例,而是关闭其之上的所有其他 activity,并且此 Intent 将作为新 Intent 传递给(现在位于顶部)旧 activity。 |
3 |
FLAG_ACTIVITY_NEW_TASK 此标志通常由想要呈现“启动器”样式行为的 activity 使用:它们向用户提供一个可以单独执行的不同事情列表,否则这些事情将与启动它们的 activity 完全独立运行。 |
Types of Intents
Android 支持以下两种类型的意图
Explicit Intents
将被连接到应用程序内部世界的显式意图,假设你想将一个 activity 连接到另一个 activity,我们可以通过显式意图来执行此引用,以下图片是通过单击按钮将第一个活动连接到第二个活动。
这些意图通过名称指定目标组件,它们通常用于应用程序内部消息 - 例如 activity 启动从属服务或启动关联 activity。例如 −
// Explicit Intent by specifying its class name
Intent i = new Intent(FirstActivity.this, SecondActivity.class);
// Starts TargetActivity
startActivity(i);
Implicit Intents
这些意图不命名目标,并且组件名称的字段留空。隐式意图通常用于激活其他应用程序中的组件。例如 −
Intent read1=new Intent();
read1.setAction(android.content.Intent.ACTION_VIEW);
read1.setData(ContactsContract.Contacts.CONTENT_URI);
startActivity(read1);
上面的代码将给出如下所示的结果
接收意图的目标组件可以使用 getExtras() 方法来获取源组件发送的额外数据。例如 −
// Get bundle object at appropriate place in your code
Bundle extras = getIntent().getExtras();
// Extract data using passed keys
String value1 = extras.getString("Key1");
String value2 = extras.getString("Key2");
Example
以下示例显示了 Android Intent 启动各种 Android 内置应用程序的功能。
Step |
Description |
1 |
你将使用 Android studio IDE 创建一个 Android 应用,并将其命名为 My Application,包名为 com.example.saira_000.myapplication。 |
2 |
修改 src/main/java/MainActivity.java 文件并添加代码以定义与两个按钮(即 Start Browser 和 Start Phone)相对应的两个监听器。 |
3 |
修改布局 XML 文件 res/layout/activity_main.xml 以在线性布局中添加三个按钮。 |
4 |
运行应用,以启动 Android 模拟器,并验证应用中已执行的更改。 |
以下是修改后的主活动文件 src/com.example.My Application/MainActivity.java 的内容。
package com.example.saira_000.myapplication;
import android.content.Intent;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
Button b1,b2;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
b1=(Button)findViewById(R.id.button);
b1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(android.content.Intent.ACTION_VIEW,
Uri.parse("http://www.example.com"));
startActivity(i);
}
});
b2=(Button)findViewById(R.id.button2);
b2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(android.content.Intent.ACTION_VIEW,
Uri.parse("tel:9510300000"));
startActivity(i);
}
});
}
}
以下是 res/layout/activity_main.xml 文件的内容——
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Intent Example"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:textSize="30dp" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tutorials point"
android:textColor="#ff87ff09"
android:textSize="30dp"
android:layout_below="@+id/textView1"
android:layout_centerHorizontal="true" />
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/imageButton"
android:src="@drawable/abc"
android:layout_below="@+id/textView2"
android:layout_centerHorizontal="true" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/editText"
android:layout_below="@+id/imageButton"
android:layout_alignRight="@+id/imageButton"
android:layout_alignEnd="@+id/imageButton" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start Browser"
android:id="@+id/button"
android:layout_alignTop="@+id/editText"
android:layout_alignRight="@+id/textView1"
android:layout_alignEnd="@+id/textView1"
android:layout_alignLeft="@+id/imageButton"
android:layout_alignStart="@+id/imageButton" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start Phone"
android:id="@+id/button2"
android:layout_below="@+id/button"
android:layout_alignLeft="@+id/button"
android:layout_alignStart="@+id/button"
android:layout_alignRight="@+id/textView2"
android:layout_alignEnd="@+id/textView2" />
</RelativeLayout>
以下是 res/values/strings.xml 的内容,用于定义两个新常量——
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">My Applicaiton</string>
</resources>
以下是 AndroidManifest.xml 的默认内容−
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.saira_000.myapplication">
<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>
让我们尝试运行你的 My Application 应用程序。我假设你在进行环境设置时创建了你的 AVD 。若要通过 Android Studio 运行该应用程序,请打开你的一个项目的活动文件,然后从工具栏单击运行图标。Android Studio 将应用程序安装在你的 AVD 上并启动它,如果你的设置和应用程序一切正常,它将显示以下模拟器窗口 −
现在单击 Start Browser 按钮,该按钮将启动已配置的浏览器并显示 [role="bare"] [role="bare"]http://www.example.com ,如下所示 −
同样地,你可以使用 Start Phone 按钮启动电话界面,该界面将允许你拨打已给定的电话号码。
Intent Filters
您已经看到如何使用 Intent 调用另一个 Activity。Android OS 使用过滤器识别一组可使用特定动作、类别和与 Intent 关联的数据方案处理 Intent 的 Activity、服务和广播接收器。您将使用清单文件中的 <intent-filter> 元素列出与任何 Activity、服务或广播接收器关联的动作、类别和数据类型。
以下是 AndroidManifest.xml 文件一部分的一个示例,用来指定一个 com.example.My Application.CustomActivity Activity,可以通过这两个提到的动作、一个类别和一个数据来调用它 -
<activity android:name=".CustomActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<action android:name="com.example.My Application.LAUNCH" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="http" />
</intent-filter>
</activity>
一旦此 Activity 及上面提到的过滤器被定义,其他 Activity 将能够使用 android.intent.action.VIEW 或使用 com.example.My Application.LAUNCH 动作调用此 Activity,前提是它们的类别是 android.intent.category.DEFAULT 。
<data> 元素指定被调用的 Activity 所期望的数据类型,对于上面的示例,我们的自定义 Activity 希望数据以“http://”开头。
可能出现的情况是,一个 Intent 可以通过一个以上 Activity 或服务的过滤器;用户可能被要求激活哪个组件。如果没有找到目标,则会引发异常。
在调用 Activity 之前,Android 有以下测试 -
-
过滤器 <intent-filter> 可以列出多个动作,如上面所示,但此列表不能是空的;一个过滤器必须包含至少一个 <action> 元素,否则它将阻止所有 Intents。如果提到了多个动作,则 Android 会尝试在调用 Activity 之前匹配其中一个动作。
-
一个过滤器 <intent-filter> 可以列出零、一个或多个类别。如果没有提到类别,那么 Android 总会通过此测试,但是,如果提到了多个类别,那么要使 Intent 通过类别测试,Intent 对象中的每个类别都必须与过滤器中的一个类别匹配。
-
每个 <data> 元素可以指定一个 URI 和一个数据类型(MIME 媒体类型)。URI 的每个部分都有 scheme, host, port 和 path 等独立的属性。包含 URI 和数据类型的 Intent 对象只在类型与过滤器中列出的类型匹配时,才通过测试的数据类型部分。
Example
下面的示例是对上面示例的修改。在这里,我们将看到当一个 Intent 调用在 中定义的两个 Activity 时,Android 如何解决冲突,接下来是使用过滤器调用自定义 Activity 的方法,第三个是当 Android 没有为 Intent 定义适当的 Activity 时出现的异常情况。
Step |
Description |
1 |
您将使用 Android Studio 创建一个 Android 应用程序,并将其命名为 My Application,该应用程序位于包 com.example.tutorialspoint7.myapplication; 中。 |
2 |
修改 src/Main/Java/MainActivity.java 文件并添加代码来定义与布局文件中定义的三个按钮相对应的三个监听器。 |
3 |
添加一个新的 src/Main/Java/CustomActivity.java 文件,以有一个自定义 Activity,将被不同的 Intent 调用。 |
4 |
修改布局 XML 文件 res/layout/activity_main.xml 以在线性布局中添加三个按钮。 |
5 |
添加一个布局 XML 文件 res/layout/custom_view.xml 来添加一个简单的 <TextView> 来显示通过 intent 传递的数据。 |
6 |
修改 AndroidManifest.xml 以添加 <intent-filter> 来定义 Intent 调用的自定义 Activity 的规则。 |
7 |
运行应用,以启动 Android 模拟器,并验证应用中已执行的更改。 |
以下是修改的主活动文件 src/MainActivity.java 的内容。
package com.example.tutorialspoint7.myapplication;
import android.content.Intent;
import android.net.Uri;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
public class MainActivity extends AppCompatActivity {
Button b1,b2,b3;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
b1=(Button)findViewById(R.id.button);
b1.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent(android.content.Intent.ACTION_VIEW,
Uri.parse("http://www.example.com"));
startActivity(i);
}
});
b2 = (Button)findViewById(R.id.button2);
b2.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent("com.example.
tutorialspoint7.myapplication.
LAUNCH",Uri.parse("http://www.example.com"));
startActivity(i);
}
});
b3 = (Button)findViewById(R.id.button3);
b3.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent i = new Intent("com.example.
My Application.LAUNCH",
Uri.parse("https://www.example.com"));
startActivity(i);
}
});
}
}
以下是修改后的主活动文件 src/com.example.My Application/CustomActivity.java 的内容。
package com.example.tutorialspoint7.myapplication;
import android.app.Activity;
import android.net.Uri;
import android.os.Bundle;
import android.widget.TextView;
/**
* Created by TutorialsPoint7 on 8/23/2016.
*/
public class CustomActivity extends Activity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.custom_view);
TextView label = (TextView) findViewById(R.id.show_data);
Uri url = getIntent().getData();
label.setText(url.toString());
}
}
以下是 res/layout/activity_main.xml 文件的内容——
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.tutorialspoint7.myapplication.MainActivity">
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Intent Example"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:textSize="30dp" />
<TextView
android:id="@+id/textView2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Tutorials point"
android:textColor="#ff87ff09"
android:textSize="30dp"
android:layout_below="@+id/textView1"
android:layout_centerHorizontal="true" />
<ImageButton
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/imageButton"
android:src="@drawable/abc"
android:layout_below="@+id/textView2"
android:layout_centerHorizontal="true" />
<EditText
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/editText"
android:layout_below="@+id/imageButton"
android:layout_alignRight="@+id/imageButton"
android:layout_alignEnd="@+id/imageButton" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start Browser"
android:id="@+id/button"
android:layout_alignTop="@+id/editText"
android:layout_alignLeft="@+id/imageButton"
android:layout_alignStart="@+id/imageButton"
android:layout_alignEnd="@+id/imageButton" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Start browsing with launch action"
android:id="@+id/button2"
android:layout_below="@+id/button"
android:layout_alignLeft="@+id/button"
android:layout_alignStart="@+id/button"
android:layout_alignEnd="@+id/button" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Exceptional condition"
android:id="@+id/button3"
android:layout_below="@+id/button2"
android:layout_alignLeft="@+id/button2"
android:layout_alignStart="@+id/button2"
android:layout_toStartOf="@+id/editText"
android:layout_alignParentEnd="true" />
</RelativeLayout>
以下是 res/layout/custom_view.xml 文件的内容 -
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView android:id="@+id/show_data"
android:layout_width="fill_parent"
android:layout_height="400dp"/>
</LinearLayout>
以下是 res/values/strings.xml 的内容,用于定义两个新常量——
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="app_name">My Application</string>
</resources>
以下是 AndroidManifest.xml 的默认内容−
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.tutorialspoint7.myapplication">
<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="com.example.tutorialspoint7.myapplication.CustomActivity">
<intent-filter>
<action android:name = "android.intent.action.VIEW" />
<action android:name = "com.example.tutorialspoint7.myapplication.LAUNCH" />
<category android:name = "android.intent.category.DEFAULT" />
<data android:scheme = "http" />
</intent-filter>
</activity>
</application>
</manifest>
让我们尝试运行您的 My Application 应用程序。我假设您在进行环境设置时已经创建了您的 AVD 。要从 Android Studio 运行应用程序,请打开您的一个项目活动文件,然后单击工具栏中的运行图标。Android Studio 会在您的 AVD 上安装该应用程序并启动它,如果您的设置和应用程序一切都正常的话,它将显示以下模拟器窗口 -
现在,让我们开始第一个按钮“使用 VIEW 动作启动浏览器”。在这里,我们使用过滤器“android.intent.action.VIEW”定义了我们的自定义 Activity,并且已经由 Android 定义了一个针对 VIEW 动作的默认 Activity,它启动网络浏览器,因此 Android 会显示以下两个选项供您选择要启动的 Activity。
现在,如果您选择浏览器,则Android将启动网络浏览器并打开example.com网站,但如果您选择IndentDemo选项,那么Android将启动CustomActivity,该活动除了捕获传递的数据并在文本视图中显示以下内容之外什么也不做:
现在,使用返回按钮返回并单击“使用启动操作启动浏览器”按钮,此处,Android将应用过滤器以选择定义活动,它只会启动您的自定义活动。
再次,使用返回按钮返回并单击“异常条件”按钮,此处,Android尝试为给定的意图查找一个有效的过滤器,但它找不到有效的活动定义,因为这次我们使用了数据作为 https 而不是 http ,尽管我们给出了正确的操作,因此,Android引发异常并显示以下屏幕: