1page.title=向另一个应用发送用户
2page.tags=意向
3helpoutsWidget=true
4
5trainingnavtop=true
6
7@jd:body
8
9
10<div id="tb-wrapper">
11  <div id="tb">
12
13<h2>本课程将向您展示如何</h2>
14<ol>
15  <li><a href="#Build">构建隐含意向</a></li>
16  <li><a href="#Verify">确认是否存在接收意向的应用</a></li>
17  <li><a href="#StartActivity">开始具有意向的Activity</a></li>
18  <li><a href="#AppChooser">显示应用选择器</a></li>
19</ol>
20
21<h2>您还应阅读</h2>
22<ul>
23    <li><a href="{@docRoot}training/sharing/index.html">共享简单数据</a></li>
24</ul>
25
26  </div>
27</div>
28
29<p>Android 最重要的功能之一是应用能够基于它要执行的“操作”向另一个应用发送用户。
30例如,如果您的应用有您要在地图上显示的公司地址,您无需在显示地图的应用中构建Activity。
31
32而是可以创建使用
33 {@link android.content.Intent} 查看地址的请求。Android 系统之后启动可以在地图上显示该地址的应用。
34</p>
35
36<p>正如第一堂课<a href="{@docRoot}training/basics/firstapp/index.html">构建您的第一个应用</a>中所讲述的,您必须使用意向在自己应用中的Activity之间进行导航。您通常使用<em>明确意向</em>执行此操作,该意向定义您希望启动的组件的确切类名称。
37
38
39但是,当您希望另一应用执行操作时,比如“查看地图”,您必须使用<em>隐含意向</em>。
40</p>
41
42<p>本课程向您展示如何针对特定操作创建隐含意向,以及如何使用该意向开始在另一个应用中执行操作的Activity。
43</p>
44
45
46
47<h2 id="Build">构建隐含意向</h2>
48
49<p>隐含意向不声明要启动的组件的类名称,而是声明要执行的操作。
50该操作指定您要执行的操作,比如<em>查看</em>、<em>编辑</em>、<em>发送</em>或 <em>获取</em> 某项。
51意向通常还包含与操作关联的数据,比如您要查看的地址或您要发送的电子邮件消息。根据要创建的意向,数据可能是 {@link android.net.Uri}、多种其他数据类型之一,或意向可能根本就不需要数据。
52
53
54</p>
55
56<p>如果您的数据是 {@link android.net.Uri},有一个简单的  {@link
57android.content.Intent#Intent(String,Uri) Intent()} 构造函数,您可用来定义操作和数据。
58</p>
59
60<p>例如,此处显示如何使用指定电话号码的 {@link
61android.net.Uri} 数据创建发起电话呼叫的意向:</p>
62
63<pre>
64Uri number = Uri.parse("tel:5551234");
65Intent callIntent = new Intent(Intent.ACTION_DIAL, number);
66</pre>
67
68<p>当您的应用通过调用 {@link android.app.Activity#startActivity
69startActivity()} 调用此意向时,“电话”应用会发起向指定电话号码的呼叫。</p>
70
71<p>这里有一些其他意向及其操作和 {@link android.net.Uri} 数据对:
72</p>
73
74<ul>
75  <li>查看地图:
76<pre>
77// Map point based on address
78Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
79// Or map point based on latitude/longitude
80// Uri location = Uri.parse("geo:37.422219,-122.08364?z=14"); // z param is zoom level
81Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);
82</pre>
83  </li>
84  <li>查看网页:
85<pre>
86Uri webpage = Uri.parse("http://www.android.com");
87Intent webIntent = new Intent(Intent.ACTION_VIEW, webpage);
88</pre>
89  </li>
90</ul>
91
92<p>其他类型的隐含意向需要提供不同数据类型(比如,字符串)的“额外”数据。
93您可以使用各种 {@link
94android.content.Intent#putExtra(String,String) putExtra()} 方法添加一条或多条额外数据。</p>
95
96<p>默认情况下,系统基于所包含的
97{@link android.net.Uri} 数据确定意向需要的相应 MIME 类型。如果您未在意向中包含 {@link android.net.Uri},您通常应使用 {@link android.content.Intent#setType setType()} 指定与意向关联的数据的类型。
98
99设置 MIME 类型可进一步指定哪些类型的Activity应接收意向。
100</p>
101
102<p>此处有更多添加额外数据以指定所需操作的意向:</p>
103
104<ul>
105  <li>发送带附件的电子邮件:
106<pre>
107Intent emailIntent = new Intent(Intent.ACTION_SEND);
108// The intent does not have a URI, so declare the "text/plain" MIME type
109emailIntent.setType(HTTP.PLAIN_TEXT_TYPE);
110emailIntent.putExtra(Intent.EXTRA_EMAIL, new String[] {"jon@example.com"}); // recipients
111emailIntent.putExtra(Intent.EXTRA_SUBJECT, "Email subject");
112emailIntent.putExtra(Intent.EXTRA_TEXT, "Email message text");
113emailIntent.putExtra(Intent.EXTRA_STREAM, Uri.parse("content://path/to/email/attachment"));
114// You can also attach multiple items by passing an ArrayList of Uris
115</pre>
116  </li>
117  <li>创建日历事件:
118<pre>
119Intent calendarIntent = new Intent(Intent.ACTION_INSERT, Events.CONTENT_URI);
120Calendar beginTime = Calendar.getInstance().set(2012, 0, 19, 7, 30);
121Calendar endTime = Calendar.getInstance().set(2012, 0, 19, 10, 30);
122calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_BEGIN_TIME, beginTime.getTimeInMillis());
123calendarIntent.putExtra(CalendarContract.EXTRA_EVENT_END_TIME, endTime.getTimeInMillis());
124calendarIntent.putExtra(Events.TITLE, "Ninja class");
125calendarIntent.putExtra(Events.EVENT_LOCATION, "Secret dojo");
126</pre>
127<p class="note"><strong>注意:</strong>只有 API 级别 14 或更高级别支持此日历事件意向。
128</p>
129  </li>
130</ul>
131
132<p class="note"><strong>注意:</strong>尽可能具体地定义您的 {@link
133android.content.Intent} 非常重要。例如,如果您想要使用 {@link android.content.Intent#ACTION_VIEW} 意向显示图像,您应指定
134{@code image/*}的 MIME 类型。
135这可防止可“查看”数据的其他类型的应用(比如地图应用)被意向触发。
136</p>
137
138
139
140<h2 id="Verify">确认是否存在接收意向的应用</h2>
141
142<p>尽管 Android 平台保证某些意向可以分解为内置应用之一(比如,“电话”、“电子邮件”或“日历”应用),您应在调用意向之前始终包含确认步骤。
143
144</p>
145
146<p class="caution"><strong>注意:</strong>如果您调用了意向,但设备上没有可用于处理意向的应用,您的应用将崩溃。
147</p>
148
149<p>要确认是否存在可响应意向的可用Activity,请调用 {@link
150android.content.pm.PackageManager#queryIntentActivities queryIntentActivities()} 来获取能够处理您的{@link android.content.Intent} 的Activity列表。
151如果返回的 {@link
152java.util.List} 不为空,您可以安全地使用该意向。例如:</p>
153
154<pre>
155PackageManager packageManager = {@link android.content.Context#getPackageManager()};
156List<ResolveInfo> activities = packageManager.queryIntentActivities(intent,
157        PackageManager.MATCH_DEFAULT_ONLY);
158boolean isIntentSafe = activities.size() > 0;
159</pre>
160
161<p>如果 <code>isIntentSafe</code> 是 <code>true</code>,则至少有一个应用将响应该意向。
162如果它是 <code>false</code>,则没有任何应用处理该意向。</p>
163
164<p class="note"><strong>注意:</strong>在您需要在用户尝试使用它之前禁用使用该意向的功能时,您应在Activity初次开始时执行此检查。
165
166如果您了解可处理意向的特定应用,您还可以为用户提供下载该应用的链接(请参阅如何<a href="{@docRoot}distribute/tools/promote/linking.html">在 Google
167Play</a> 链接到您的产品)。
168</p>
169
170
171<h2 id="StartActivity">开始具有意向的Activity</h2>
172
173<div class="figure" style="width:200px;margin-top:-10px">
174  <img src="{@docRoot}images/training/basics/intents-choice.png" alt="" />
175  <p class="img-caption"><strong>图 1.</strong>当多个应用可处理意向时显示的选择对话框示例。
176</p>
177</div>
178
179<p>一旦您已创建您的 {@link android.content.Intent} 并设置附加信息,调用 {@link
180android.app.Activity#startActivity startActivity()} 将其发送给系统 。如果系统识别可处理意向的多个Activity,它会为用户显示对话框供其选择要使用的应用,如图 1 所示。
181
182如果只有一个Activity处理意向,系统会立即开始这个Activity。
183</p>
184
185<pre>
186startActivity(intent);
187</pre>
188
189<p>此处显示完整的示例:如何创建查看地图的意向,确认是否存在处理意向的应用,然后启动它:
190</p>
191
192<pre>
193// Build the intent
194Uri location = Uri.parse("geo:0,0?q=1600+Amphitheatre+Parkway,+Mountain+View,+California");
195Intent mapIntent = new Intent(Intent.ACTION_VIEW, location);
196
197// Verify it resolves
198PackageManager packageManager = {@link android.content.Context#getPackageManager()};
199List&lt;ResolveInfo> activities = packageManager.queryIntentActivities(mapIntent, 0);
200boolean isIntentSafe = activities.size() > 0;
201
202// Start an activity if it's safe
203if (isIntentSafe) {
204    startActivity(mapIntent);
205}
206</pre>
207
208
209
210<h2 id="AppChooser">显示应用选择器</h2>
211
212<div class="figure" style="width:200px;margin-top:-10px">
213  <img src="{@docRoot}images/training/basics/intent-chooser.png" alt="" />
214  <p class="img-caption"><strong>图 2.</strong>选择器的对话框。</p>
215</div>
216
217<p>注意,当您通过将您的 {@link android.content.Intent} 传递至 {@link
218android.app.Activity#startActivity startActivity()} 而开始Activity时,有多个应用响应意向,用户可以选择默认使用哪个应用(通过选中对话框底部的复选框;见图 1)。
219
220当执行用户通常希望每次使用相同应用进行的操作时,比如当打开网页(用户可能只使用一个网页浏览器)或拍照(用户可能习惯使用一个照相机)时,这非常有用。
221
222</p>
223
224<p>但是,如果要执行的操作可由多个应用处理并且用户可能习惯于每次选择不同的应用,&mdash;比如“共享”操作,用户有多个应用分享项目&mdash;,您应明确显示选择器对话框,如图 2 所示。
225
226
227选择器对话框强制用户选择用于每次操作的应用(用户不能对此操作选择默认的应用)。
228
229</p>
230
231<p>要显示选择器,使用 {@link
232android.content.Intent#createChooser createChooser()} 创建{@link android.content.Intent} 并将其传递至 {@link
233android.app.Activity#startActivity startActivity()}。例如:</p>
234
235<pre>
236Intent intent = new Intent(Intent.ACTION_SEND);
237...
238
239// Always use string resources for UI text.
240// This says something like "Share this photo with"
241String title = getResources().getString(R.string.chooser_title);
242// Create intent to show chooser
243Intent chooser = Intent.createChooser(intent, title);
244
245// Verify the intent will resolve to at least one activity
246if (intent.resolveActivity(getPackageManager()) != null) {
247    startActivity(chooser);
248}
249</pre>
250
251<p>这将显示一个对话框,其中有响应传递给 {@link
252android.content.Intent#createChooser createChooser()} 方法的意向的应用列表,并且将提供的文本用作
253对话框标题。</p>
254
255
256
257